25 #include <QDataStream> 47 class QSmf::QSmfPrivate {
57 m_OldCurrTempo(500000),
75 double m_DblOldRealtime;
78 quint64 m_OldCurrTempo;
79 quint64 m_OldRealTime;
80 quint64 m_OldCurrTime;
81 quint64 m_RevisedTime;
82 quint64 m_TempoChangeTime;
84 quint64 m_NumBytesWritten;
89 QDataStream *m_IOStream;
91 QList<QSmfRecTempo> m_TempoList;
108 d->m_TempoList.clear();
116 bool QSmf::endOfSmf()
118 return d->m_IOStream->atEnd();
125 quint8 QSmf::getByte()
128 if (!d->m_IOStream->atEnd())
140 void QSmf::putByte(quint8 value)
142 *d->m_IOStream << value;
143 d->m_NumBytesWritten++;
151 void QSmf::addTempo(quint64 tempo, quint64 time)
153 QSmfRecTempo tempoRec;
154 tempoRec.tempo = tempo;
155 tempoRec.time = time;
156 d->m_TempoList.append(tempoRec);
162 void QSmf::readHeader()
167 d->m_CurrTempo = 500000;
168 d->m_OldCurrTempo = 500000;
169 addTempo(d->m_CurrTempo, 0);
170 if (d->m_Interactive)
178 readExpected(
"MThd");
179 d->m_ToBeRead = read32bit();
180 d->m_fileFormat = read16bit();
181 d->m_Tracks = read16bit();
182 d->m_Division = read16bit();
187 while ((d->m_ToBeRead > 0) && !endOfSmf())
196 void QSmf::readTrack()
201 static const quint8 chantype[16] =
202 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
211 quint64 delta_ticks, save_time, save_tempo;
213 sysexcontinue =
false;
215 if (d->m_Interactive)
217 d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
221 readExpected(
"MTrk");
222 d->m_ToBeRead = read32bit();
226 d->m_DblRealTime = 0;
227 d->m_DblOldRealtime = 0;
228 d->m_OldCurrTime = 0;
229 d->m_OldRealTime = 0;
230 d->m_CurrTempo = findTempo();
234 while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
236 if (d->m_Interactive)
242 delta_ticks = readVarLen();
243 d->m_RevisedTime = d->m_CurrTime;
244 d->m_CurrTime += delta_ticks;
245 while (d->m_RevisedTime < d->m_CurrTime)
247 save_time = d->m_RevisedTime;
248 save_tempo = d->m_CurrTempo;
249 d->m_CurrTempo = findTempo();
250 if (d->m_CurrTempo != d->m_OldCurrTempo)
252 d->m_OldCurrTempo = d->m_CurrTempo;
253 d->m_OldRealTime = d->m_RealTime;
254 if (d->m_RevisedTime != d->m_TempoChangeTime)
256 d->m_DblOldRealtime = d->m_DblRealTime;
257 d->m_OldCurrTime = save_time;
259 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
260 d->m_Division, save_tempo);
261 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
262 d->m_RealTime =
static_cast<quint64
>(0.5 + d->m_DblRealTime);
263 if (d->m_RevisedTime == d->m_TempoChangeTime)
265 d->m_OldCurrTime = d->m_RevisedTime;
266 d->m_DblOldRealtime = d->m_DblRealTime;
271 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
272 d->m_Division, d->m_CurrTempo);
273 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
274 d->m_RealTime =
static_cast<quint64
>(0.5 + d->m_DblRealTime);
282 SMFError(
"didn't find expected continuation of a SysEx");
290 SMFError(
"unexpected running status");
299 needed = chantype[status >> 4 & 0x0f];
312 channelMessage(status, c1, getByte());
316 channelMessage(status, c1, 0);
326 lookfor = readVarLen();
327 lookfor = d->m_ToBeRead - lookfor;
329 while (d->m_ToBeRead > lookfor)
336 lookfor = readVarLen();
337 lookfor = d->m_ToBeRead - lookfor;
340 while (d->m_ToBeRead > lookfor)
351 sysexcontinue =
true;
355 lookfor = readVarLen();
356 lookfor = d->m_ToBeRead - lookfor;
361 while (d->m_ToBeRead > lookfor)
371 sysexcontinue =
false;
376 badByte(c, d->m_IOStream->device()->pos() - 1);
390 for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
403 void QSmf::SMFWrite()
407 writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
409 if (d->m_fileFormat == 1)
413 for (i = 0; i < d->m_Tracks; ++i)
425 d->m_IOStream = stream;
435 QFile file(fileName);
436 file.open(QIODevice::ReadOnly);
437 QDataStream ds(&file);
448 d->m_IOStream = stream;
458 QFile file(fileName);
459 file.open(QIODevice::WriteOnly);
460 QDataStream ds(&file);
471 void QSmf::writeHeaderChunk(
int format,
int ntracks,
int division)
477 write16bit(division);
484 void QSmf::writeTrackChunk(
int track)
494 offset = d->m_IOStream->device()->pos();
496 write32bit(trklength);
497 d->m_NumBytesWritten = 0;
501 place_marker = d->m_IOStream->device()->pos();
502 d->m_IOStream->device()->seek(offset);
503 trklength = d->m_NumBytesWritten;
505 write32bit(trklength);
506 d->m_IOStream->device()->seek(place_marker);
517 writeVarLen(deltaTime);
519 putByte(d->m_LastStatus);
521 writeVarLen(data.size());
522 foreach(
char byte, data)
534 writeVarLen(deltaTime);
538 if (d->m_codec == NULL)
539 lcldata = data.toLatin1();
541 lcldata = d->m_codec->fromUnicode(data);
542 writeVarLen(lcldata.length());
543 foreach(
char byte, lcldata)
556 writeVarLen(deltaTime);
570 writeVarLen(deltaTime);
584 const QByteArray& data)
588 writeVarLen(deltaTime);
598 SMFError(
"error: MIDI channel greater than 16");
602 if (d->m_LastStatus != c)
614 j = (data[0] == type ? 1 : 0);
615 for (i = j; i < data.size(); ++i)
631 writeVarLen(deltaTime);
634 SMFError(
"error: Wrong method for a system exclusive event");
638 SMFError(
"error: MIDI channel greater than 16");
641 if (d->m_LastStatus != c)
660 writeVarLen(deltaTime);
663 SMFError(
"error: Wrong method for a system exclusive event");
667 SMFError(
"error: MIDI channel greater than 16");
670 if (d->m_LastStatus != c)
688 unsigned int i, j, size;
690 writeVarLen(deltaTime);
693 SMFError(
"error: type should be system exclusive");
699 c = (unsigned)data[0];
703 j = (c == type ? 1 : 0);
704 for (i = j; i < (unsigned)len; ++i)
717 writeVarLen(deltaTime);
719 putByte(d->m_LastStatus);
722 putByte((seqnum >> 8) & 0xff);
723 putByte(seqnum & 0xff);
733 writeVarLen(deltaTime);
737 putByte((tempo >> 16) & 0xff);
738 putByte((tempo >> 8) & 0xff);
739 putByte(tempo & 0xff);
749 long us_tempo = 60000000l / tempo;
763 writeVarLen(deltaTime);
781 writeVarLen(deltaTime);
786 putByte(mode & 0x01);
793 void QSmf::writeVarLen(quint64 value)
797 buffer = value & 0x7f;
798 while ((value >>= 7) > 0)
802 buffer += (value & 0x7f);
806 putByte(buffer & 0xff);
816 void QSmf::write32bit(quint32 data)
818 putByte((data >> 24) & 0xff);
819 putByte((data >> 16) & 0xff);
820 putByte((data >> 8) & 0xff);
821 putByte(data & 0xff);
824 void QSmf::write16bit(quint16 data)
826 putByte((data >> 8) & 0xff);
827 putByte(data & 0xff);
830 quint16 QSmf::to16bit(quint8 c1, quint8 c2)
838 quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
848 quint16 QSmf::read16bit()
853 return to16bit(c1, c2);
856 quint32 QSmf::read32bit()
858 quint8 c1, c2, c3, c4;
863 return to32bit(c1, c2, c3, c4);
866 long QSmf::readVarLen()
879 value = (value << 7) + (c & 0x7f);
880 }
while ((c & 0x80) != 0);
885 void QSmf::readExpected(
const QString& s)
889 for (j = 0; j < s.length(); ++j)
892 if (QChar(b) != s[j])
894 SMFError(QString(
"Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
900 quint64 QSmf::findTempo()
902 quint64 result, old_tempo, new_tempo;
903 QSmfRecTempo rec = d->m_TempoList.last();
904 old_tempo = d->m_CurrTempo;
905 new_tempo = d->m_CurrTempo;
906 QList<QSmfRecTempo>::Iterator it;
907 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
910 if (rec.time <= d->m_CurrTime)
912 old_tempo = rec.tempo;
914 new_tempo = rec.tempo;
915 if (rec.time > d->m_RevisedTime)
920 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
922 d->m_RevisedTime = d->m_CurrTime;
927 d->m_RevisedTime = rec.time;
928 d->m_TempoChangeTime = d->m_RevisedTime;
937 double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
941 double smpte_resolution;
945 result =
static_cast<double>(ticks * tempo)/(division * 1000000.0);
949 smpte_format = upperByte(division);
950 smpte_resolution = lowerByte(division);
951 result =
static_cast<double>(ticks)/(smpte_format * smpte_resolution
957 void QSmf::SMFError(
const QString& s)
962 void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
969 SMFError(QString(
"ChannelMessage with bad c1 = %1").arg(c1));
974 SMFError(QString(
"ChannelMessage with bad c2 = %1").arg(c2));
998 k = c1 + (c2 << 7) - 8192;
1002 SMFError(QString(
"Invalid MIDI status %1. Unhandled event").arg(status));
1007 void QSmf::metaEvent(quint8 b)
1010 QByteArray m(d->m_MsgBuff);
1025 if (d->m_codec == NULL)
1028 s = d->m_codec->toUnicode(m);
1042 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1044 rec = d->m_TempoList.last();
1045 if (rec.tempo == d->m_CurrTempo)
1049 if (rec.time > d->m_CurrTime)
1053 addTempo(d->m_CurrTempo, d->m_CurrTime);
1076 QByteArray varr(d->m_MsgBuff);
1080 void QSmf::badByte(quint8 b,
int p)
1082 SMFError(QString(
"Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1085 quint8 QSmf::lowerByte(quint16 x)
1090 quint8 QSmf::upperByte(quint16 x)
1092 return ((x >> 8) & 0xff);
1095 void QSmf::msgInit()
1097 d->m_MsgBuff.truncate(0);
1100 void QSmf::msgAdd(quint8 b)
1102 int s = d->m_MsgBuff.size();
1103 d->m_MsgBuff.resize(s + 1);
1104 d->m_MsgBuff[s] = b;
1115 return d->m_CurrTime;
1124 return d->m_CurrTempo;
1133 return d->m_RealTime;
1142 return d->m_Division;
1151 d->m_Division = division;
1169 d->m_Tracks = tracks;
1178 return d->m_fileFormat;
1187 d->m_fileFormat = fileFormat;
1196 return (
long) d->m_IOStream->device()->pos();
void signalSMFNoteOff(int chan, int pitch, int vol)
Emitted after reading a Note Off message.
void signalSMFSeqSpecific(const QByteArray &data)
Emitted after reading a Sequencer specific message.
long getRealTime()
Gets the real time in seconds.
#define forced_port
SMF Forced MIDI port.
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
#define midi_command_mask
Mask to extract the command from the status byte.
void signalSMFHeader(int format, int ntrks, int division)
Emitted after reading a SMF header.
#define forced_channel
SMF Forced MIDI channel.
void signalSMFforcedPort(int port)
Emitted after reading a Forced port message.
void writeToStream(QDataStream *stream)
Writes a SMF stream.
void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
#define marker
SMF Marker.
#define channel_aftertouch
MIDI event Channel after-touch.
long getCurrentTime()
Gets the current time in ticks.
void signalSMFText(int typ, const QString &data)
Emitted after reading a SMF text message.
The QObject class is the base class of all Qt objects.
void signalSMFTrackStart()
Emitted after reading a track prefix.
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
#define key_signature
SMF Key signature.
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
QSmf(QObject *parent=0)
Constructor.
int getTracks()
Gets the number of tracks.
void signalSMFSmpte(int b0, int b1, int b2, int b3, int b4)
Emitted after reading a SMPT offset message.
void signalSMFWriteTrack(int track)
Emitted to request the user to write a track.
long getFilePos()
Gets the position in the SMF stream.
void setTracks(int tracks)
Sets the number of tracks.
#define control_change
MIDI event Control change.
long getCurrentTempo()
Gets the current tempo.
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change message.
void signalSMFError(const QString &errorStr)
Emitted for a SMF read or write error.
#define sequencer_specific
SMF Sequencer specific.
#define MTrk
SMF Track prefix.
virtual ~QSmf()
Destructor.
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
void signalSMFNoteOn(int chan, int pitch, int vol)
Emitted after reading a Note On message.
void readFromStream(QDataStream *stream)
Reads a SMF stream.
#define time_signature
SMF Time signature.
#define smpte_offset
SMF SMPTE offset.
void writeKeySignature(long deltaTime, int tone, int mode)
Writes a key Signature message.
void signalSMFSequenceNum(int seq)
Emitted after reading a Sequence number message.
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
int getFileFormat()
Gets the SMF file format.
#define end_of_track
SMF End of track.
void signalSMFKeySig(int b0, int b1)
Emitted after reading a SMF Key Signature smessage.
#define sequence_number
SMF Sequence number.
void signalSMFTempo(int tempo)
Emitted after reading a Tempo Change message.
void signalSMFWriteTempoTrack()
Emitted to request the user to write the tempo track.
#define text_event
SMF Text event.
#define note_off
MIDI event Note Off.
void signalSMFTrackEnd()
Emitted after a track has finished.
#define poly_aftertouch
MIDI event Polyphonic pressure.
#define end_of_sysex
MIDI event System Exclusive end.
void signalSMFChanPress(int chan, int press)
Emitted after reading a Channel Aftertouch message.
#define meta_event
SMF Meta Event prefix.
#define pitch_wheel
MIDI event Bender.
void signalSMFMetaMisc(int typ, const QByteArray &data)
Emitted after reading any SMF Meta message.
QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
void signalSMFMetaUnregistered(int typ, const QByteArray &data)
Emitted after reading an unregistered SMF Meta message.
#define set_tempo
SMF Tempo change.
void writeSequenceNumber(long deltaTime, int seqnum)
Writes a MIDI Sequence number.
#define instrument_name
SMF Instrument name.
void setDivision(int division)
Sets the resolution.
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
void signalSMFTimeSig(int b0, int b1, int b2, int b3)
Emitted after reading a SMF Time signature message.
void writeMetaEvent(long deltaTime, int type, const QByteArray &data)
Writes a variable length Meta Event.
#define midi_channel_mask
Mask to extract the channel from the status byte.
void signalSMFCtlChange(int chan, int ctl, int value)
Emitted after reading a Control Change message.
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
void signalSMFendOfTrack()
Emitted after reading a End-Of-Track message.
#define note_on
MIDI event Note On.
#define system_exclusive
MIDI event System Exclusive begin.
#define cue_point
SMF Cue point.
void setFileFormat(int fileFormat)
Sets the SMF file format.
#define program_chng
MIDI event Program change.
#define sequence_name
SMF Sequence name.
Standard MIDI Files Input/Output.
int getDivision()
Gets the resolution.
#define MThd
SMF Header prefix.
#define copyright_notice
SMF Copyright notice.