[go: up one dir, main page]

Menu

[r19]: / trunk / MidiRecord.h  Maximize  Restore  History

Download this file

156 lines (132 with data), 4.6 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyleft 2014 Chris Korda
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or any later version.
/*
chris korda
revision history:
rev date comments
00 15mar14 initial version
01 31mar15 make part info copyable
02 01apr15 in ExportMidiFile, optionally fix duplicate notes
MIDI recording
*/
#ifndef CMIDIRECORD_INCLUDED
#define CMIDIRECORD_INCLUDED
#include "ArrayEx.h"
#include "MidiInst.h"
class CPatch;
class CMidiRecord : public WObject {
public:
// Construction
CMidiRecord();
// Types
struct EVENT {
LARGE_INTEGER Time; // timestamp, in performance counter ticks
DWORD Msg; // MIDI message
DWORD Port; // MIDI output device index
};
typedef CArrayEx<EVENT, EVENT&> CEventArray;
class CPartInfo : public WCopyable {
public:
CMidiInst m_Inst; // MIDI instrument
CString m_Name; // part name
};
typedef CArrayEx<CPartInfo, CPartInfo&> CPartInfoArray;
struct FILE_HEADER {
UINT ID; // file indentifier
UINT Version; // format version number
LARGE_INTEGER PerfFreq; // performance counter frequency, in Hertz
double Tempo; // tempo, in beats per minute
UINT Events; // event count
};
struct MIDI_TRACK {
MIDI_INST m_Inst; // MIDI instrument identifier
int m_Events; // number of events in track
int m_FirstEvent; // index of track's first event
LPCTSTR m_Name; // track name
};
typedef CArrayEx<MIDI_TRACK, MIDI_TRACK&> CMidiTrackArray;
// Constants
enum {
FILE_ID = 0x524d4543, // file indentifier CEMR (ChordEase Midi Recording)
FILE_VERSION = 1, // file format version number
};
// Attributes
bool IsRecording() const;
void SetRecord(bool Enable);
int GetEventCount() const;
EVENT& operator[](int Index);
const EVENT& operator[](int Index) const;
void GetEvent(CEventArray& Event) const;
void SetEvent(const CEventArray& Event);
int GetBufferSize() const;
void SetBufferSize(int Size);
void GetMidiTracks(const CPartInfoArray& PartInfo, CMidiTrackArray& Track) const;
// Operations
void RemoveAllEvents();
void AddEvent(DWORD Port, DWORD Msg);
bool Write(LPCTSTR Path, const CPatch& Patch);
bool Write(LPCTSTR Path, const FILE_HEADER& Header, const CPartInfoArray& PartInfo);
bool Read(LPCTSTR Path, FILE_HEADER& Header, CPartInfoArray& PartInfo);
bool ExportMidiFile(LPCTSTR Path, const CPatch& Patch, short PPQ, bool FixDupNotes) const;
bool ExportMidiFile(LPCTSTR Path, const CPartInfoArray& PartInfo, double Tempo, short PPQ, LARGE_INTEGER PerfFreq, bool FixDupNotes) const;
static CString GetTimeStr(int Millis);
protected:
// Types
struct NOTE_STATE { // state of each MIDI note, for fixing duplicate notes
int Instances; // number of instances of this note in existence
int PendingOffs; // number of deferred note off commands pending
};
// Data members
CEventArray m_Event; // record buffer; array of events
long m_EventCount; // interlocked event count
bool m_IsRecording; // true if recording
int m_BufferSize; // record buffer size, in events
// Helpers
static int TrackSortByInst(const void *elem1, const void *elem2);
static void GetPartInfo(const CPatch& Patch, CPartInfoArray& PartInfo);
static void WritePartInfo(CFile& fp, const CPartInfoArray& PartInfo);
static void ReadPartInfo(CFile& fp, CPartInfoArray& PartInfo);
static void WriteString(CFile& fp, const CString& Str);
static void ReadString(CFile& fp, CString& Str);
};
inline bool CMidiRecord::IsRecording() const
{
return(m_IsRecording);
}
inline int CMidiRecord::GetEventCount() const
{
return(m_Event.GetSize());
}
inline CMidiRecord::EVENT& CMidiRecord::operator[](int Index)
{
return(m_Event[Index]);
}
inline const CMidiRecord::EVENT& CMidiRecord::operator[](int Index) const
{
return(m_Event[Index]);
}
inline void CMidiRecord::GetEvent(CEventArray& Event) const
{
Event = m_Event;
}
inline int CMidiRecord::GetBufferSize() const
{
return(m_BufferSize);
}
inline void CMidiRecord::SetBufferSize(int Size)
{
m_BufferSize = Size;
}
inline void CMidiRecord::AddEvent(DWORD Port, DWORD Msg)
{
if (m_EventCount < m_Event.GetSize()) { // if buffer not full
long iEvent = InterlockedIncrement(&m_EventCount);
EVENT& event = m_Event[iEvent - 1];
QueryPerformanceCounter(&event.Time);
event.Msg = Msg;
event.Port = Port;
}
}
#endif