mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-27 19:30:41 +00:00
More whitespace changes.
svn-id: r18273
This commit is contained in:
parent
bdee380fd9
commit
eeab93cf09
@ -126,7 +126,7 @@ int MidiDriver::detectMusicDriver(int midiFlags) {
|
|||||||
if (musicDriver == MD_AUTO || musicDriver < 0) {
|
if (musicDriver == MD_AUTO || musicDriver < 0) {
|
||||||
if (midiFlags & MDT_PREFER_NATIVE) {
|
if (midiFlags & MDT_PREFER_NATIVE) {
|
||||||
if (musicDriver == MD_AUTO) {
|
if (musicDriver == MD_AUTO) {
|
||||||
#if defined (WIN32) && !defined(_WIN32_WCE)
|
#if defined(WIN32) && !defined(_WIN32_WCE)
|
||||||
musicDriver = MD_WINDOWS; // MD_WINDOWS is default MidiDriver on windows targets
|
musicDriver = MD_WINDOWS; // MD_WINDOWS is default MidiDriver on windows targets
|
||||||
#elif defined(MACOSX)
|
#elif defined(MACOSX)
|
||||||
musicDriver = MD_COREAUDIO;
|
musicDriver = MD_COREAUDIO;
|
||||||
@ -134,7 +134,7 @@ int MidiDriver::detectMusicDriver(int midiFlags) {
|
|||||||
musicDriver = MD_YPA1; // TODO : change this and use Zodiac driver when needed
|
musicDriver = MD_YPA1; // TODO : change this and use Zodiac driver when needed
|
||||||
#elif defined(__MORPHOS__)
|
#elif defined(__MORPHOS__)
|
||||||
musicDriver = MD_ETUDE;
|
musicDriver = MD_ETUDE;
|
||||||
#elif defined (_WIN32_WCE) || defined(UNIX) || defined(X11_BACKEND)
|
#elif defined(_WIN32_WCE) || defined(UNIX) || defined(X11_BACKEND)
|
||||||
// Always use MIDI emulation via adlib driver on CE and UNIX device
|
// Always use MIDI emulation via adlib driver on CE and UNIX device
|
||||||
|
|
||||||
// TODO: We should, for the Unix targets, attempt to detect
|
// TODO: We should, for the Unix targets, attempt to detect
|
||||||
|
@ -133,7 +133,7 @@ public:
|
|||||||
static const char *getErrorName(int error_code);
|
static const char *getErrorName(int error_code);
|
||||||
|
|
||||||
// HIGH-LEVEL SEMANTIC METHODS
|
// HIGH-LEVEL SEMANTIC METHODS
|
||||||
virtual void setPitchBendRange (byte channel, uint range)
|
virtual void setPitchBendRange(byte channel, uint range)
|
||||||
{
|
{
|
||||||
send(( 0 << 16) | (101 << 8) | (0xB0 | channel));
|
send(( 0 << 16) | (101 << 8) | (0xB0 | channel));
|
||||||
send(( 0 << 16) | (100 << 8) | (0xB0 | channel));
|
send(( 0 << 16) | (100 << 8) | (0xB0 | channel));
|
||||||
@ -143,15 +143,15 @@ public:
|
|||||||
send(( 127 << 16) | (100 << 8) | (0xB0 | channel));
|
send(( 127 << 16) | (100 << 8) | (0xB0 | channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void sysEx (byte *msg, uint16 length) { }
|
virtual void sysEx(byte *msg, uint16 length) { }
|
||||||
virtual void sysEx_customInstrument (byte channel, uint32 type, byte *instr) { }
|
virtual void sysEx_customInstrument(byte channel, uint32 type, byte *instr) { }
|
||||||
virtual void metaEvent (byte type, byte*data, uint16 length) { }
|
virtual void metaEvent(byte type, byte*data, uint16 length) { }
|
||||||
|
|
||||||
// Timing functions - MidiDriver now operates timers
|
// Timing functions - MidiDriver now operates timers
|
||||||
virtual void setTimerCallback (void *timer_param, Common::Timer::TimerProc timer_proc) = 0;
|
virtual void setTimerCallback(void *timer_param, Common::Timer::TimerProc timer_proc) = 0;
|
||||||
|
|
||||||
/** The time in microseconds between invocations of the timer callback. */
|
/** The time in microseconds between invocations of the timer callback. */
|
||||||
virtual uint32 getBaseTempo (void) = 0;
|
virtual uint32 getBaseTempo(void) = 0;
|
||||||
|
|
||||||
// Channel allocation functions
|
// Channel allocation functions
|
||||||
virtual MidiChannel *allocateChannel() = 0;
|
virtual MidiChannel *allocateChannel() = 0;
|
||||||
@ -164,29 +164,29 @@ public:
|
|||||||
virtual byte getNumber() = 0;
|
virtual byte getNumber() = 0;
|
||||||
virtual void release() = 0;
|
virtual void release() = 0;
|
||||||
|
|
||||||
virtual void send (uint32 b) = 0; // 4-bit channel portion is ignored
|
virtual void send(uint32 b) = 0; // 4-bit channel portion is ignored
|
||||||
|
|
||||||
// Regular messages
|
// Regular messages
|
||||||
virtual void noteOff (byte note) = 0;
|
virtual void noteOff(byte note) = 0;
|
||||||
virtual void noteOn (byte note, byte velocity) = 0;
|
virtual void noteOn(byte note, byte velocity) = 0;
|
||||||
virtual void programChange (byte program) = 0;
|
virtual void programChange(byte program) = 0;
|
||||||
virtual void pitchBend (int16 bend) = 0; // -0x2000 to +0x1FFF
|
virtual void pitchBend(int16 bend) = 0; // -0x2000 to +0x1FFF
|
||||||
|
|
||||||
// Control Change messages
|
// Control Change messages
|
||||||
virtual void controlChange (byte control, byte value) = 0;
|
virtual void controlChange(byte control, byte value) = 0;
|
||||||
virtual void modulationWheel (byte value) { controlChange (1, value); }
|
virtual void modulationWheel(byte value) { controlChange (1, value); }
|
||||||
virtual void volume (byte value) { controlChange (7, value); }
|
virtual void volume(byte value) { controlChange (7, value); }
|
||||||
virtual void panPosition (byte value) { controlChange (10, value); }
|
virtual void panPosition(byte value) { controlChange (10, value); }
|
||||||
virtual void pitchBendFactor (byte value) = 0;
|
virtual void pitchBendFactor(byte value) = 0;
|
||||||
virtual void detune (byte value) { controlChange (17, value); }
|
virtual void detune(byte value) { controlChange (17, value); }
|
||||||
virtual void priority (byte value) { }
|
virtual void priority(byte value) { }
|
||||||
virtual void sustain (bool value) { controlChange (64, value ? 1 : 0); }
|
virtual void sustain(bool value) { controlChange (64, value ? 1 : 0); }
|
||||||
virtual void effectLevel (byte value) { controlChange (91, value); }
|
virtual void effectLevel(byte value) { controlChange (91, value); }
|
||||||
virtual void chorusLevel (byte value) { controlChange (93, value); }
|
virtual void chorusLevel(byte value) { controlChange (93, value); }
|
||||||
virtual void allNotesOff() { controlChange (123, 0); }
|
virtual void allNotesOff() { controlChange (123, 0); }
|
||||||
|
|
||||||
// SysEx messages
|
// SysEx messages
|
||||||
virtual void sysEx_customInstrument (uint32 type, byte *instr) = 0;
|
virtual void sysEx_customInstrument(uint32 type, byte *instr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,21 +33,21 @@
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
MidiParser::MidiParser() :
|
MidiParser::MidiParser() :
|
||||||
_hanging_notes_count (0),
|
_hanging_notes_count(0),
|
||||||
_driver (0),
|
_driver(0),
|
||||||
_timer_rate (0x4A0000),
|
_timer_rate(0x4A0000),
|
||||||
_ppqn (96),
|
_ppqn(96),
|
||||||
_tempo (500000),
|
_tempo(500000),
|
||||||
_psec_per_tick (5208), // 500000 / 96
|
_psec_per_tick(5208), // 500000 / 96
|
||||||
_autoLoop (false),
|
_autoLoop(false),
|
||||||
_smartJump (false),
|
_smartJump(false),
|
||||||
_num_tracks (0),
|
_num_tracks(0),
|
||||||
_active_track (255),
|
_active_track(255),
|
||||||
_abort_parse (0) {
|
_abort_parse(0) {
|
||||||
memset (_active_notes, 0, sizeof(_active_notes));
|
memset(_active_notes, 0, sizeof(_active_notes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::property (int prop, int value) {
|
void MidiParser::property(int prop, int value) {
|
||||||
switch (prop) {
|
switch (prop) {
|
||||||
case mpAutoLoop:
|
case mpAutoLoop:
|
||||||
_autoLoop = (value != 0);
|
_autoLoop = (value != 0);
|
||||||
@ -56,14 +56,14 @@ void MidiParser::property (int prop, int value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::setTempo (uint32 tempo) {
|
void MidiParser::setTempo(uint32 tempo) {
|
||||||
_tempo = tempo;
|
_tempo = tempo;
|
||||||
if (_ppqn)
|
if (_ppqn)
|
||||||
_psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn;
|
_psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the conventional (i.e. SMF) variable length quantity
|
// This is the conventional (i.e. SMF) variable length quantity
|
||||||
uint32 MidiParser::readVLQ (byte * &data) {
|
uint32 MidiParser::readVLQ(byte * &data) {
|
||||||
byte str;
|
byte str;
|
||||||
uint32 value = 0;
|
uint32 value = 0;
|
||||||
int i;
|
int i;
|
||||||
@ -78,7 +78,7 @@ uint32 MidiParser::readVLQ (byte * &data) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::activeNote (byte channel, byte note, bool active) {
|
void MidiParser::activeNote(byte channel, byte note, bool active) {
|
||||||
if (note >= 128 || channel >= 16)
|
if (note >= 128 || channel >= 16)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ void MidiParser::activeNote (byte channel, byte note, bool active) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::hangingNote (byte channel, byte note, uint32 time_left, bool recycle) {
|
void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool recycle) {
|
||||||
NoteTimer *best = 0;
|
NoteTimer *best = 0;
|
||||||
NoteTimer *ptr = _hanging_notes;
|
NoteTimer *ptr = _hanging_notes;
|
||||||
int i;
|
int i;
|
||||||
@ -115,7 +115,8 @@ void MidiParser::hangingNote (byte channel, byte note, uint32 time_left, bool re
|
|||||||
return;
|
return;
|
||||||
best = ptr;
|
best = ptr;
|
||||||
if (ptr->time_left) {
|
if (ptr->time_left) {
|
||||||
if (recycle) _driver->send (0x80 | channel | note << 8);
|
if (recycle)
|
||||||
|
_driver->send(0x80 | channel | note << 8);
|
||||||
--_hanging_notes_count;
|
--_hanging_notes_count;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -160,7 +161,7 @@ void MidiParser::onTimer() {
|
|||||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||||
if (ptr->time_left) {
|
if (ptr->time_left) {
|
||||||
if (ptr->time_left <= _timer_rate) {
|
if (ptr->time_left <= _timer_rate) {
|
||||||
_driver->send (0x80 | ptr->channel | ptr->note << 8);
|
_driver->send(0x80 | ptr->channel | ptr->note << 8);
|
||||||
ptr->time_left = 0;
|
ptr->time_left = 0;
|
||||||
--_hanging_notes_count;
|
--_hanging_notes_count;
|
||||||
} else {
|
} else {
|
||||||
@ -187,43 +188,43 @@ void MidiParser::onTimer() {
|
|||||||
|
|
||||||
if (info.event == 0xF0) {
|
if (info.event == 0xF0) {
|
||||||
// SysEx event
|
// SysEx event
|
||||||
_driver->sysEx (info.ext.data, (uint16) info.length);
|
_driver->sysEx (info.ext.data, (uint16)info.length);
|
||||||
} else if (info.event == 0xFF) {
|
} else if (info.event == 0xFF) {
|
||||||
// META event
|
// META event
|
||||||
if (info.ext.type == 0x2F) {
|
if (info.ext.type == 0x2F) {
|
||||||
// End of Track must be processed by us,
|
// End of Track must be processed by us,
|
||||||
// as well as sending it to the output device.
|
// as well as sending it to the output device.
|
||||||
if (_autoLoop) {
|
if (_autoLoop) {
|
||||||
jumpToTick (0);
|
jumpToTick(0);
|
||||||
parseNextEvent (_next_event);
|
parseNextEvent(_next_event);
|
||||||
} else {
|
} else {
|
||||||
allNotesOff();
|
allNotesOff();
|
||||||
resetTracking();
|
resetTracking();
|
||||||
_driver->metaEvent (info.ext.type, info.ext.data, (uint16) info.length);
|
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (info.ext.type == 0x51) {
|
} else if (info.ext.type == 0x51) {
|
||||||
if (info.length >= 3) {
|
if (info.length >= 3) {
|
||||||
setTempo (info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
|
setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_driver->metaEvent (info.ext.type, info.ext.data, (uint16) info.length);
|
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
|
||||||
} else {
|
} else {
|
||||||
if (info.command() == 0x8) {
|
if (info.command() == 0x8) {
|
||||||
activeNote (info.channel(), info.basic.param1, false);
|
activeNote(info.channel(), info.basic.param1, false);
|
||||||
} else if (info.command() == 0x9) {
|
} else if (info.command() == 0x9) {
|
||||||
if (info.length > 0)
|
if (info.length > 0)
|
||||||
hangingNote (info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time));
|
hangingNote(info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time));
|
||||||
else
|
else
|
||||||
activeNote (info.channel(), info.basic.param1, true);
|
activeNote(info.channel(), info.basic.param1, true);
|
||||||
}
|
}
|
||||||
_driver->send (info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
_driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!_abort_parse) {
|
if (!_abort_parse) {
|
||||||
_position._last_event_time = event_time;
|
_position._last_event_time = event_time;
|
||||||
parseNextEvent (_next_event);
|
parseNextEvent(_next_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +244,7 @@ void MidiParser::allNotesOff() {
|
|||||||
for (i = 0; i < 128; ++i) {
|
for (i = 0; i < 128; ++i) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
if (_active_notes[i] & (1 << j)) {
|
if (_active_notes[i] & (1 << j)) {
|
||||||
_driver->send (0x80 | j | i << 8);
|
_driver->send(0x80 | j | i << 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +252,7 @@ void MidiParser::allNotesOff() {
|
|||||||
// Turn off all hanging notes
|
// Turn off all hanging notes
|
||||||
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
||||||
if (_hanging_notes[i].time_left) {
|
if (_hanging_notes[i].time_left) {
|
||||||
_driver->send (0x80 | _hanging_notes[i].channel | _hanging_notes[i].note << 8);
|
_driver->send(0x80 | _hanging_notes[i].channel | _hanging_notes[i].note << 8);
|
||||||
_hanging_notes[i].time_left = 0;
|
_hanging_notes[i].time_left = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,15 +260,15 @@ void MidiParser::allNotesOff() {
|
|||||||
|
|
||||||
// To be sure, send an "All Note Off" event (but not all MIDI devices support this...)
|
// To be sure, send an "All Note Off" event (but not all MIDI devices support this...)
|
||||||
for (i = 0; i < 16; ++i)
|
for (i = 0; i < 16; ++i)
|
||||||
_driver->send (0x007BB0 | i);
|
_driver->send(0x007BB0 | i);
|
||||||
memset (_active_notes, 0, sizeof(_active_notes));
|
memset(_active_notes, 0, sizeof(_active_notes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::resetTracking() {
|
void MidiParser::resetTracking() {
|
||||||
_position.clear();
|
_position.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MidiParser::setTrack (int track) {
|
bool MidiParser::setTrack(int track) {
|
||||||
if (track < 0 || track >= _num_tracks)
|
if (track < 0 || track >= _num_tracks)
|
||||||
return false;
|
return false;
|
||||||
else if (track == _active_track)
|
else if (track == _active_track)
|
||||||
@ -279,30 +280,32 @@ bool MidiParser::setTrack (int track) {
|
|||||||
allNotesOff();
|
allNotesOff();
|
||||||
|
|
||||||
resetTracking();
|
resetTracking();
|
||||||
memset (_active_notes, 0, sizeof(_active_notes));
|
memset(_active_notes, 0, sizeof(_active_notes));
|
||||||
_active_track = track;
|
_active_track = track;
|
||||||
_position._play_pos = _tracks[track];
|
_position._play_pos = _tracks[track];
|
||||||
parseNextEvent (_next_event);
|
parseNextEvent(_next_event);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser::hangAllActiveNotes() {
|
void MidiParser::hangAllActiveNotes() {
|
||||||
// Search for note off events until we have
|
// Search for note off events until we have
|
||||||
// accounted for every active note.
|
// accounted for every active note.
|
||||||
uint16 temp_active [128];
|
uint16 temp_active[128];
|
||||||
memcpy (temp_active, _active_notes, sizeof (temp_active));
|
memcpy(temp_active, _active_notes, sizeof (temp_active));
|
||||||
|
|
||||||
uint32 advance_tick = _position._last_event_tick;
|
uint32 advance_tick = _position._last_event_tick;
|
||||||
while (true) {
|
while (true) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < 128; ++i)
|
for (i = 0; i < 128; ++i)
|
||||||
if (temp_active[i] != 0) break;
|
if (temp_active[i] != 0)
|
||||||
if (i == 128) break;
|
break;
|
||||||
parseNextEvent (_next_event);
|
if (i == 128)
|
||||||
|
break;
|
||||||
|
parseNextEvent(_next_event);
|
||||||
advance_tick += _next_event.delta;
|
advance_tick += _next_event.delta;
|
||||||
if (_next_event.command() == 0x8) {
|
if (_next_event.command() == 0x8) {
|
||||||
if (temp_active[_next_event.basic.param1] & (1 << _next_event.channel())) {
|
if (temp_active[_next_event.basic.param1] & (1 << _next_event.channel())) {
|
||||||
hangingNote (_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick, false);
|
hangingNote(_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick, false);
|
||||||
temp_active[_next_event.basic.param1] &= ~ (1 << _next_event.channel());
|
temp_active[_next_event.basic.param1] &= ~ (1 << _next_event.channel());
|
||||||
}
|
}
|
||||||
} else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
|
} else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
|
||||||
@ -310,8 +313,8 @@ void MidiParser::hangAllActiveNotes() {
|
|||||||
for (i = 0; i < 128; ++i) {
|
for (i = 0; i < 128; ++i) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
if (temp_active[i] & (1 << j)) {
|
if (temp_active[i] & (1 << j)) {
|
||||||
activeNote (j, i, false);
|
activeNote(j, i, false);
|
||||||
_driver->send (0x80 | j | i << 8);
|
_driver->send(0x80 | j | i << 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,16 +323,16 @@ void MidiParser::hangAllActiveNotes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MidiParser::jumpToTick (uint32 tick, bool fireEvents) {
|
bool MidiParser::jumpToTick(uint32 tick, bool fireEvents) {
|
||||||
if (_active_track >= _num_tracks)
|
if (_active_track >= _num_tracks)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Tracker currentPos (_position);
|
Tracker currentPos(_position);
|
||||||
EventInfo currentEvent (_next_event);
|
EventInfo currentEvent(_next_event);
|
||||||
|
|
||||||
resetTracking();
|
resetTracking();
|
||||||
_position._play_pos = _tracks[_active_track];
|
_position._play_pos = _tracks[_active_track];
|
||||||
parseNextEvent (_next_event);
|
parseNextEvent(_next_event);
|
||||||
if (tick > 0) {
|
if (tick > 0) {
|
||||||
while (true) {
|
while (true) {
|
||||||
EventInfo &info = _next_event;
|
EventInfo &info = _next_event;
|
||||||
@ -351,26 +354,26 @@ bool MidiParser::jumpToTick (uint32 tick, bool fireEvents) {
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (info.ext.type == 0x51 && info.length >= 3) // Tempo
|
if (info.ext.type == 0x51 && info.length >= 3) // Tempo
|
||||||
setTempo (info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
|
setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
|
||||||
if (fireEvents)
|
if (fireEvents)
|
||||||
_driver->metaEvent (info.ext.type, info.ext.data, (uint16) info.length);
|
_driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length);
|
||||||
}
|
}
|
||||||
} else if (fireEvents) {
|
} else if (fireEvents) {
|
||||||
if (info.event == 0xF0)
|
if (info.event == 0xF0)
|
||||||
_driver->sysEx (info.ext.data, (uint16) info.length);
|
_driver->sysEx(info.ext.data, (uint16) info.length);
|
||||||
else
|
else
|
||||||
_driver->send (info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
_driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseNextEvent (_next_event);
|
parseNextEvent(_next_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_smartJump || !currentPos._play_pos) {
|
if (!_smartJump || !currentPos._play_pos) {
|
||||||
allNotesOff();
|
allNotesOff();
|
||||||
} else {
|
} else {
|
||||||
EventInfo targetEvent (_next_event);
|
EventInfo targetEvent(_next_event);
|
||||||
Tracker targetPosition (_position);
|
Tracker targetPosition(_position);
|
||||||
|
|
||||||
_position = currentPos;
|
_position = currentPos;
|
||||||
_next_event = currentEvent;
|
_next_event = currentEvent;
|
||||||
|
@ -58,13 +58,13 @@ struct Tracker {
|
|||||||
Tracker() { clear(); }
|
Tracker() { clear(); }
|
||||||
|
|
||||||
//! Copy constructor for each duplication of Tracker information.
|
//! Copy constructor for each duplication of Tracker information.
|
||||||
Tracker (const Tracker ©) :
|
Tracker(const Tracker ©) :
|
||||||
_play_pos (copy._play_pos),
|
_play_pos(copy._play_pos),
|
||||||
_play_time (copy._play_time),
|
_play_time(copy._play_time),
|
||||||
_play_tick (copy._play_tick),
|
_play_tick(copy._play_tick),
|
||||||
_last_event_time (copy._last_event_time),
|
_last_event_time(copy._last_event_time),
|
||||||
_last_event_tick (copy._last_event_tick),
|
_last_event_tick(copy._last_event_tick),
|
||||||
_running_status (copy._running_status)
|
_running_status(copy._running_status)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
//! Clears all data; used by the constructor for initialization.
|
//! Clears all data; used by the constructor for initialization.
|
||||||
@ -290,13 +290,13 @@ protected:
|
|||||||
bool _abort_parse; //!< If a jump or other operation interrupts parsing, flag to abort.
|
bool _abort_parse; //!< If a jump or other operation interrupts parsing, flag to abort.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static uint32 readVLQ (byte * &data);
|
static uint32 readVLQ(byte * &data);
|
||||||
virtual void resetTracking();
|
virtual void resetTracking();
|
||||||
virtual void allNotesOff();
|
virtual void allNotesOff();
|
||||||
virtual void parseNextEvent (EventInfo &info) = 0;
|
virtual void parseNextEvent(EventInfo &info) = 0;
|
||||||
|
|
||||||
void activeNote (byte channel, byte note, bool active);
|
void activeNote(byte channel, byte note, bool active);
|
||||||
void hangingNote (byte channel, byte note, uint32 ticks_left, bool recycle = true);
|
void hangingNote(byte channel, byte note, uint32 ticks_left, bool recycle = true);
|
||||||
void hangAllActiveNotes();
|
void hangAllActiveNotes();
|
||||||
|
|
||||||
//! Platform independent BE uint32 read-and-advance.
|
//! Platform independent BE uint32 read-and-advance.
|
||||||
@ -304,8 +304,8 @@ protected:
|
|||||||
* from a memory pointer, at the same time advancing
|
* from a memory pointer, at the same time advancing
|
||||||
* the pointer.
|
* the pointer.
|
||||||
*/
|
*/
|
||||||
uint32 read4high (byte * &data) {
|
uint32 read4high(byte * &data) {
|
||||||
uint32 val = READ_BE_UINT32 (data);
|
uint32 val = READ_BE_UINT32(data);
|
||||||
data += 4;
|
data += 4;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -315,8 +315,8 @@ protected:
|
|||||||
* from a memory pointer, at the same time advancing
|
* from a memory pointer, at the same time advancing
|
||||||
* the pointer.
|
* the pointer.
|
||||||
*/
|
*/
|
||||||
uint16 read2low (byte * &data) {
|
uint16 read2low(byte * &data) {
|
||||||
uint16 val = READ_LE_UINT16 (data);
|
uint16 val = READ_LE_UINT16(data);
|
||||||
data += 2;
|
data += 2;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -348,24 +348,24 @@ public:
|
|||||||
MidiParser();
|
MidiParser();
|
||||||
virtual ~MidiParser() { allNotesOff(); }
|
virtual ~MidiParser() { allNotesOff(); }
|
||||||
|
|
||||||
virtual bool loadMusic (byte *data, uint32 size) = 0;
|
virtual bool loadMusic(byte *data, uint32 size) = 0;
|
||||||
virtual void unloadMusic();
|
virtual void unloadMusic();
|
||||||
virtual void property (int prop, int value);
|
virtual void property(int prop, int value);
|
||||||
|
|
||||||
void setMidiDriver (MidiDriver *driver) { _driver = driver; }
|
void setMidiDriver(MidiDriver *driver) { _driver = driver; }
|
||||||
void setTimerRate (uint32 rate) { _timer_rate = rate; }
|
void setTimerRate(uint32 rate) { _timer_rate = rate; }
|
||||||
void setTempo (uint32 tempo);
|
void setTempo(uint32 tempo);
|
||||||
void onTimer();
|
void onTimer();
|
||||||
|
|
||||||
bool setTrack (int track);
|
bool setTrack(int track);
|
||||||
bool jumpToTick (uint32 tick, bool fireEvents = false);
|
bool jumpToTick(uint32 tick, bool fireEvents = false);
|
||||||
|
|
||||||
uint32 getPPQN() { return _ppqn; }
|
uint32 getPPQN() { return _ppqn; }
|
||||||
virtual uint32 getTick() { return _position._play_tick; }
|
virtual uint32 getTick() { return _position._play_tick; }
|
||||||
|
|
||||||
static MidiParser *createParser_SMF();
|
static MidiParser *createParser_SMF();
|
||||||
static MidiParser *createParser_XMIDI();
|
static MidiParser *createParser_XMIDI();
|
||||||
static void timerCallback (void *data) { ((MidiParser *) data)->onTimer(); }
|
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,14 +35,14 @@ protected:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void compressToType0();
|
void compressToType0();
|
||||||
void parseNextEvent (EventInfo &info);
|
void parseNextEvent(EventInfo &info);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MidiParser_SMF() : _buffer(0), _malformedPitchBends(false) {}
|
MidiParser_SMF() : _buffer(0), _malformedPitchBends(false) {}
|
||||||
~MidiParser_SMF();
|
~MidiParser_SMF();
|
||||||
|
|
||||||
bool loadMusic (byte *data, uint32 size);
|
bool loadMusic(byte *data, uint32 size);
|
||||||
void property (int property, int value);
|
void property(int property, int value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -51,21 +51,21 @@ static const byte special_lengths[16] = { 0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|||||||
|
|
||||||
MidiParser_SMF::~MidiParser_SMF() {
|
MidiParser_SMF::~MidiParser_SMF() {
|
||||||
if (_buffer)
|
if (_buffer)
|
||||||
free (_buffer);
|
free(_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser_SMF::property (int prop, int value) {
|
void MidiParser_SMF::property(int prop, int value) {
|
||||||
switch (prop) {
|
switch (prop) {
|
||||||
case mpMalformedPitchBends:
|
case mpMalformedPitchBends:
|
||||||
_malformedPitchBends = (value > 0);
|
_malformedPitchBends = (value > 0);
|
||||||
default:
|
default:
|
||||||
MidiParser::property (prop, value);
|
MidiParser::property(prop, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser_SMF::parseNextEvent (EventInfo &info) {
|
void MidiParser_SMF::parseNextEvent(EventInfo &info) {
|
||||||
info.start = _position._play_pos;
|
info.start = _position._play_pos;
|
||||||
info.delta = readVLQ (_position._play_pos);
|
info.delta = readVLQ(_position._play_pos);
|
||||||
|
|
||||||
// Process the next info. If mpMalformedPitchBends
|
// Process the next info. If mpMalformedPitchBends
|
||||||
// was set, we must skip over any pitch bend events
|
// was set, we must skip over any pitch bend events
|
||||||
@ -113,14 +113,14 @@ void MidiParser_SMF::parseNextEvent (EventInfo &info) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0: // SysEx
|
case 0x0: // SysEx
|
||||||
info.length = readVLQ (_position._play_pos);
|
info.length = readVLQ(_position._play_pos);
|
||||||
info.ext.data = _position._play_pos;
|
info.ext.data = _position._play_pos;
|
||||||
_position._play_pos += info.length;
|
_position._play_pos += info.length;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xF: // META event
|
case 0xF: // META event
|
||||||
info.ext.type = *(_position._play_pos++);
|
info.ext.type = *(_position._play_pos++);
|
||||||
info.length = readVLQ (_position._play_pos);
|
info.length = readVLQ(_position._play_pos);
|
||||||
info.ext.data = _position._play_pos;
|
info.ext.data = _position._play_pos;
|
||||||
_position._play_pos += info.length;
|
_position._play_pos += info.length;
|
||||||
break;
|
break;
|
||||||
@ -128,7 +128,7 @@ void MidiParser_SMF::parseNextEvent (EventInfo &info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
bool MidiParser_SMF::loadMusic(byte *data, uint32 size) {
|
||||||
uint32 len;
|
uint32 len;
|
||||||
byte midi_type;
|
byte midi_type;
|
||||||
uint32 total_size;
|
uint32 total_size;
|
||||||
@ -138,17 +138,17 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
byte *pos = data;
|
byte *pos = data;
|
||||||
isGMF = false;
|
isGMF = false;
|
||||||
|
|
||||||
if (!memcmp (pos, "RIFF", 4)) {
|
if (!memcmp(pos, "RIFF", 4)) {
|
||||||
// Skip the outer RIFF header.
|
// Skip the outer RIFF header.
|
||||||
pos += 8;
|
pos += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memcmp (pos, "MThd", 4)) {
|
if (!memcmp(pos, "MThd", 4)) {
|
||||||
// SMF with MTHd information.
|
// SMF with MTHd information.
|
||||||
pos += 4;
|
pos += 4;
|
||||||
len = read4high (pos);
|
len = read4high(pos);
|
||||||
if (len != 6) {
|
if (len != 6) {
|
||||||
warning("MThd length 6 expected but found %d", (int) len);
|
warning("MThd length 6 expected but found %d", (int)len);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,12 +158,12 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
_num_tracks = pos[2] << 8 | pos[3];
|
_num_tracks = pos[2] << 8 | pos[3];
|
||||||
midi_type = pos[1];
|
midi_type = pos[1];
|
||||||
if (midi_type > 2 /*|| (midi_type < 2 && _num_tracks > 1)*/) {
|
if (midi_type > 2 /*|| (midi_type < 2 && _num_tracks > 1)*/) {
|
||||||
warning("No support for a Type %d MIDI with %d tracks", (int) midi_type, (int) _num_tracks);
|
warning("No support for a Type %d MIDI with %d tracks", (int)midi_type, (int)_num_tracks);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_ppqn = pos[4] << 8 | pos[5];
|
_ppqn = pos[4] << 8 | pos[5];
|
||||||
pos += len;
|
pos += len;
|
||||||
} else if (!memcmp (pos, "GMF\x1", 4)) {
|
} else if (!memcmp(pos, "GMF\x1", 4)) {
|
||||||
// Older GMD/MUS file with no header info.
|
// Older GMD/MUS file with no header info.
|
||||||
// Assume 1 track, 192 PPQN, and no MTrk headers.
|
// Assume 1 track, 192 PPQN, and no MTrk headers.
|
||||||
isGMF = true;
|
isGMF = true;
|
||||||
@ -178,14 +178,14 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
|
|
||||||
// Now we identify and store the location for each track.
|
// Now we identify and store the location for each track.
|
||||||
if (_num_tracks > ARRAYSIZE(_tracks)) {
|
if (_num_tracks > ARRAYSIZE(_tracks)) {
|
||||||
warning("Can only handle %d tracks but was handed %d", (int) ARRAYSIZE(_tracks), (int) _num_tracks);
|
warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_size = 0;
|
total_size = 0;
|
||||||
int tracks_read = 0;
|
int tracks_read = 0;
|
||||||
while (tracks_read < _num_tracks) {
|
while (tracks_read < _num_tracks) {
|
||||||
if (memcmp (pos, "MTrk", 4) && !isGMF) {
|
if (memcmp(pos, "MTrk", 4) && !isGMF) {
|
||||||
warning("Position: %p ('%c')", pos, *pos);
|
warning("Position: %p ('%c')", pos, *pos);
|
||||||
warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
|
warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
|
||||||
return false;
|
return false;
|
||||||
@ -195,7 +195,7 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
_tracks[tracks_read] = pos + (isGMF ? 0 : 8);
|
_tracks[tracks_read] = pos + (isGMF ? 0 : 8);
|
||||||
if (!isGMF) {
|
if (!isGMF) {
|
||||||
pos += 4;
|
pos += 4;
|
||||||
len = read4high (pos);
|
len = read4high(pos);
|
||||||
total_size += len;
|
total_size += len;
|
||||||
pos += len;
|
pos += len;
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +212,7 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
// If this is a Type 1 MIDI, we need to now compress
|
// If this is a Type 1 MIDI, we need to now compress
|
||||||
// our tracks down into a single Type 0 track.
|
// our tracks down into a single Type 0 track.
|
||||||
if (_buffer) {
|
if (_buffer) {
|
||||||
free (_buffer);
|
free(_buffer);
|
||||||
_buffer = 0;
|
_buffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
// FIXME: Doubled the buffer size to prevent crashes with the
|
// FIXME: Doubled the buffer size to prevent crashes with the
|
||||||
// Inherit the Earth MIDIs. Jamieson630 said something about a
|
// Inherit the Earth MIDIs. Jamieson630 said something about a
|
||||||
// better fix, but this will have to do in the meantime.
|
// better fix, but this will have to do in the meantime.
|
||||||
_buffer = (byte *) malloc (size * 2);
|
_buffer = (byte *)malloc(size * 2);
|
||||||
compressToType0();
|
compressToType0();
|
||||||
_num_tracks = 1;
|
_num_tracks = 1;
|
||||||
_tracks[0] = _buffer;
|
_tracks[0] = _buffer;
|
||||||
@ -230,8 +230,8 @@ bool MidiParser_SMF::loadMusic (byte *data, uint32 size) {
|
|||||||
// will persist beyond this call, i.e. we do NOT
|
// will persist beyond this call, i.e. we do NOT
|
||||||
// copy the data to our own buffer. Take warning....
|
// copy the data to our own buffer. Take warning....
|
||||||
resetTracking();
|
resetTracking();
|
||||||
setTempo (500000);
|
setTempo(500000);
|
||||||
setTrack (0);
|
setTrack(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ void MidiParser_SMF::compressToType0() {
|
|||||||
for (i = 0; i < _num_tracks; ++i) {
|
for (i = 0; i < _num_tracks; ++i) {
|
||||||
running_status[i] = 0;
|
running_status[i] = 0;
|
||||||
track_pos[i] = _tracks[i];
|
track_pos[i] = _tracks[i];
|
||||||
track_timer[i] = readVLQ (track_pos[i]);
|
track_timer[i] = readVLQ(track_pos[i]);
|
||||||
running_status[i] = 0;
|
running_status[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ void MidiParser_SMF::compressToType0() {
|
|||||||
byte event;
|
byte event;
|
||||||
uint32 copy_bytes;
|
uint32 copy_bytes;
|
||||||
bool write;
|
bool write;
|
||||||
byte active_tracks = (byte) _num_tracks;
|
byte active_tracks = (byte)_num_tracks;
|
||||||
|
|
||||||
while (active_tracks) {
|
while (active_tracks) {
|
||||||
write = true;
|
write = true;
|
||||||
@ -293,14 +293,14 @@ void MidiParser_SMF::compressToType0() {
|
|||||||
} while (_malformedPitchBends && (event & 0xF0) == 0xE0 && pos++);
|
} while (_malformedPitchBends && (event & 0xF0) == 0xE0 && pos++);
|
||||||
running_status[best_i] = event;
|
running_status[best_i] = event;
|
||||||
|
|
||||||
if (command_lengths [(event >> 4) - 8] > 0) {
|
if (command_lengths[(event >> 4) - 8] > 0) {
|
||||||
copy_bytes = command_lengths [(event >> 4) - 8];
|
copy_bytes = command_lengths[(event >> 4) - 8];
|
||||||
} else if (special_lengths [(event & 0x0F)] > 0) {
|
} else if (special_lengths[(event & 0x0F)] > 0) {
|
||||||
copy_bytes = special_lengths [(event & 0x0F)];
|
copy_bytes = special_lengths[(event & 0x0F)];
|
||||||
} else if (event == 0xF0) {
|
} else if (event == 0xF0) {
|
||||||
// SysEx
|
// SysEx
|
||||||
pos2 = pos;
|
pos2 = pos;
|
||||||
length = readVLQ (pos);
|
length = readVLQ(pos);
|
||||||
copy_bytes = 1 + (pos - pos2) + length;
|
copy_bytes = 1 + (pos - pos2) + length;
|
||||||
} else if (event == 0xFF) {
|
} else if (event == 0xFF) {
|
||||||
// META
|
// META
|
||||||
@ -310,13 +310,13 @@ void MidiParser_SMF::compressToType0() {
|
|||||||
write = false;
|
write = false;
|
||||||
} else {
|
} else {
|
||||||
pos2 = pos;
|
pos2 = pos;
|
||||||
length = readVLQ (pos);
|
length = readVLQ(pos);
|
||||||
copy_bytes = 2 + (pos - pos2) + length;
|
copy_bytes = 2 + (pos - pos2) + length;
|
||||||
}
|
}
|
||||||
if (event == 0x2F)
|
if (event == 0x2F)
|
||||||
--active_tracks;
|
--active_tracks;
|
||||||
} else {
|
} else {
|
||||||
warning("Bad MIDI command %02X", (int) event);
|
warning("Bad MIDI command %02X", (int)event);
|
||||||
track_pos[best_i] = 0;
|
track_pos[best_i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,24 +334,24 @@ void MidiParser_SMF::compressToType0() {
|
|||||||
|
|
||||||
// Write VLQ delta
|
// Write VLQ delta
|
||||||
while (delta & 0x80) {
|
while (delta & 0x80) {
|
||||||
*output++ = (byte) (delta & 0xFF);
|
*output++ = (byte)(delta & 0xFF);
|
||||||
delta >>= 8;
|
delta >>= 8;
|
||||||
}
|
}
|
||||||
*output++ = (byte) (delta & 0xFF);
|
*output++ = (byte)(delta & 0xFF);
|
||||||
|
|
||||||
// Write MIDI data
|
// Write MIDI data
|
||||||
if (!implicitEvent)
|
if (!implicitEvent)
|
||||||
++track_pos[best_i];
|
++track_pos[best_i];
|
||||||
--copy_bytes;
|
--copy_bytes;
|
||||||
*output++ = running_status[best_i];
|
*output++ = running_status[best_i];
|
||||||
memcpy (output, track_pos[best_i], copy_bytes);
|
memcpy(output, track_pos[best_i], copy_bytes);
|
||||||
output += copy_bytes;
|
output += copy_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch new VLQ delta for winning track
|
// Fetch new VLQ delta for winning track
|
||||||
track_pos[best_i] += copy_bytes;
|
track_pos[best_i] += copy_bytes;
|
||||||
if (active_tracks)
|
if (active_tracks)
|
||||||
track_timer[best_i] += readVLQ (track_pos[best_i]);
|
track_timer[best_i] += readVLQ(track_pos[best_i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,14 +179,14 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
|
|||||||
|
|
||||||
// Must be at least 2 bytes long
|
// Must be at least 2 bytes long
|
||||||
if (chunk_len < 2) {
|
if (chunk_len < 2) {
|
||||||
warning("Invalid chunk length %d for 'INFO' block!", (int) chunk_len);
|
warning("Invalid chunk length %d for 'INFO' block!", (int)chunk_len);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_num_tracks = (byte) read2low(pos);
|
_num_tracks = (byte)read2low(pos);
|
||||||
|
|
||||||
if (chunk_len > 2) {
|
if (chunk_len > 2) {
|
||||||
warning("Chunk length %d is greater than 2", (int) chunk_len);
|
warning("Chunk length %d is greater than 2", (int)chunk_len);
|
||||||
pos += chunk_len - 2;
|
pos += chunk_len - 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -224,7 +224,7 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
|
|||||||
// Ok it's an XMIDI.
|
// Ok it's an XMIDI.
|
||||||
// We're going to identify and store the location for each track.
|
// We're going to identify and store the location for each track.
|
||||||
if (_num_tracks > ARRAYSIZE(_tracks)) {
|
if (_num_tracks > ARRAYSIZE(_tracks)) {
|
||||||
warning("Can only handle %d tracks but was handed %d", (int) ARRAYSIZE(_tracks), (int) _num_tracks);
|
warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user