From 49fa1748f5f47750ba09592a9b63fb87e7bbbcdb Mon Sep 17 00:00:00 2001 From: mahlzeit Date: Mon, 17 Mar 2003 22:30:19 +0000 Subject: [PATCH] cleaned up midi1 git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2934 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/midi/Jamfile | 4 +- src/kits/midi/Midi.cpp | 745 ++++++------- src/kits/midi/MidiEvent.cpp | 26 - src/kits/midi/MidiEvent.h | 135 --- src/kits/midi/MidiGlue.cpp | 220 ++++ src/kits/midi/MidiGlue.h | 118 ++ src/kits/midi/MidiPort.cpp | 304 ++--- src/kits/midi/MidiPortConsumer.cpp | 97 -- src/kits/midi/MidiPortConsumer.h | 42 - src/kits/midi/MidiStore.cpp | 1658 +++++++++++++++------------- src/kits/midi/MidiSynth.cpp | 23 +- src/kits/midi/MidiSynthFile.cpp | 23 +- src/kits/midi/MidiText.cpp | 110 +- src/kits/midi/Samples.cpp | 23 +- src/kits/midi/Synth.cpp | 46 +- 15 files changed, 1834 insertions(+), 1740 deletions(-) delete mode 100644 src/kits/midi/MidiEvent.cpp delete mode 100644 src/kits/midi/MidiEvent.h create mode 100644 src/kits/midi/MidiGlue.cpp create mode 100644 src/kits/midi/MidiGlue.h delete mode 100644 src/kits/midi/MidiPortConsumer.cpp delete mode 100644 src/kits/midi/MidiPortConsumer.h diff --git a/src/kits/midi/Jamfile b/src/kits/midi/Jamfile index 1f610622e0..1a8fbe008d 100644 --- a/src/kits/midi/Jamfile +++ b/src/kits/midi/Jamfile @@ -6,19 +6,17 @@ UsePublicHeaders midi ; SharedLibrary midi : Midi.cpp + MidiGlue.cpp MidiPort.cpp - MidiPortConsumer.cpp MidiStore.cpp MidiSynth.cpp MidiSynthFile.cpp MidiText.cpp - MidiEvent.cpp Samples.cpp Synth.cpp ; LinkSharedOSLibs libmidi.so : be - stdc++.r4 midi2 ; diff --git a/src/kits/midi/Midi.cpp b/src/kits/midi/Midi.cpp index 177be57b16..59501d20d3 100644 --- a/src/kits/midi/Midi.cpp +++ b/src/kits/midi/Midi.cpp @@ -1,465 +1,370 @@ -/** - * @file Midi.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans + * Copyright (c) 2002 Michael Pfeiffer + * Copyright (c) 2002 Jerome Leveque + * Copyright (c) 2002 Paul Stadler + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * @author Matthijs Hollemans - * @author Jerome Leveque - * @author Paul Stadler + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #include +#include #include "Midi.h" +#include "MidiGlue.h" #include "debug.h" -#include "MidiEvent.h" -//----------------------------------------------- +//------------------------------------------------------------------------------ -#define MSG_CODE_PROCESS_EVENT 1 -#define MSG_CODE_TERMINATE_THREAD 0 +status_t _run_thread(void* data) +{ + BMidi* midi = (BMidi*) data; + midi->Run(); + midi->isRunning = false; + return 0; +} -//----------------------------------------------- +//------------------------------------------------------------------------------ -//----------------------------------------------------------------------------- -// Initialization Stuff BMidi::BMidi() { - fConnectionList = new BList(); - fIsRunning = false; - - fInflowPort = create_port(1, "Inflow Port"); - - fInflowTask = spawn_thread( - _inflow_task_, "BMidi Inflow Thread", - B_REAL_TIME_PRIORITY, (void *)this); - - fInflowAlive = resume_thread(fInflowTask) == B_OK; + connections = new BList; + threadId = -1; + isRunning = false; + + producer = new BMidiLocalProducer("MidiGlue(out)"); + consumer = new BMidiGlue(this, "MidiGlue(in)"); } +//------------------------------------------------------------------------------ + BMidi::~BMidi() { - write_port(fInflowPort, MSG_CODE_TERMINATE_THREAD, NULL, 0); + Stop(); - status_t exit_value; - wait_for_thread(fInflowTask, &exit_value); + status_t result; + wait_for_thread(threadId, &result); - delete_port(fInflowPort); - delete fConnectionList; + producer->Release(); + consumer->Release(); + + delete connections; } -//----------------------------------------------------------------------------- -// Stubs for midi event hooks. -void BMidi::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) -{ -} -void BMidi::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) -{ -} -void BMidi::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time) -{ -} -void BMidi::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, uint32 time) -{ -} -void BMidi::ProgramChange(uchar chan, uchar prog_num, uint32 time) -{ -} -void BMidi::ChannelPressure(uchar chan, uchar pres, uint32 time) -{ -} -void BMidi::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) -{ -} -void BMidi::SystemExclusive(void * data, size_t data_len, uint32 time) -{ -} -void BMidi::SystemCommon(uchar stat_byte, uchar data1, uchar data2, uint32 time) -{ -} -void BMidi::SystemRealTime(uchar stat_byte, uint32 time) -{ -} -void BMidi::TempoChange(int32 bpm, uint32 time) -{ -} -void BMidi::AllNotesOff(bool just_chan, uint32 time) +//------------------------------------------------------------------------------ + +void BMidi::NoteOff(uchar channel, uchar note, uchar velocity, uint32 time) { + // do nothing } -//----------------------------------------------------------------------------- -// Public API Functions -status_t BMidi::Start() +//------------------------------------------------------------------------------ + +void BMidi::NoteOn(uchar channel, uchar note, uchar velocity, uint32 time) { - fRunTask = spawn_thread(_run_thread_, - "BMidi Run Thread", B_REAL_TIME_PRIORITY, (void *)this); - fIsRunning = true; - status_t ret = resume_thread(fRunTask); - if(ret != B_OK) + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::KeyPressure( + uchar channel, uchar note, uchar pressure, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::ProgramChange(uchar channel, uchar programNumber, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::ChannelPressure(uchar channel, uchar pressure, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::SystemExclusive(void* data, size_t length, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::SystemCommon(uchar status, uchar data1, uchar data2, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::SystemRealTime(uchar status, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::TempoChange(int32 beatsPerMinute, uint32 time) +{ + // do nothing +} + +//------------------------------------------------------------------------------ + +void BMidi::AllNotesOff(bool justChannel, uint32 time) +{ + for (uchar channel = 1; channel <= 16; ++channel) { - fIsRunning = false; - } - return B_OK; -} + SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time); -//----------------------------------------------------------------------------- - -void BMidi::Stop() -{ - status_t exit_value; - status_t ret; - fIsRunning = false; - ret = wait_for_thread(fRunTask, &exit_value); -} - -bool BMidi::IsRunning() const -{ - thread_info info; - get_thread_info(fRunTask,&info); - if(find_thread("BMidi Run Thread") == fRunTask) - return true; -return false; -} - -void BMidi::Connect(BMidi *to_object) -{ - fConnectionList->AddItem((void *)to_object); -} - -void BMidi::Disconnect(BMidi *from_object) -{ - fConnectionList->RemoveItem((void *)from_object); -} - -bool BMidi::IsConnected(BMidi * to_object) const -{ - return fConnectionList->HasItem((void *)to_object); -} - -BList * BMidi::Connections() const -{ - return fConnectionList; -} - -void BMidi::SnoozeUntil(uint32 time) const -{ - snooze_until((uint64)time*1000, B_SYSTEM_TIMEBASE); -} - -bool BMidi::KeepRunning() -{ - return fIsRunning; -} - -void BMidi::Run() -{ - while(KeepRunning()) - snooze(50000); -} - -//----------------------------------------------------------------------------- -// Spray Functions -void BMidi::SprayMidiEvent(BMidiEvent *e) const -{ -// TRACE(("Hello")) - int32 num_connections = fConnectionList->CountItems(); - BMidi *m; - for(int32 i = 0; i < num_connections; i++) - { - m = (BMidi *)fConnectionList->ItemAt(i); - write_port(m->fInflowPort, MSG_CODE_PROCESS_EVENT, e, sizeof(BMidiEvent)); - } -} - -//---------------------- - -void BMidi::SprayNoteOff( - uchar channel, uchar note, uchar velocity, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_NOTE_OFF; - event.noteOff.channel = channel; - event.noteOff.note = note; - event.noteOff.velocity = velocity; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayNoteOn( - uchar channel, uchar note, uchar velocity, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_NOTE_ON; - event.noteOn.channel = channel; - event.noteOn.note = note; - event.noteOn.velocity = velocity; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayKeyPressure( - uchar channel, uchar note, uchar pressure, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_KEY_PRESSURE; - event.keyPressure.channel = channel; - event.keyPressure.note = note; - event.keyPressure.pressure = pressure; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayControlChange( - uchar channel, uchar controlNumber, uchar controlValue, - uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_CONTROL_CHANGE; - event.controlChange.channel = channel; - event.controlChange.controlNumber = controlNumber; - event.controlChange.controlValue = controlValue; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayProgramChange( - uchar channel, uchar programNumber, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_PROGRAM_CHANGE; - event.programChange.channel = channel; - event.programChange.programNumber = programNumber; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayChannelPressure( - uchar channel, uchar pressure, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_CHANNEL_PRESSURE; - event.channelPressure.channel = channel; - event.channelPressure.pressure = pressure; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayPitchBend( - uchar channel, uchar lsb, uchar msb, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_PITCH_BEND; - event.pitchBend.channel = channel; - event.pitchBend.lsb = lsb; - event.pitchBend.msb = msb; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SpraySystemExclusive( - void * data, size_t dataLength, uint32 time) const -{ - // Should this data be duplicated!!?? I think Yes. - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE; - event.systemExclusive.data = new uint8[dataLength]; - memcpy(event.systemExclusive.data, data, dataLength); - event.systemExclusive.dataLength = dataLength; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SpraySystemCommon( - uchar status, uchar data1, uchar data2, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_SYSTEM_COMMON; - event.systemCommon.status = status; - event.systemCommon.data1 = data1; - event.systemCommon.data2 = data2; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SpraySystemRealTime(uchar status, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_SYSTEM_REAL_TIME; - event.systemRealTime.status = status; - SprayMidiEvent(&event); -} - -//---------------------- - -void BMidi::SprayTempoChange(int32 beatsPerMinute, uint32 time) const -{ - BMidiEvent event; - event.time = time; - event.opcode = BMidiEvent::OP_TEMPO_CHANGE; - event.tempoChange.beatsPerMinute = beatsPerMinute; - SprayMidiEvent(&event); -} - -//----------------------------------------------------------------------------- -// The Inflow Thread -void BMidi::InflowTask() -{ - BMidiEvent event; - int32 code; - size_t len; - while(true) - { - len = read_port(fInflowPort, &code, &event, sizeof(BMidiEvent)); - - if (code == MSG_CODE_TERMINATE_THREAD) { return; } - - if (len != sizeof(BMidiEvent)) { continue; } //ignore errors - - switch (event.opcode) + if (!justChannel) { - case BMidiEvent::OP_NONE: - case BMidiEvent::OP_TRACK_END: - case BMidiEvent::OP_ALL_NOTES_OFF: - break; - - case BMidiEvent::OP_NOTE_OFF: - NoteOff( - event.noteOff.channel, - event.noteOff.note, - event.noteOff.velocity, - event.time); - break; - - case BMidiEvent::OP_NOTE_ON: - NoteOn( - event.noteOn.channel, - event.noteOn.note, - event.noteOn.velocity, - event.time); - break; - - case BMidiEvent::OP_KEY_PRESSURE: - KeyPressure( - event.keyPressure.channel, - event.keyPressure.note, - event.keyPressure.pressure, - event.time); - break; - - case BMidiEvent::OP_CONTROL_CHANGE: - ControlChange( - event.controlChange.channel, - event.controlChange.controlNumber, - event.controlChange.controlValue, - event.time); - break; - - case BMidiEvent::OP_PROGRAM_CHANGE: - ProgramChange( - event.programChange.channel, - event.programChange.programNumber, - event.time); - break; - - case BMidiEvent::OP_CHANNEL_PRESSURE: - ChannelPressure( - event.channelPressure.channel, - event.channelPressure.pressure, - event.time); - break; - - case BMidiEvent::OP_PITCH_BEND: - PitchBend( - event.pitchBend.channel, - event.pitchBend.lsb, - event.pitchBend.msb, - event.time); - break; - - case BMidiEvent::OP_SYSTEM_EXCLUSIVE: - SystemExclusive( - event.systemExclusive.data, - event.systemExclusive.dataLength, - event.time); - break; - - case BMidiEvent::OP_SYSTEM_COMMON: - SystemCommon( - event.systemCommon.status, - event.systemCommon.data1, - event.systemCommon.data2, - event.time); - break; - - case BMidiEvent::OP_SYSTEM_REAL_TIME: - SystemRealTime( - event.systemRealTime.status, - event.time); - break; - - case BMidiEvent::OP_TEMPO_CHANGE: - TempoChange( - event.tempoChange.beatsPerMinute, - event.time); - break; - - default: break; + for (uchar note = 0; note <= 0x7F; ++note) + { + SprayNoteOff(channel, note, 0, time); + } } } } -//---------------------- -//---------------------- -//---------------------- -//---------------------- -//---------------------- -//---------------------- -//---------------------- -//---------------------- +//------------------------------------------------------------------------------ + +status_t BMidi::Start() +{ + if (isRunning) { return B_OK; } + + status_t err = spawn_thread( + _run_thread, "MidiRunThread", B_URGENT_PRIORITY, this); + + if (err < B_OK) { return err; } + + threadId = err; + isRunning = true; + + err = resume_thread(threadId); + if (err != B_OK) + { + threadId = -1; + isRunning = false; + } + + return err; +} + +//------------------------------------------------------------------------------ + +void BMidi::Stop() +{ + threadId = -1; +} + +//------------------------------------------------------------------------------ + +bool BMidi::IsRunning() const +{ + return isRunning; +} + +//------------------------------------------------------------------------------ + +void BMidi::Connect(BMidi* toObject) +{ + if (toObject != NULL) + { + if (producer->Connect(toObject->consumer) == B_OK) + { + connections->AddItem(toObject); + } + } +} + +//------------------------------------------------------------------------------ + +void BMidi::Disconnect(BMidi* fromObject) +{ + if (fromObject != NULL) + { + if (producer->Disconnect(fromObject->consumer) == B_OK) + { + connections->RemoveItem(fromObject); + } + } +} + +//------------------------------------------------------------------------------ + +bool BMidi::IsConnected(BMidi* toObject) const +{ + if (toObject != NULL) + { + return producer->IsConnected(toObject->consumer); + } + + return false; +} + +//------------------------------------------------------------------------------ + +BList* BMidi::Connections() const +{ + return connections; +} + +//------------------------------------------------------------------------------ + +void BMidi::SnoozeUntil(uint32 time) const +{ + snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); +} + +//------------------------------------------------------------------------------ + +bool BMidi::KeepRunning() +{ + return (threadId != -1); +} + +//------------------------------------------------------------------------------ void BMidi::_ReservedMidi1() {} void BMidi::_ReservedMidi2() {} void BMidi::_ReservedMidi3() {} -//---------------------- +//------------------------------------------------------------------------------ -status_t _run_thread_(void *data) +void BMidi::Run() { - ((BMidi*)data)->Run(); - return 0; + // do nothing } -//---------------------- +//------------------------------------------------------------------------------ -status_t _inflow_task_(void * data) +void BMidi::SprayNoteOff( + uchar channel, uchar note, uchar velocity, uint32 time) const { - ((BMidi*)data)->InflowTask(); - return 0; + producer->SprayNoteOff( + channel - 1, note, velocity, MAKE_BIGTIME(time)); } -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- +//------------------------------------------------------------------------------ + +void BMidi::SprayNoteOn( + uchar channel, uchar note, uchar velocity, uint32 time) const +{ + producer->SprayNoteOn( + channel - 1, note, velocity, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayKeyPressure( + uchar channel, uchar note, uchar pressure, uint32 time) const +{ + producer->SprayKeyPressure( + channel - 1, note, pressure, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayControlChange( + uchar channel, uchar controlNumber, uchar controlValue, + uint32 time) const +{ + producer->SprayControlChange( + channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayProgramChange( + uchar channel, uchar programNumber, uint32 time) const +{ + producer->SprayProgramChange( + channel - 1, programNumber, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayChannelPressure( + uchar channel, uchar pressure, uint32 time) const +{ + producer->SprayChannelPressure( + channel - 1, pressure, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayPitchBend( + uchar channel, uchar lsb, uchar msb, uint32 time) const +{ + producer->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SpraySystemExclusive( + void* data, size_t length, uint32 time) const +{ + producer->SpraySystemExclusive(data, length, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SpraySystemCommon( + uchar status, uchar data1, uchar data2, uint32 time) const +{ + producer->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SpraySystemRealTime(uchar status, uint32 time) const +{ + producer->SpraySystemRealTime(status, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidi::SprayTempoChange(int32 beatsPerMinute, uint32 time) const +{ + producer->SprayTempoChange(beatsPerMinute, MAKE_BIGTIME(time)); +} + +//------------------------------------------------------------------------------ diff --git a/src/kits/midi/MidiEvent.cpp b/src/kits/midi/MidiEvent.cpp deleted file mode 100644 index 97bf3f4866..0000000000 --- a/src/kits/midi/MidiEvent.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file MidiEvent.cpp - * - * @author Matthijs Hollemans - * @author Paul Stadler - */ - -#include "MidiEvent.h" - -//------------------------------------------------------------------------------ - -BMidiEvent::BMidiEvent() -{ - opcode = OP_NONE; -} - -//------------------------------------------------------------------------------ - -BMidiEvent::~BMidiEvent() -{ - if (opcode == OP_SYSTEM_EXCLUSIVE) - delete systemExclusive.data; -} - -//------------------------------------------------------------------------------ - diff --git a/src/kits/midi/MidiEvent.h b/src/kits/midi/MidiEvent.h deleted file mode 100644 index 8f362155d9..0000000000 --- a/src/kits/midi/MidiEvent.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file MidiEvent.h - * - * @author Matthijs Hollemans - * @author Paul Stadler - */ - -#ifndef _MIDI_EVENT_H -#define _MIDI_EVENT_H - -#include "MidiDefs.h" - -/** - * Describes a MIDI message and its attributes. - */ -class BMidiEvent -{ -public: - BMidiEvent(); - ~BMidiEvent(); - - enum - { - OP_NONE, - OP_NOTE_OFF, - OP_NOTE_ON, - OP_KEY_PRESSURE, - OP_CONTROL_CHANGE, - OP_PROGRAM_CHANGE, - OP_CHANNEL_PRESSURE, - OP_PITCH_BEND, - OP_SYSTEM_EXCLUSIVE, - OP_SYSTEM_COMMON, - OP_SYSTEM_REAL_TIME, - OP_TEMPO_CHANGE, - OP_ALL_NOTES_OFF, - OP_TRACK_END, - } - opcode; - - uint32 time; - - union - { - struct - { - uchar channel; - uchar note; - uchar velocity; - } - noteOff; - - struct - { - uchar channel; - uchar note; - uchar velocity; - } - noteOn; - - struct - { - uchar channel; - uchar note; - uchar pressure; - } - keyPressure; - - struct - { - uchar channel; - uchar controlNumber; - uchar controlValue; - } - controlChange; - - struct - { - uchar channel; - uchar programNumber; - } - programChange; - - struct - { - uchar channel; - uchar pressure; - } - channelPressure; - - struct - { - uchar channel; - uchar lsb; - uchar msb; - } - pitchBend; - - struct - { - uint8* data; - size_t dataLength; - } - systemExclusive; - - struct - { - uchar status; - uchar data1; - uchar data2; - } - systemCommon; - - struct - { - uchar status; - } - systemRealTime; - - struct - { - uint32 beatsPerMinute; - } - tempoChange; - - struct - { - bool justChannel; - } - allNotesOff; - }; -}; - -#endif _MIDI_EVENT_H - diff --git a/src/kits/midi/MidiGlue.cpp b/src/kits/midi/MidiGlue.cpp new file mode 100644 index 0000000000..daffd9b2a9 --- /dev/null +++ b/src/kits/midi/MidiGlue.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2003 Matthijs Hollemans + * Copyright (c) 2002 Jerome Leveque + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Midi.h" +#include "MidiGlue.h" +#include "MidiPort.h" + +//------------------------------------------------------------------------------ + +BMidiGlue::BMidiGlue(BMidi* midiObject_, const char* name) + : BMidiLocalConsumer(name) +{ + midiObject = midiObject_; +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::NoteOff( + uchar channel, uchar note, uchar velocity, bigtime_t time) +{ + midiObject->NoteOff(channel + 1, note, velocity, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::NoteOn( + uchar channel, uchar note, uchar velocity, bigtime_t time) +{ + midiObject->NoteOn(channel + 1, note, velocity, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::KeyPressure( + uchar channel, uchar note, uchar pressure, bigtime_t time) +{ + midiObject->KeyPressure(channel + 1, note, pressure, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time) +{ + midiObject->ControlChange( + channel + 1, controlNumber, controlValue, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::ProgramChange( + uchar channel, uchar programNumber, bigtime_t time) +{ + midiObject->ProgramChange(channel + 1, programNumber, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::ChannelPressure( + uchar channel, uchar pressure, bigtime_t time) +{ + midiObject->ChannelPressure(channel + 1, pressure, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::PitchBend( + uchar channel, uchar lsb, uchar msb, bigtime_t time) +{ + midiObject->PitchBend(channel + 1, lsb, msb, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::SystemExclusive( + void* data, size_t length, bigtime_t time) +{ + midiObject->SystemExclusive(data, length, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::SystemCommon( + uchar status, uchar data1, uchar data2, bigtime_t time) +{ + midiObject->SystemCommon(status, data1, data2, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::SystemRealTime(uchar status, bigtime_t time) +{ + midiObject->SystemRealTime(status, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiGlue::TempoChange(int32 beatsPerMinute, bigtime_t time) +{ + midiObject->TempoChange(beatsPerMinute, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +BMidiPortGlue::BMidiPortGlue(BMidiPort* midiObject_, const char* name) + : BMidiLocalConsumer(name) +{ + midiObject = midiObject_; +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::NoteOff( + uchar channel, uchar note, uchar velocity, bigtime_t time) +{ + midiObject->SprayNoteOff(channel + 1, note, velocity, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::NoteOn( + uchar channel, uchar note, uchar velocity, bigtime_t time) +{ + midiObject->SprayNoteOn(channel + 1, note, velocity, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::KeyPressure( + uchar channel, uchar note, uchar pressure, bigtime_t time) +{ + midiObject->SprayKeyPressure( + channel + 1, note, pressure, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time) +{ + midiObject->SprayControlChange( + channel + 1, controlNumber, controlValue, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::ProgramChange( + uchar channel, uchar programNumber, bigtime_t time) +{ + midiObject->SprayProgramChange( + channel + 1, programNumber, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::ChannelPressure( + uchar channel, uchar pressure, bigtime_t time) +{ + midiObject->SprayChannelPressure(channel + 1, pressure, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::PitchBend( + uchar channel, uchar lsb, uchar msb, bigtime_t time) +{ + midiObject->SprayPitchBend(channel + 1, lsb, msb, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::SystemExclusive( + void* data, size_t length, bigtime_t time) +{ + midiObject->SpraySystemExclusive(data, length, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::SystemCommon( + uchar status, uchar data1, uchar data2, bigtime_t time) +{ + midiObject->SpraySystemCommon(status, data1, data2, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::SystemRealTime(uchar status, bigtime_t time) +{ + midiObject->SpraySystemRealTime(status, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ + +void BMidiPortGlue::TempoChange(int32 beatsPerMinute, bigtime_t time) +{ + midiObject->SprayTempoChange(beatsPerMinute, MAKE_TIME(time)); +} + +//------------------------------------------------------------------------------ diff --git a/src/kits/midi/MidiGlue.h b/src/kits/midi/MidiGlue.h new file mode 100644 index 0000000000..c8b8b055db --- /dev/null +++ b/src/kits/midi/MidiGlue.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2003 Matthijs Hollemans + * Copyright (c) 2002 Jerome Leveque + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _MIDI_GLUE_H +#define _MIDI_GLUE_H + +#include + +#define MAKE_TIME(t) (t / (bigtime_t)1000) +#define MAKE_BIGTIME(t) (t * (bigtime_t)1000) + +class BMidiGlue: public BMidiLocalConsumer +{ +public: + + BMidiGlue(BMidi* midiObject, const char* name = NULL); + + virtual void NoteOff( + uchar channel, uchar note, uchar velocity, bigtime_t time); + + virtual void NoteOn( + uchar channel, uchar note, uchar velocity, bigtime_t time); + + virtual void KeyPressure( + uchar channel, uchar note, uchar pressure, bigtime_t time); + + virtual void ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, + bigtime_t time); + + virtual void ProgramChange( + uchar channel, uchar programNumber, bigtime_t time); + + virtual void ChannelPressure( + uchar channel, uchar pressure, bigtime_t time); + + virtual void PitchBend( + uchar channel, uchar lsb, uchar msb, bigtime_t time); + + virtual void SystemExclusive( + void* data, size_t length, bigtime_t time); + + virtual void SystemCommon( + uchar status, uchar data1, uchar data2, bigtime_t time); + + virtual void SystemRealTime(uchar status, bigtime_t time); + + virtual void TempoChange(int32 beatsPerMinute, bigtime_t time); + +private: + + BMidi* midiObject; +}; + +class BMidiPortGlue: public BMidiLocalConsumer +{ +public: + + BMidiPortGlue(BMidiPort* midiObject, const char* name = NULL); + + virtual void NoteOff( + uchar channel, uchar note, uchar velocity, bigtime_t time); + + virtual void NoteOn( + uchar channel, uchar note, uchar velocity, bigtime_t time); + + virtual void KeyPressure( + uchar channel, uchar note, uchar pressure, bigtime_t time); + + virtual void ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, + bigtime_t time); + + virtual void ProgramChange( + uchar channel, uchar programNumber, bigtime_t time); + + virtual void ChannelPressure( + uchar channel, uchar pressure, bigtime_t time); + + virtual void PitchBend( + uchar channel, uchar lsb, uchar msb, bigtime_t time); + + virtual void SystemExclusive( + void* data, size_t length, bigtime_t time); + + virtual void SystemCommon( + uchar status, uchar data1, uchar data2, bigtime_t time); + + virtual void SystemRealTime(uchar status, bigtime_t time); + + virtual void TempoChange(int32 beatsPerMinute, bigtime_t time); + +private: + + BMidiPort* midiObject; +}; + +#endif // _MIDI_GLUE_H diff --git a/src/kits/midi/MidiPort.cpp b/src/kits/midi/MidiPort.cpp index 718eb8b651..cd011a2a47 100644 --- a/src/kits/midi/MidiPort.cpp +++ b/src/kits/midi/MidiPort.cpp @@ -1,43 +1,54 @@ -/** - * @file MidiPort.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans + * Copyright (c) 2002 Jerome Leveque * - * @author Jerome Leveque - * @author Matthijs Hollemans + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ +#include +#include +#include + #include "debug.h" #include "MidiPort.h" - -//------------------------------------------------------------------------------ - -#include "MidiPortConsumer.h" - -//------------------------------------------------------------------------------ - -#include -#include - -#include +#include "MidiGlue.h" //------------------------------------------------------------------------------ BMidiPort::BMidiPort(const char* name) - : BMidi(), - remote_source(NULL), - remote_sink(NULL), - fName(NULL), - fCStatus(B_ERROR), - _fDevices(new BList) { - local_source = new BMidiLocalProducer("MidiPortGlue(out)"); - if (local_source != NULL) - local_source->Register(); - local_sink = new BMidiPortConsumer(this, "MidiPortGlue(in)"); - if (local_sink != NULL) - local_sink->Register(); + portName = NULL; + devices = new BList; + status = B_ERROR; + + localSource = new BMidiLocalProducer("MidiPortGlue(out)"); + localSink = new BMidiPortGlue(this, "MidiPortGlue(in)"); + + remoteSource = NULL; + remoteSink = NULL; ScanDevices(); - Open(name); + + if (name != NULL) + { + Open(name); + } } //------------------------------------------------------------------------------ @@ -45,86 +56,92 @@ BMidiPort::BMidiPort(const char* name) BMidiPort::~BMidiPort() { Close(); - delete fName; - delete _fDevices; - if (local_source) - local_source->Release(); - if (local_sink) - local_sink->Release(); + + EmptyDeviceList(); + delete devices; + + localSource->Release(); + localSink->Release(); } //------------------------------------------------------------------------------ status_t BMidiPort::InitCheck() const { -return fCStatus; + return status; } //------------------------------------------------------------------------------ status_t BMidiPort::Open(const char* name) { - if (name == NULL) - return fCStatus = B_ERROR; + status = B_ERROR; - Close(); - -int32 id = 0; - BMidiRoster *roster = BMidiRoster::MidiRoster(); - if (roster == NULL) - return fCStatus = B_ERROR; - BMidiEndpoint *endpt = NULL; - while ((endpt = roster->NextEndpoint(&id)) != NULL) + if (name != NULL) { - if (strcmp(endpt->Name(), name) == 0) - {//An endpoint have the same name as we want - delete fName; - fName = new char[strlen(name)]; - if (fName != NULL) - strcpy(fName, name); - //Can an Endpoint be Consumer AND Producer? - if (endpt->IsProducer()) + Close(); + + for (int32 t = 0; t < devices->CountItems(); ++t) + { + BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(t); + if (strcmp(name, endp->Name()) == 0) { - remote_source = (BMidiProducer*)endpt; -// endpt->Acquire(); //Because we always call Release() - } - if (endpt->IsConsumer()) - { - remote_sink = (BMidiConsumer*)endpt; -// endpt->Acquire();//Because we always call Release() - if (local_source != NULL) - local_source->Connect(remote_sink); + if (endp->IsValid()) // still exists? + { + if (endp->IsProducer()) + { + if (remoteSource == NULL) + { + remoteSource = (BMidiProducer*) endp; + } + } + else if (endp->IsConsumer()) + { + if (remoteSink == NULL) + { + remoteSink = (BMidiConsumer*) endp; + localSource->Connect(remoteSink); + } + } + } } } - else + + if (remoteSource != NULL) { - endpt->Release(); + portName = strdup(remoteSource->Name()); + status = B_OK; + } + else if (remoteSink != NULL) + { + portName = strdup(remoteSink->Name()); + status = B_OK; } } -return fCStatus = B_OK; + + return status; } //------------------------------------------------------------------------------ void BMidiPort::Close() { - if (remote_source != NULL) + if (remoteSource != NULL) { - if (local_sink != NULL) - { - remote_source->Disconnect(local_sink); - } - remote_source->Release(); - remote_source = NULL; + remoteSource->Disconnect(localSink); + remoteSource = NULL; } - if (remote_sink != NULL) + + if (remoteSink != NULL) { - if (local_source != NULL) - { - local_source->Disconnect(remote_sink); - } - remote_sink->Release(); - remote_sink = NULL; + localSource->Disconnect(remoteSink); + remoteSink = NULL; + } + + if (portName != NULL) + { + free(portName); + portName = NULL; } } @@ -132,7 +149,7 @@ void BMidiPort::Close() const char* BMidiPort::PortName() const { -return fName; + return portName; } //------------------------------------------------------------------------------ @@ -140,7 +157,7 @@ return fName; void BMidiPort::NoteOff( uchar channel, uchar note, uchar velocity, uint32 time) { - local_source->SprayNoteOff(channel, note, velocity, time); + localSource->SprayNoteOff(channel - 1, note, velocity, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ @@ -148,7 +165,7 @@ void BMidiPort::NoteOff( void BMidiPort::NoteOn( uchar channel, uchar note, uchar velocity, uint32 time) { - local_source->SprayNoteOn(channel, note, velocity, time); + localSource->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ @@ -156,7 +173,8 @@ void BMidiPort::NoteOn( void BMidiPort::KeyPressure( uchar channel, uchar note, uchar pressure, uint32 time) { - local_source->SprayKeyPressure(channel, note, pressure, 0); + localSource->SprayKeyPressure( + channel - 1, note, pressure, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ @@ -164,7 +182,8 @@ void BMidiPort::KeyPressure( void BMidiPort::ControlChange( uchar channel, uchar controlNumber, uchar controlValue, uint32 time) { - local_source->SprayControlChange(channel, controlNumber, controlValue, 0); + localSource->SprayControlChange( + channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ @@ -172,28 +191,30 @@ void BMidiPort::ControlChange( void BMidiPort::ProgramChange( uchar channel, uchar programNumber, uint32 time) { - local_source->SprayProgramChange(channel, programNumber, 0); + localSource->SprayProgramChange( + channel - 1, programNumber, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ void BMidiPort::ChannelPressure(uchar channel, uchar pressure, uint32 time) { - local_source->SprayChannelPressure(channel, pressure, 0); + localSource->SprayChannelPressure( + channel - 1, pressure, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ void BMidiPort::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) { - local_source->SprayPitchBend(channel, lsb, msb, 0); + localSource->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ -void BMidiPort::SystemExclusive(void* data, size_t dataLength, uint32 time) +void BMidiPort::SystemExclusive(void* data, size_t length, uint32 time) { - local_source->SpraySystemExclusive(data, dataLength, 0); + localSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ @@ -201,63 +222,67 @@ void BMidiPort::SystemExclusive(void* data, size_t dataLength, uint32 time) void BMidiPort::SystemCommon( uchar status, uchar data1, uchar data2, uint32 time) { - local_source->SpraySystemCommon(status, data1, data2, 0); + localSource->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ void BMidiPort::SystemRealTime(uchar status, uint32 time) { - local_source->SpraySystemRealTime(status, 0); + localSource->SpraySystemRealTime(status, MAKE_BIGTIME(time)); } //------------------------------------------------------------------------------ status_t BMidiPort::Start() { - if ((local_sink != NULL) && (remote_source != NULL)) - if ((fCStatus = remote_source->Connect(local_sink)) != B_OK) - return fCStatus; - else - { - return BMidi::Start(); - } - else - return fCStatus = B_ERROR; + status_t err = super::Start(); + + if ((err == B_OK) && (remoteSource != NULL)) + { + return remoteSource->Connect(localSink); + } + + return err; } //------------------------------------------------------------------------------ void BMidiPort::Stop() { - if ((remote_source != NULL) && (local_sink != NULL)) + if (remoteSource != NULL) { - remote_source->Disconnect(local_sink); + remoteSource->Disconnect(localSink); } - BMidi::Stop(); + + super::Stop(); } //------------------------------------------------------------------------------ int32 BMidiPort::CountDevices() { -return _fDevices->CountItems(); + return devices->CountItems(); } //------------------------------------------------------------------------------ status_t BMidiPort::GetDeviceName(int32 n, char* name, size_t bufSize) { -BMidiEndpoint *endpt = (BMidiEndpoint*)_fDevices->ItemAt(n); - if (endpt == NULL) + BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(n); + if (endp == NULL) + { return B_BAD_VALUE; - size_t size = strlen(endpt->Name()); - if (size > bufSize) + } + + size_t size = strlen(endp->Name()); + if (size >= bufSize) + { return B_NAME_TOO_LONG; - if (strlen(strcpy(name, endpt->Name())) == size) - return B_OK; - else - return B_ERROR; + } + + strcpy(name, endp->Name()); + return B_OK; } //------------------------------------------------------------------------------ @@ -270,33 +295,58 @@ void BMidiPort::_ReservedMidiPort3() { } void BMidiPort::Run() { - while(KeepRunning()) + while (KeepRunning()) + { snooze(50000); + } } //------------------------------------------------------------------------------ void BMidiPort::ScanDevices() { -int32 id = 0; - BMidiRoster *roster = BMidiRoster::MidiRoster(); - if (roster == NULL) - return; - BMidiEndpoint *endpt = NULL; - while ((endpt = roster->NextEndpoint(&id)) != NULL) + EmptyDeviceList(); + + int32 id = 0; + BMidiEndpoint* endp; + + while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL) { - bool additem = true; - for (int32 i = 0; i < _fDevices->CountItems(); i++) + // Each hardware port has two endpoints associated with it, a consumer + // and a producer. Both have the same name, so we add only one of them. + + bool addItem = true; + for (int32 t = 0; t < devices->CountItems(); ++t) { - BMidiEndpoint *endpoint = (BMidiEndpoint*)_fDevices->ItemAt(i); - if (strcmp(endpt->Name(), endpoint->Name()) == 0) - additem = false; + BMidiEndpoint* other = (BMidiEndpoint*) devices->ItemAt(t); + if (strcmp(endp->Name(), other->Name()) == 0) + { + addItem = false; + break; + } + } + + if (addItem) + { + devices->AddItem(endp); + } + else + { + endp->Release(); } - if (additem) - _fDevices->AddItem(endpt); - endpt->Release(); } } //------------------------------------------------------------------------------ +void BMidiPort::EmptyDeviceList() +{ + for (int32 t = 0; t < devices->CountItems(); ++t) + { + ((BMidiEndpoint*) devices->ItemAt(t))->Release(); + } + + devices->MakeEmpty(); +} + +//------------------------------------------------------------------------------ diff --git a/src/kits/midi/MidiPortConsumer.cpp b/src/kits/midi/MidiPortConsumer.cpp deleted file mode 100644 index 8f181f62b3..0000000000 --- a/src/kits/midi/MidiPortConsumer.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file MidiPort.cpp - * - * @author Jerome Leveque - */ - -//---------------------------------------- - -#include "MidiPortConsumer.h" - -//---------------------------------------- - -BMidiPortConsumer::BMidiPortConsumer(BMidiPort *toPort, const char *name = NULL) - : BMidiLocalConsumer(name), port(toPort) -{ -} - -//----------------- - -void BMidiPortConsumer::NoteOff(uchar channel, uchar note, uchar velocity, bigtime_t time) -{ - port->SprayNoteOff(channel, note, velocity, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::NoteOn(uchar channel, uchar note, uchar velocity, bigtime_t time) -{ - port->SprayNoteOn(channel, note, velocity, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::KeyPressure(uchar channel, uchar note, uchar pressure, bigtime_t time) -{ - port->SprayKeyPressure(channel, note, pressure, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::ControlChange(uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time) -{ - port->SprayControlChange(channel, controlNumber, controlValue, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::ProgramChange(uchar channel, uchar programNumber, bigtime_t time) -{ - port->SprayProgramChange(channel, programNumber, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::ChannelPressure(uchar channel, uchar pressure, bigtime_t time) -{ - port->SprayChannelPressure(channel, pressure, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::PitchBend(uchar channel, uchar lsb, uchar msb, bigtime_t time) -{ - port->SprayPitchBend(channel, lsb, msb, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::SystemExclusive(void *data, size_t dataLength, bigtime_t time) -{ - port->SpraySystemExclusive(data, dataLength, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::SystemCommon(uchar statusByte, uchar data1, uchar data2, bigtime_t time) -{ - port->SpraySystemCommon(statusByte, data1, data2, B_NOW); -} - -//----------------- - -void BMidiPortConsumer::SystemRealTime(uchar statusByte, bigtime_t time) -{ - port->SpraySystemRealTime(statusByte, B_NOW); -} - -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- -//---------------------------------------- diff --git a/src/kits/midi/MidiPortConsumer.h b/src/kits/midi/MidiPortConsumer.h deleted file mode 100644 index 45b094e549..0000000000 --- a/src/kits/midi/MidiPortConsumer.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file MidiPort.h - * - * @author Jerome Leveque - */ - -//---------------------------------------- - -#ifndef _MIDI_PORT_CONSUMER_H -#define _MIDI_PORT_CONSUMER_H - -#include -#include - -//---------------------------------------- - -class BMidiPortConsumer : public BMidiLocalConsumer -{ -public: - BMidiPortConsumer(BMidiPort *toPort, const char *name = NULL); - - void NoteOff(uchar channel, uchar note, uchar velocity, bigtime_t time); - void NoteOn(uchar channel, uchar note, uchar velocity, bigtime_t time); - void KeyPressure(uchar channel, uchar note, uchar pressure, bigtime_t time); - void ControlChange(uchar channel, uchar controlNumber, - uchar controlValue, bigtime_t time); - void ProgramChange(uchar channel, uchar programNumber, bigtime_t time); - void ChannelPressure(uchar channel, uchar pressure, bigtime_t time); - void PitchBend(uchar channel, uchar lsb, uchar msb, bigtime_t time); - void SystemExclusive(void *data, size_t dataLength, bigtime_t time); - void SystemCommon(uchar statusByte, uchar data1, - uchar data2, bigtime_t time); - void SystemRealTime(uchar statusByte, bigtime_t time); - -private: - BMidiPort *port; - -}; - -//---------------------------------------- - -#endif _MIDI_PORT_CONSUMER_H diff --git a/src/kits/midi/MidiStore.cpp b/src/kits/midi/MidiStore.cpp index 83b9cc0a89..c6ce4a5c23 100644 --- a/src/kits/midi/MidiStore.cpp +++ b/src/kits/midi/MidiStore.cpp @@ -1,900 +1,739 @@ -#include "MidiStore.h" -#include "MidiEvent.h" +/* + * Copyright (c) 2002-2003 Matthijs Hollemans + * Copyright (c) 2002 Jerome Leveque + * Copyright (c) 2002 Paul Stadler + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ #include -#include //For strcmp(...) -#include //For printf(...) -#include #include +#include +#include -//----------------------------------------------- +#include "MidiDefs.h" +#include "MidiStore.h" +#include "debug.h" -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- +//------------------------------------------------------------------------------ -int CompareEvents(const void* event1, const void* event2) +struct BMidiEvent { - return ((BMidiEvent*)event1)->time - ((BMidiEvent*)event2)->time; + BMidiEvent() + { + byte1 = 0; + byte2 = 0; + byte3 = 0; + data = NULL; + length = 0; + } + + ~BMidiEvent() + { + free(data); + } + + uint32 time; // either ticks or milliseconds + bool ticks; // event is from MIDI file + uchar byte1; + uchar byte2; + uchar byte3; + void* data; // sysex data + size_t length; // sysex data size + int32 tempo; // beats per minute +}; + +//------------------------------------------------------------------------------ + +static int compare_events(const void* event1, const void* event2) +{ + BMidiEvent* e1 = *((BMidiEvent**) event1); + BMidiEvent* e2 = *((BMidiEvent**) event2); + + return (e1->time - e2->time); } -//----------------------------------------------- +//------------------------------------------------------------------------------ BMidiStore::BMidiStore() { - events = new BList(); - fFile = NULL; - fFileBuffer = NULL; - fFileBufferMax = 0; - fNeedsSorting = false; - fDivision = 480; - fNumTracks = 1; - fStartTime = 0; - fCurrEvent = 0; + events = new BList; + currentEvent = 0; + startTime = 0; + needsSorting = false; + beatsPerMinute = 60; + ticksPerBeat = 240; + file = NULL; } -//----------------------------------------------- +//------------------------------------------------------------------------------ BMidiStore::~BMidiStore() { - int32 count = events->CountItems(); - for (int i = count - 1; i >= 0; i--) + for (int32 t = 0; t < events->CountItems(); ++t) { - delete (BMidiEvent*) events->RemoveItem(i); + delete EventAt(t); } delete events; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) +void BMidiStore::NoteOff( + uchar channel, uchar note, uchar velocity, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_NOTE_OFF, chan, note, vel); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_NOTE_OFF | (channel - 1); + event->byte2 = note; + event->byte3 = velocity; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) +void BMidiStore::NoteOn( + uchar channel, uchar note, uchar velocity, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_NOTE_ON, chan, note, vel); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_NOTE_ON | (channel - 1); + event->byte2 = note; + event->byte3 = velocity; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time) +void BMidiStore::KeyPressure( + uchar channel, uchar note, uchar pressure, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_KEY_PRESSURE, chan, note, pres); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_KEY_PRESSURE | (channel - 1); + event->byte2 = note; + event->byte3 = pressure; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, uint32 time) +void BMidiStore::ControlChange( + uchar channel, uchar controlNumber, uchar controlValue, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_CONTROL_CHANGE, chan, ctrl_num, ctrl_val); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_CONTROL_CHANGE | (channel - 1); + event->byte2 = controlNumber; + event->byte3 = controlValue; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::ProgramChange(uchar chan, uchar prog_num, uint32 time) +void BMidiStore::ProgramChange( + uchar channel, uchar programNumber, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_PROGRAM_CHANGE, chan, prog_num); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_PROGRAM_CHANGE | (channel - 1); + event->byte2 = programNumber; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::ChannelPressure(uchar chan, uchar pres, uint32 time) +void BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_CHANNEL_PRESSURE, chan, pres); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_CHANNEL_PRESSURE | (channel - 1); + event->byte2 = pressure; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) +void BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_PITCH_BEND, chan, lsb, msb); -} -//----------------------------------------------- - -void BMidiStore::SystemExclusive(void *data, size_t data_len, uint32 time) -{ - BMidiEvent *e = new BMidiEvent; - e->opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE; - e->time = time; - e->systemExclusive.data = new uint8[data_len]; - memcpy(e->systemExclusive.data, data, data_len); - e->systemExclusive.dataLength = data_len; - AddSystemExclusive(e, sizeof(BMidiEvent)); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_PITCH_BEND | (channel - 1); + event->byte2 = lsb; + event->byte3 = msb; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::SystemCommon(uchar stat_byte, uchar data1, uchar data2, uint32 time) +void BMidiStore::SystemExclusive(void* data, size_t length, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_SYSTEM_COMMON, stat_byte, data1, data2); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = B_SYS_EX_START; + event->data = malloc(length); + event->length = length; + memcpy(event->data, data, length); + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::SystemRealTime(uchar stat_byte, uint32 time) +void BMidiStore::SystemCommon( + uchar status, uchar data1, uchar data2, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_SYSTEM_REAL_TIME, stat_byte); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = status; + event->byte2 = data1; + event->byte3 = data2; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::TempoChange(int32 bpm, uint32 time) +void BMidiStore::SystemRealTime(uchar status, uint32 time) { - AddEvent(time, true, BMidiEvent::OP_TEMPO_CHANGE, bpm); + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = status; + AddEvent(event); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -status_t BMidiStore::Import(const entry_ref *ref) -{//ToTest -status_t status = B_NO_ERROR; +void BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time) +{ + BMidiEvent* event = new BMidiEvent; + event->time = time; + event->ticks = false; + event->byte1 = 0xFF; + event->byte2 = 0x51; + event->byte3 = 0x03; + event->tempo = beatsPerMinute; + AddEvent(event); +} - fFile = new BFile(ref, B_READ_ONLY); +//------------------------------------------------------------------------------ - status = fFile->InitCheck(); - if (status != B_OK) +status_t BMidiStore::Import(const entry_ref* ref) +{ + try { - delete fFile; - return status; - } - - status = ReadHeader(); - if (status != B_OK) - { - delete fFile; - return status; - } - - Read16Bit(); //Format of the MidiFile - fNumTracks = Read16Bit(); - fDivision = Read16Bit(); - fDivisionFactor = 1 / fDivision; - - status = B_OK; - for(fCurrTrack = 0; fCurrTrack < fNumTracks; fCurrTrack++) - { - char mtrk[4]; - if (ReadMT(mtrk) == false) + file = new BFile(ref, B_READ_ONLY); + if (file->InitCheck() != B_OK) { - PRINT(("Error while reading MTrk\n")); - status = B_BAD_MIDI_DATA; - break; + throw file->InitCheck(); } - PRINT(("Printing Track %ld\n", fCurrTrack)); - fFileBufferSize = Read32Bit(); - if (fFileBufferSize > fFileBufferMax) + char fourcc[4]; + ReadFourCC(fourcc); + if (strncmp(fourcc, "MThd", 4) != 0) { - fFileBufferMax = fFileBufferSize; - delete fFileBuffer; - fFileBuffer = new uchar[fFileBufferSize]; + throw (status_t) B_BAD_MIDI_DATA; } - if (ReadTrack() == false) + + if (Read32Bit() != 6) { - PRINT(("Error while reading Trak %ld\n", fCurrTrack)); - status = B_BAD_MIDI_DATA; - break; + throw (status_t) B_BAD_MIDI_DATA; + } + + format = Read16Bit(); + numTracks = Read16Bit(); + ticksPerBeat = Read16Bit(); + + if (ticksPerBeat & 0x8000) // we don't support SMPTE + { // time codes, only ticks + ticksPerBeat = 240; // per quarter note + } + + currTrack = 0; + while (currTrack < numTracks) + { + ReadChunk(); } } - - delete fFile; - delete fFileBuffer; - fFileBuffer = NULL; - SortEvents(true); -return status; -} - -//----------------------------------------------- - -status_t BMidiStore::Export(const entry_ref *ref, int32 format) -{//ToDo - fFile = new BFile(ref, B_READ_WRITE); - status_t status = fFile->InitCheck(); - if (status != B_OK) + catch (status_t e) { - delete fFile; - return status; + delete file; + file = NULL; + return e; } SortEvents(true); - WriteHeaderChunk(format); -off_t position_of_length = 0; - - if (format == 0) - {//Format is 0 just one track - position_of_length = fFile->Position() + 4; - WriteTrack(-1); - fFile->Seek(position_of_length, SEEK_SET); - Write32Bit(fNumBytesWritten); - fFile->Seek(0, SEEK_END); - } - - if (format == 1) - {//Format is 1, number of track is fNumTracks initialized when import file - for (int32 i = 0; i < fNumTracks; i++) - { - position_of_length = fFile->Position() + 4; - WriteTrack(i); - fFile->Seek(position_of_length, SEEK_SET); - Write32Bit(fNumBytesWritten); - fFile->Seek(0, SEEK_END); - } - } - -return B_OK; + delete file; + file = NULL; + return B_OK; } -//----------------------------------------------- +//------------------------------------------------------------------------------ + +status_t BMidiStore::Export(const entry_ref* ref, int32 format) +{ + try + { + file = new BFile(ref, B_READ_WRITE); + if (file->InitCheck() != B_OK) + { + throw file->InitCheck(); + } + + SortEvents(true); + + WriteFourCC('M', 'T', 'h', 'd'); + Write32Bit(6); + Write16Bit(0); // we do only format 0 + Write16Bit(1); + Write16Bit(ticksPerBeat); + + WriteTrack(); + } + catch (status_t e) + { + delete file; + file = NULL; + return e; + } + + delete file; + file = NULL; + return B_OK; +} + +//------------------------------------------------------------------------------ void BMidiStore::SortEvents(bool force) { - events->SortItems(CompareEvents); + if (force || needsSorting) + { + events->SortItems(compare_events); + needsSorting = false; + } } -//----------------------------------------------- +//------------------------------------------------------------------------------ uint32 BMidiStore::CountEvents() const -{//ToTest -return events->CountItems(); +{ + return events->CountItems(); } -//----------------------------------------------- +//------------------------------------------------------------------------------ uint32 BMidiStore::CurrentEvent() const -{//ToTest - return fCurrEvent; +{ + return currentEvent; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::SetCurrentEvent(uint32 event_num) -{//ToTest - fCurrEvent = event_num; +void BMidiStore::SetCurrentEvent(uint32 eventNumber) +{ + currentEvent = eventNumber; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -uint32 BMidiStore::DeltaOfEvent(uint32 event_num) const -{//ToDo -return 0; +uint32 BMidiStore::DeltaOfEvent(uint32 eventNumber) const +{ + // Even though the BeBook says that the delta is the time span between + // an event and the first event in the list, this doesn't appear to be + // true for events that were captured from other BMidi objects such as + // BMidiPort. For those events, we return the absolute timestamp. The + // BeBook is correct for events from MIDI files, though. + + BMidiEvent* event = EventAt(eventNumber); + if (event != NULL) + { + return GetEventTime(event); + } + + return 0; } -//----------------------------------------------- +//------------------------------------------------------------------------------ uint32 BMidiStore::EventAtDelta(uint32 time) const -{//ToDo -return 0; +{ + for (int32 t = 0; t < events->CountItems(); ++t) + { + if (GetEventTime(EventAt(t)) >= time) { return t; } + } + + return 0; } -//----------------------------------------------- +//------------------------------------------------------------------------------ uint32 BMidiStore::BeginTime() const -{//ToTest - return fStartTime; +{ + return startTime; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::SetTempo(int32 bpm) -{//ToTest - fTempo = bpm; +void BMidiStore::SetTempo(int32 beatsPerMinute_) +{ + beatsPerMinute = beatsPerMinute_; } -//----------------------------------------------- +//------------------------------------------------------------------------------ int32 BMidiStore::Tempo() const -{//ToTest - return fTempo; +{ + return beatsPerMinute; } -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- +//------------------------------------------------------------------------------ + +void BMidiStore::_ReservedMidiStore1() { } +void BMidiStore::_ReservedMidiStore2() { } +void BMidiStore::_ReservedMidiStore3() { } + +//------------------------------------------------------------------------------ void BMidiStore::Run() { - fStartTime = B_NOW; - SortEvents(true); + int32 timeAdjust; + bool firstEvent = true; + while (KeepRunning()) { - BMidiEvent* event = (BMidiEvent*)events->ItemAt(fCurrEvent); + BMidiEvent* event = EventAt(currentEvent); + if (event == NULL) { return; } - if (event == NULL) return; + if (firstEvent) + { + startTime = B_NOW; + timeAdjust = startTime - GetEventTime(event); + SprayEvent(event, startTime); + firstEvent = false; + } + else + { + SprayEvent(event, GetEventTime(event) + timeAdjust); + } - printf("Curr Event : %ld, Time : %ld\n", fCurrEvent, event->time); - - fCurrTime = event->time; - event->time += fStartTime; -// SprayMidiEvent(event); - event->time = fCurrTime; - - fCurrEvent++; + ++currentEvent; } } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::AddEvent(uint32 time, bool inMS, uchar type, uchar data1 = 0, uchar data2 = 0, uchar data3 = 0, uchar data4 = 0) -{//ToTest - if (!inMS) +void BMidiStore::AddEvent(BMidiEvent* event) +{ + events->AddItem(event); + needsSorting = true; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time) +{ + uchar byte1 = event->byte1; + uchar byte2 = event->byte2; + uchar byte3 = event->byte3; + + switch (byte1 & 0xF0) { - time = TicksToMilliseconds(time); - } - BMidiEvent *e = new BMidiEvent(); - e->time = time; - switch (type) - { - case BMidiEvent::OP_NOTE_OFF : - e->opcode = BMidiEvent::OP_NOTE_OFF; - e->noteOff.channel = data1; - e->noteOff.note = data2; - e->noteOff.velocity = data3; - break; - case BMidiEvent::OP_NOTE_ON : - e->opcode = BMidiEvent::OP_NOTE_ON; - e->noteOn.channel = data1; - e->noteOn.note = data2; - e->noteOn.velocity = data3; - break; - case BMidiEvent::OP_KEY_PRESSURE : - e->opcode = BMidiEvent::OP_KEY_PRESSURE; - e->keyPressure.channel = data1; - e->keyPressure.note = data2; - e->keyPressure.pressure = data3; - break; - case BMidiEvent::OP_CONTROL_CHANGE : - e->opcode = BMidiEvent::OP_CONTROL_CHANGE; - e->controlChange.channel = data1; - e->controlChange.controlNumber = data2; - e->controlChange.controlValue = data3; - break; - case BMidiEvent::OP_PROGRAM_CHANGE : - e->opcode = BMidiEvent::OP_PROGRAM_CHANGE; - e->programChange.channel = data1; - e->programChange.programNumber = data2; - break; - case BMidiEvent::OP_CHANNEL_PRESSURE : - e->opcode = BMidiEvent::OP_CHANNEL_PRESSURE; - e->channelPressure.channel = data1; - e->channelPressure.pressure = data2; - break; - case BMidiEvent::OP_PITCH_BEND : - e->opcode = BMidiEvent::OP_PITCH_BEND; - e->pitchBend.channel = data1; - e->pitchBend.lsb = data2; - e->pitchBend.msb = data3; - break; - case BMidiEvent::OP_SYSTEM_COMMON : - e->opcode = BMidiEvent::OP_SYSTEM_COMMON; - e->systemCommon.status = data1; - e->systemCommon.data1 = data2; - e->systemCommon.data2 = data3; - break; - case BMidiEvent::OP_SYSTEM_REAL_TIME : - e->opcode = BMidiEvent::OP_SYSTEM_REAL_TIME; - e->systemRealTime.status = data1; - break; - case BMidiEvent::OP_TEMPO_CHANGE : - e->opcode = BMidiEvent::OP_TEMPO_CHANGE; - e->tempoChange.beatsPerMinute = data1; - break; - case BMidiEvent::OP_ALL_NOTES_OFF : - e->opcode = BMidiEvent::OP_ALL_NOTES_OFF; - e->allNotesOff.justChannel = data1; - break; - default : - delete e; + case B_NOTE_OFF: + SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time); + return; + + case B_NOTE_ON: + SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time); + return; + + case B_KEY_PRESSURE: + SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time); + return; + + case B_CONTROL_CHANGE: + SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time); + return; + + case B_PROGRAM_CHANGE: + SprayProgramChange((byte1 & 0x0F) + 1, byte2, time); + return; + + case B_CHANNEL_PRESSURE: + SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time); + return; + + case B_PITCH_BEND: + SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time); + return; + + case 0xF0: + switch (byte1) + { + case B_SYS_EX_START: + SpraySystemExclusive(event->data, event->length, time); + return; + + case B_MIDI_TIME_CODE: + case B_SONG_POSITION: + case B_SONG_SELECT: + case B_CABLE_MESSAGE: + case B_TUNE_REQUEST: + case B_SYS_EX_END: + SpraySystemCommon(byte1, byte2, byte3, time); + return; + + case B_TIMING_CLOCK: + case B_START: + case B_CONTINUE: + case B_STOP: + case B_ACTIVE_SENSING: + SpraySystemRealTime(byte1, time); + return; + + case B_SYSTEM_RESET: + if ((byte2 == 0x51) && (byte3 == 0x03)) + { + SprayTempoChange(event->tempo, time); + beatsPerMinute = event->tempo; + } + else + { + SpraySystemRealTime(byte1, time); + } + return; + } return; } - events->AddItem(e); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::AddSystemExclusive(void* data, size_t dataLength) -{//ToTest -// BMidiEvent *e = new BMidiEvent(); -// e->time = 0; -// e->systemExclusive.data = (uint8*)data; -// e->systemExclusive.dataLength = dataLength; - events->AddItem(data); +BMidiEvent* BMidiStore::EventAt(int32 index) const +{ + return (BMidiEvent*) events->ItemAt(index); } -//----------------------------------------------- +//------------------------------------------------------------------------------ -status_t BMidiStore::ReadHeader() -{//ToTest -char mthd[4]; - if (ReadMT(mthd) == false) - return B_ERROR; - if(strncmp(mthd, "MThd", 4) != 0) +uint32 BMidiStore::GetEventTime(const BMidiEvent* event) const +{ + if (event->ticks) { - return B_BAD_MIDI_DATA; + return TicksToMilliseconds(event->time); + } + else + { + return event->time; + } +} + +//------------------------------------------------------------------------------ + +uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const +{ + return ((uint64) ticks * 60000) / (beatsPerMinute * ticksPerBeat); +} + +//------------------------------------------------------------------------------ + +uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const +{ + return ((uint64) ms * beatsPerMinute * ticksPerBeat) / 60000; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::ReadFourCC(char* fourcc) +{ + if (file->Read(fourcc, 4) != 4) + { + throw (status_t) B_BAD_MIDI_DATA; + } +} + +//------------------------------------------------------------------------------ + +void BMidiStore::WriteFourCC(char a, char b, char c, char d) +{ + char fourcc[4] = { a, b, c, d }; + if (file->Write(fourcc, 4) != 4) + { + throw (status_t) B_ERROR; + } +} + +//------------------------------------------------------------------------------ + +uint32 BMidiStore::Read32Bit() +{ + uint8 buf[4]; + if (file->Read(buf, 4) != 4) + { + throw (status_t) B_BAD_MIDI_DATA; } -int32 length = Read32Bit(); - if (length != 6) + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::Write32Bit(uint32 val) +{ + uint8 buf[4]; + buf[0] = (val >> 24) & 0xFF; + buf[1] = (val >> 16) & 0xFF; + buf[2] = (val >> 8) & 0xFF; + buf[3] = val & 0xFF; + + if (file->Write(buf, 4) != 4) { - return B_BAD_MIDI_DATA; + throw (status_t) B_ERROR; } -return B_OK; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -bool BMidiStore::ReadMT(char *data) -{//ToTest - return fFile->Read(data, 4) == 4; -} - -//----------------------------------------------- - -int32 BMidiStore::Read32Bit() -{//ToTest -uchar char32bit[4]; - fFile->Read(char32bit, 4); -return To32Bit(char32bit[0], char32bit[1], char32bit[2], char32bit[3]); -} - -//----------------------------------------------- - -int32 BMidiStore::EGetC() -{//ToDo -return 0; -} - -//----------------------------------------------- - -int32 BMidiStore::To32Bit(int32 data1, int32 data2, int32 data3, int32 data4) -{//ToTest - return data1 << 24 | data2 << 16 | data3 << 8 | data4; -} - -//----------------------------------------------- - -int32 BMidiStore::Read16Bit() -{//ToTest -uchar char16bit[2]; - fFile->Read(char16bit, 2); -return To16Bit(char16bit[0], char16bit[1]); -} - -//----------------------------------------------- - -int32 BMidiStore::To16Bit(int32 data1, int32 data2) -{//ToTest - return (uint32)data1 << 8 | (uint32)data2; -} - -//----------------------------------------------- - -bool BMidiStore::ReadTrack() -{//ToTest - if (fFile->Read(fFileBuffer, fFileBufferSize) != fFileBufferSize) - return false; -fNeedsSorting = true; -fFileBufferIndex = 0; -uint32 ticks = 0; -uint32 time = 0; //in ms -uchar data = 0; -uint32 ForTempo = 0; -//fStartTime = 0; - while (fFileBufferIndex < (fFileBufferSize - 3)) +uint16 BMidiStore::Read16Bit() +{ + uint8 buf[2]; + if (file->Read(buf, 2) != 2) { - ticks += ReadVariNum(); - time = /*fStartTime + */TicksToMilliseconds(ticks); - uchar temp = fFileBuffer[fFileBufferIndex]; - if (temp > 0x7F) + throw (status_t) B_BAD_MIDI_DATA; + } + + return (buf[0] << 8) | buf[1]; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::Write16Bit(uint16 val) +{ + uint8 buf[2]; + buf[0] = (val >> 8) & 0xFF; + buf[1] = val & 0xFF; + + if (file->Write(buf, 2) != 2) + { + throw (status_t) B_ERROR; + } +} + +//------------------------------------------------------------------------------ + +uint8 BMidiStore::PeekByte() +{ + uint8 buf; + if (file->Read(&buf, 1) != 1) + { + throw (status_t) B_BAD_MIDI_DATA; + } + + if (file->Seek(-1, SEEK_CUR) < 0) + { + throw (status_t) B_ERROR; + } + + return buf; +} + +//------------------------------------------------------------------------------ + +uint8 BMidiStore::NextByte() +{ + uint8 buf; + if (file->Read(&buf, 1) != 1) + { + throw (status_t) B_BAD_MIDI_DATA; + } + + --byteCount; + return buf; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::WriteByte(uint8 val) +{ + if (file->Write(&val, 1) != 1) + { + throw (status_t) B_ERROR; + } + + ++byteCount; +} + +//------------------------------------------------------------------------------ + +void BMidiStore::SkipBytes(uint32 length) +{ + if (file->Seek(length, SEEK_CUR) < 0) + { + throw (status_t) B_BAD_MIDI_DATA; + } + + byteCount -= length; +} + +//------------------------------------------------------------------------------ + +uint32 BMidiStore::ReadVarLength() +{ + uint32 val; + uint8 byte; + + if ((val = NextByte()) & 0x80) + { + val &= 0x7F; + do { - data = temp; - fFileBufferIndex++; + val = (val << 7) + ((byte = NextByte()) & 0x7F); } - if (data < 0x80) - { - PRINT(("Big Problem, data : %d, Index : %ld\n", data, fFileBufferIndex)); - return false; - } - switch (data & 0xF0) - { - case B_NOTE_OFF : - NoteOff(data & 0x0F, fFileBuffer[fFileBufferIndex], - fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_NOTE_ON : - NoteOn(data & 0x0F, fFileBuffer[fFileBufferIndex], - fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_KEY_PRESSURE : - KeyPressure(data & 0x0F, fFileBuffer[fFileBufferIndex], - fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_CONTROL_CHANGE : - ControlChange(data & 0x0F, fFileBuffer[fFileBufferIndex], - fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_PITCH_BEND : - PitchBend(data & 0x0F, fFileBuffer[fFileBufferIndex], - fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_PROGRAM_CHANGE : - ProgramChange(data & 0x0F, fFileBuffer[fFileBufferIndex], time); - fFileBufferIndex += 2; - break; - case B_CHANNEL_PRESSURE : - ChannelPressure(data & 0x0F, fFileBuffer[fFileBufferIndex], time); - fFileBufferIndex += 1; - break; - } - switch (data) - { - case B_SYS_EX_START : - temp = MsgLength(); - SystemExclusive(&fFileBuffer[fFileBufferIndex - 1], temp + 2, time); - fFileBufferIndex += temp; - break; - case B_SONG_POSITION : - SystemCommon(data, fFileBuffer[fFileBufferIndex], fFileBuffer[fFileBufferIndex + 1], time); - fFileBufferIndex += 2; - break; - case B_MIDI_TIME_CODE : - case B_SONG_SELECT : - SystemCommon(data, fFileBuffer[fFileBufferIndex], 0, time); - fFileBufferIndex += 1; - break; - case B_TUNE_REQUEST : - case B_TIMING_CLOCK : - SystemCommon(data, 0, 0, time); - break; - case B_START : - case B_CONTINUE : - case B_STOP : - case B_ACTIVE_SENSING : - SystemRealTime(data, time); - break; - case B_SYSTEM_RESET : - temp = fFileBuffer[fFileBufferIndex]; - if (temp == 0x2F) - return true; - if (temp == 0x51) - {//Calcul of the tempo is wrong - fFileBufferIndex +=2; - ForTempo = fFileBuffer[fFileBufferIndex++] << 8; - ForTempo |= fFileBuffer[fFileBufferIndex++]; - ForTempo = (ForTempo << 8) | fFileBuffer[fFileBufferIndex++]; -// ForTempo /= 2500; - TempoChange(ForTempo, time); - } - else - { - temp = fFileBuffer[fFileBufferIndex + 1] + 3; - SystemExclusive(&fFileBuffer[fFileBufferIndex - 1], temp, time); - fFileBufferIndex += temp - 1; - } - break; - default : - if (data >= 0xF0) - printf("Midi Data not Defined\n"); - } - } -return true; -} - -//----------------------------------------------- - -int32 BMidiStore::ReadVariNum() -{//ToTest -int32 result = 0; -uchar tempo = 0; - while (fFileBufferIndex < fFileBufferSize) - { - tempo = fFileBuffer[fFileBufferIndex++]; - result |= tempo & 0x7F; - if ((tempo & 0x80) == 0) - return result; - result <<= 7; - } -return B_ERROR; -} - -//----------------------------------------------- - -void BMidiStore::ChannelMessage(int32, int32, int32) -{//ToDo - -} - -//----------------------------------------------- - -void BMidiStore::MsgInit() -{//ToDo - -} - -//----------------------------------------------- - -void BMidiStore::MsgAdd(int32) -{//ToDo - -} - -//----------------------------------------------- - -void BMidiStore::BiggerMsg() -{//ToDo - -} - -//----------------------------------------------- - -void BMidiStore::MetaEvent(int32) -{//ToDo - -} - -//----------------------------------------------- - -int32 BMidiStore::MsgLength() -{//ToTest -int32 t = 0; - while (fFileBuffer[fFileBufferIndex + t] != 0xF7) - { - if (fFileBufferIndex + t > fFileBufferSize - 3) - return -1; - else - t++; - } -return t; -} - -//----------------------------------------------- - -uchar *BMidiStore::Msg() -{//ToDo -return 0; -} - -//----------------------------------------------- - -void BMidiStore::BadByte(int32) -{//ToDo - -} - -//----------------------------------------------- - - -int32 BMidiStore::PutC(int32 c) -{//ToDo -return 0; -} - -//----------------------------------------------- - -bool BMidiStore::WriteTrack(int32 track) -{//ToTest -uchar temp[4] = {0x00, 0x00, 0x00, 0x00}; - WriteTrackChunk(track); - fNumBytesWritten = 0; -uint32 ticks = 0; -int32 i = 0; -// If track == -1 write all events -BMidiEvent *event = (BMidiEvent*)events->ItemAt(i++); - if (event != NULL) - fCurrTime = event->time; - while (event != NULL) - { - ticks = MillisecondsToTicks(event->time - fCurrTime); - switch(event->opcode) - { - case BMidiEvent::OP_NOTE_OFF : - if ((track == -1) || (track == event->noteOff.channel)) - { - temp[0] = event->noteOff.note; - temp[1] = event->noteOff.velocity; - WriteMidiEvent(ticks, B_NOTE_OFF, event->noteOff.channel, temp, 2); - } - break; - case BMidiEvent::OP_NOTE_ON : - if ((track == -1) || (track == event->noteOn.channel)) - { - temp[0] = event->noteOn.note; - temp[1] = event->noteOn.velocity; - WriteMidiEvent(ticks, B_NOTE_ON, event->noteOn.channel, temp, 2); - } - break; - case BMidiEvent::OP_KEY_PRESSURE : - if ((track == -1) || (track == event->keyPressure.channel)) - { - temp[0] = event->keyPressure.note; - temp[1] = event->keyPressure.pressure; - WriteMidiEvent(ticks, B_KEY_PRESSURE, event->keyPressure.channel, temp, 2); - } - break; - case BMidiEvent::OP_CONTROL_CHANGE : - if ((track == -1) || (track == event->controlChange.channel)) - { - temp[0] = event->controlChange.controlNumber; - temp[1] = event->controlChange.controlValue; - WriteMidiEvent(ticks, B_CONTROL_CHANGE, event->controlChange.channel, temp, 2); - } - break; - case BMidiEvent::OP_PROGRAM_CHANGE : - if ((track == -1) || (track == event->programChange.channel)) - { - temp[0] = event->programChange.programNumber; - WriteMidiEvent(ticks, B_PROGRAM_CHANGE, event->programChange.channel, temp, 1); - } - break; - case BMidiEvent::OP_CHANNEL_PRESSURE : - if ((track == -1) || (track == event->channelPressure.channel)) - { - temp[0] = event->channelPressure.pressure; - WriteMidiEvent(ticks, B_CHANNEL_PRESSURE, event->channelPressure.channel, temp, 1); - } - break; - case BMidiEvent::OP_PITCH_BEND : - if ((track == -1) || (track == event->pitchBend.channel)) - { - temp[0] = event->pitchBend.lsb; - temp[1] = event->pitchBend.msb; - WriteMidiEvent(ticks, B_PITCH_BEND, event->pitchBend.channel, temp, 2); - } - break; - case BMidiEvent::OP_SYSTEM_COMMON : - if ((track == -1) || (track == 0)) - { - temp[0] = event->systemCommon.data1; - temp[1] = event->systemCommon.data2; - WriteMetaEvent(ticks, event->systemCommon.status, temp, 2); - } - break; - case BMidiEvent::OP_SYSTEM_REAL_TIME : - if ((track == -1) || (track == 0)) - { - WriteMetaEvent(ticks, event->systemRealTime.status, temp, 0); - } - break; - case BMidiEvent::OP_SYSTEM_EXCLUSIVE : - if ((track == -1) || (track == 0)) - { - WriteSystemExclusiveEvent(ticks, event->systemExclusive.data, event->systemExclusive.dataLength); - } - break; - case BMidiEvent::OP_TEMPO_CHANGE : - if ((track == -1) || (track == 0)) - { - WriteTempo(ticks, event->tempoChange.beatsPerMinute); - } - break; -//Not used - case BMidiEvent::OP_NONE : - case BMidiEvent::OP_ALL_NOTES_OFF : - case BMidiEvent::OP_TRACK_END : - break; - } -// } - fCurrTime = event->time; - event = (BMidiEvent*)events->ItemAt(i++); + while (byte & 0x80); } - Write16Bit(0xFF2F); - EPutC(0); -return true; + return val; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::WriteTempoTrack() -{//ToDo -} +void BMidiStore::WriteVarLength(uint32 val) +{ + uint32 buffer = val & 0x7F; -//----------------------------------------------- - -bool BMidiStore::WriteTrackChunk(int32 whichTrack) -{//ToTest - Write32Bit('MTrk'); - Write32Bit(6); -return true; -} - -//----------------------------------------------- - -void BMidiStore::WriteHeaderChunk(int32 format) -{//ToTest - Write32Bit('MThd'); - Write32Bit(6); - Write16Bit(format); - if (format == 0) - fNumTracks = 1; - Write16Bit(fNumTracks); - Write16Bit(fDivision); -} - -//----------------------------------------------- - -bool BMidiStore::WriteMidiEvent(uint32 deltaTime, uint32 type, uint32 channel, uchar* data, uint32 size) -{//ToTest - WriteVarLen(deltaTime); - if (EPutC(type | channel) != 1) - return false; - while (size > 0) - { - if (EPutC(*data) != 1) - return false; - data++; - size--; - } -return true; -} - -//----------------------------------------------- - -bool BMidiStore::WriteMetaEvent(uint32 deltaTime, uint32 type, uchar* data, uint32 size) -{//ToTest - WriteVarLen(deltaTime); - if (EPutC(type) != 1) - return false; - while (size > 0) - { - if (EPutC(*data) != 1) - return false; - data++; - size--; - } -return true; -} - -//----------------------------------------------- - -bool BMidiStore::WriteSystemExclusiveEvent(uint32 deltaTime, uchar* data, uint32 size) -{//ToTest - WriteVarLen(deltaTime); - while (size > 0) - { - if (EPutC(*data) != 1) - return false; - data++; - size--; - } -return true; -} - -//----------------------------------------------- - -void BMidiStore::WriteTempo(uint32 deltaTime, int32 tempo) -{//ToTest - WriteVarLen(deltaTime); - Write16Bit(0xFF51); - EPutC(3); - EPutC((tempo >> 16) & 0xFF); - EPutC((tempo >> 8) & 0xFF); - EPutC(tempo & 0xFF); -} - -//----------------------------------------------- - -void BMidiStore::WriteVarLen(uint32 value) -{//ToTest -uint32 buffer = value & 0x7F; - while ( (value >>= 7) ) + while ((val >>= 7)) { buffer <<= 8; - buffer |= ((value & 0x7F) | 0x80); + buffer |= ((val & 0x7F) | 0x80); } + while (true) { - EPutC(buffer); + WriteByte(buffer); if (buffer & 0x80) buffer >>= 8; else @@ -902,72 +741,297 @@ uint32 buffer = value & 0x7F; } } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::Write32Bit(uint32 data) -{//ToTest - EPutC((data >> 24) & 0xFF); - EPutC((data >> 16) & 0xFF); - EPutC((data >> 8) & 0xFF); - EPutC(data & 0xFF); -} - -//----------------------------------------------- - -void BMidiStore::Write16Bit(ushort data) -{//ToTest - EPutC((data >> 8) & 0xFF); - EPutC(data & 0xFF); -} - -//----------------------------------------------- - -int32 BMidiStore::EPutC(uchar c) -{//ToTest - fNumBytesWritten++; -return fFile->Write(&c, 1); -} - -//----------------------------------------------- - - -uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const -{//ToTest - return ((uint64)ticks * 1000) / fDivision; -} - -//----------------------------------------------- - -uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const -{//ToTest - return ((uint64)ms * fDivision) / 1000; -} - -//----------------------------------------------- - -void BMidiStore::_ReservedMidiStore1() +void BMidiStore::ReadChunk() { + char fourcc[4]; + ReadFourCC(fourcc); + + byteCount = Read32Bit(); + + if (strncmp(fourcc, "MTrk", 4) == 0) + { + ReadTrack(); + } + else + { + TRACE(("Skipping '%c%c%c%c' chunk (%lu bytes)", + fourcc[0], fourcc[1], fourcc[2], fourcc[3], byteCount)) + + SkipBytes(byteCount); + } } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::_ReservedMidiStore2() +void BMidiStore::ReadTrack() { + uint8 status = 0; + uint8 data1; + uint8 data2; + BMidiEvent* event; + + totalTicks = 0; + + while (byteCount > 0) + { + uint32 ticks = ReadVarLength(); + totalTicks += ticks; + + if (PeekByte() & 0x80) + { + status = NextByte(); + } + + switch (status & 0xF0) + { + case B_NOTE_OFF: + case B_NOTE_ON: + case B_KEY_PRESSURE: + case B_CONTROL_CHANGE: + case B_PITCH_BEND: + data1 = NextByte(); + data2 = NextByte(); + event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = status; + event->byte2 = data1; + event->byte3 = data2; + AddEvent(event); + break; + + case B_PROGRAM_CHANGE: + case B_CHANNEL_PRESSURE: + data1 = NextByte(); + event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = status; + event->byte2 = data1; + AddEvent(event); + break; + + case 0xF0: + switch (status) + { + case B_SYS_EX_START: + ReadSystemExclusive(); + break; + + case B_TUNE_REQUEST: + case B_SYS_EX_END: + case B_TIMING_CLOCK: + case B_START: + case B_CONTINUE: + case B_STOP: + case B_ACTIVE_SENSING: + event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = status; + AddEvent(event); + break; + + case B_MIDI_TIME_CODE: + case B_SONG_SELECT: + case B_CABLE_MESSAGE: + data1 = NextByte(); + event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = status; + event->byte2 = data1; + AddEvent(event); + break; + + case B_SONG_POSITION: + data1 = NextByte(); + data2 = NextByte(); + event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = status; + event->byte2 = data1; + event->byte3 = data2; + AddEvent(event); + break; + + case B_SYSTEM_RESET: + ReadMetaEvent(); + break; + } + break; + } + + event = NULL; + } + + ++currTrack; } -//----------------------------------------------- +//------------------------------------------------------------------------------ -void BMidiStore::_ReservedMidiStore3() +void BMidiStore::ReadSystemExclusive() { + // We do not import sysex's from MIDI files. + + SkipBytes(ReadVarLength()); } -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- -//----------------------------------------------- +//------------------------------------------------------------------------------ + +void BMidiStore::ReadMetaEvent() +{ + // We only import the Tempo Change meta event. + + uint8 type = NextByte(); + uint32 length = ReadVarLength(); + + if ((type == 0x51) && (length == 3)) + { + uchar data[3]; + data[0] = NextByte(); + data[1] = NextByte(); + data[2] = NextByte(); + uint32 val = (data[0] << 16) | (data[1] << 8) | data[2]; + + BMidiEvent* event = new BMidiEvent; + event->time = totalTicks; + event->ticks = true; + event->byte1 = 0xFF; + event->byte2 = 0x51; + event->byte3 = 0x03; + event->tempo = 60000000 / val; + AddEvent(event); + } + else + { + SkipBytes(length); + } +} + +//------------------------------------------------------------------------------ + +void BMidiStore::WriteTrack() +{ + WriteFourCC('M', 'T', 'r', 'k'); + off_t lengthPos = file->Position(); + Write32Bit(0); + + byteCount = 0; + uint32 oldTime; + uint32 newTime; + + for (int32 t = 0; t < CountEvents(); ++t) + { + BMidiEvent* event = EventAt(t); + + if (event->ticks) + { + newTime = event->time; + } + else + { + newTime = MillisecondsToTicks(event->time); + } + + if (t == 0) + { + WriteVarLength(0); + } + else + { + WriteVarLength(newTime - oldTime); + } + + oldTime = newTime; + + switch (event->byte1 & 0xF0) + { + case B_NOTE_OFF: + case B_NOTE_ON: + case B_KEY_PRESSURE: + case B_CONTROL_CHANGE: + case B_PITCH_BEND: + WriteByte(event->byte1); + WriteByte(event->byte2); + WriteByte(event->byte3); + break; + + case B_PROGRAM_CHANGE: + case B_CHANNEL_PRESSURE: + WriteByte(event->byte1); + WriteByte(event->byte2); + break; + + case 0xF0: + switch (event->byte1) + { + case B_SYS_EX_START: + // We do not export sysex's. + break; + + case B_TUNE_REQUEST: + case B_SYS_EX_END: + case B_TIMING_CLOCK: + case B_START: + case B_CONTINUE: + case B_STOP: + case B_ACTIVE_SENSING: + WriteByte(event->byte1); + break; + + case B_MIDI_TIME_CODE: + case B_SONG_SELECT: + case B_CABLE_MESSAGE: + WriteByte(event->byte1); + WriteByte(event->byte2); + break; + + case B_SONG_POSITION: + WriteByte(event->byte1); + WriteByte(event->byte2); + WriteByte(event->byte3); + break; + + case B_SYSTEM_RESET: + WriteMetaEvent(event); + break; + } + break; + + } + } + + WriteVarLength(0); + WriteByte(0xFF); // the end-of-track + WriteByte(0x2F); // marker is required + WriteByte(0x00); + + file->Seek(lengthPos, SEEK_SET); + Write32Bit(byteCount); + file->Seek(0, SEEK_END); +} + +//------------------------------------------------------------------------------ + +void BMidiStore::WriteMetaEvent(BMidiEvent* event) +{ + // We only export the Tempo Change meta event. + + if ((event->byte2 == 0x51) && (event->byte3 == 0x03)) + { + uint32 val = 60000000 / event->tempo; + + WriteByte(0xFF); + WriteByte(0x51); + WriteByte(0x03); + WriteByte(val >> 16); + WriteByte(val >> 8); + WriteByte(val); + } +} + +//------------------------------------------------------------------------------ diff --git a/src/kits/midi/MidiSynth.cpp b/src/kits/midi/MidiSynth.cpp index d0c8f595b5..c2312914aa 100644 --- a/src/kits/midi/MidiSynth.cpp +++ b/src/kits/midi/MidiSynth.cpp @@ -1,7 +1,23 @@ -/** - * @file MidiSynth.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans * - * @author Matthijs Hollemans + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #include "debug.h" @@ -209,4 +225,3 @@ void BMidiSynth::Run() } //------------------------------------------------------------------------------ - diff --git a/src/kits/midi/MidiSynthFile.cpp b/src/kits/midi/MidiSynthFile.cpp index 8fb50f59e4..9dbf942e5f 100644 --- a/src/kits/midi/MidiSynthFile.cpp +++ b/src/kits/midi/MidiSynthFile.cpp @@ -1,7 +1,23 @@ -/** - * @file MidiSynthFile.h +/* + * Copyright (c) 2002-2003 Matthijs Hollemans * - * @author Matthijs Hollemans + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #include "debug.h" @@ -184,4 +200,3 @@ void BMidiSynthFile::_ReservedMidiSynthFile2() { } void BMidiSynthFile::_ReservedMidiSynthFile3() { } // ----------------------------------------------------------------------------- - diff --git a/src/kits/midi/MidiText.cpp b/src/kits/midi/MidiText.cpp index 0b83122ef4..f00a393985 100644 --- a/src/kits/midi/MidiText.cpp +++ b/src/kits/midi/MidiText.cpp @@ -1,15 +1,30 @@ -/** - * @file MidiText.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans + * Copyright (c) 2002 Jerome Leveque + * Copyright (c) 2002 Paul Stadler * - * @author Matthijs Hollemans - * @author Jerome Leveque - * @author Paul Stadler + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ -#include +#include #include "debug.h" -#include "MidiEvent.h" #include "MidiText.h" //------------------------------------------------------------------------------ @@ -23,7 +38,7 @@ BMidiText::BMidiText() BMidiText::~BMidiText() { - // Do nothing + // do nothing } //------------------------------------------------------------------------------ @@ -32,9 +47,9 @@ void BMidiText::NoteOff( uchar channel, uchar note, uchar velocity, uint32 time) { WaitAndPrint(time); - cout << ": NOTE OFF; channel = " << (int) channel - << ", note = " << (int) note - << ", velocity = " << (int) velocity << endl; + printf( + "B_NOTE OFF; channel = %d, note = %d, velocity = %d\n", + channel, note, velocity); } //------------------------------------------------------------------------------ @@ -43,9 +58,9 @@ void BMidiText::NoteOn( uchar channel, uchar note, uchar velocity, uint32 time) { WaitAndPrint(time); - cout << ": NOTE ON; channel = " << (int) channel - << ", note = " << (int) note - << ", velocity = " << (int) velocity << endl; + printf( + "B_NOTE ON; channel = %d, note = %d, velocity = %d\n", + channel, note, velocity); } //------------------------------------------------------------------------------ @@ -54,9 +69,9 @@ void BMidiText::KeyPressure( uchar channel, uchar note, uchar pressure, uint32 time) { WaitAndPrint(time); - cout << ": KEY PRESSURE; channel = " << (int) channel - << ", note = " << (int) note - << ", pressure = " << (int) pressure << endl; + printf( + "KEY PRESSURE; channel = %d, note = %d, pressure = %d\n", + channel, note, pressure); } //------------------------------------------------------------------------------ @@ -65,9 +80,9 @@ void BMidiText::ControlChange( uchar channel, uchar controlNumber, uchar controlValue, uint32 time) { WaitAndPrint(time); - cout << ": CONTROL CHANGE; channel = " << (int) channel - << ", control = " << (int) controlNumber - << ", value = "<< (int) controlValue << endl; + printf( + "CONTROL CHANGE; channel = %d, control = %d, value = %d\n", + channel, controlNumber, controlValue); } //------------------------------------------------------------------------------ @@ -76,8 +91,9 @@ void BMidiText::ProgramChange( uchar channel, uchar programNumber, uint32 time) { WaitAndPrint(time); - cout << ": PROGRAM CHANGE; channel = " << (int) channel - << ", program = " << (int) programNumber << endl; + printf( + "PROGRAM CHANGE; channel = %d, program = %d\n", + channel, programNumber); } //------------------------------------------------------------------------------ @@ -85,8 +101,9 @@ void BMidiText::ProgramChange( void BMidiText::ChannelPressure(uchar channel, uchar pressure, uint32 time) { WaitAndPrint(time); - cout << ": CHANNEL PRESSURE; channel = " << (int) channel - << ", pressure = " << (int) pressure << endl; + printf( + "CHANNEL PRESSURE; channel = %d, pressure = %d\n", + channel, pressure); } //------------------------------------------------------------------------------ @@ -94,23 +111,23 @@ void BMidiText::ChannelPressure(uchar channel, uchar pressure, uint32 time) void BMidiText::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) { WaitAndPrint(time); - cout << ": PITCH BEND; channel = " << (int) channel << hex - << ", lsb = " << (int) lsb - << ", msb = " << (int) msb << endl; + printf( + "PITCH BEND; channel = %d, lsb = %d, msb = %d\n", + channel, lsb, msb); } //------------------------------------------------------------------------------ -void BMidiText::SystemExclusive(void* data, size_t dataLength, uint32 time) +void BMidiText::SystemExclusive(void* data, size_t length, uint32 time) { WaitAndPrint(time); - cout << ": SYSTEM EXCLUSIVE;"; - for (size_t i = 0; i < dataLength; i++) + printf("SYSTEM EXCLUSIVE;\n"); + for (size_t t = 0; t < length; ++t) { - cout << " " << hex << (int) ((uint8*) data)[i]; + printf("%02X ", ((uint8*) data)[t]); } - cout << endl; + printf("\n"); } //------------------------------------------------------------------------------ @@ -119,9 +136,9 @@ void BMidiText::SystemCommon( uchar status, uchar data1, uchar data2, uint32 time) { WaitAndPrint(time); - cout << ": SYSTEM COMMON; status = " << hex << (int) status - << ", data1 = " << (int) data1 - << ", data2 = " << (int) data2 << endl; + printf( + "SYSTEM COMMON; status = %d, data1 = %d, data2 = %d\n", + status, data1, data2); } //------------------------------------------------------------------------------ @@ -129,23 +146,7 @@ void BMidiText::SystemCommon( void BMidiText::SystemRealTime(uchar status, uint32 time) { WaitAndPrint(time); - cout << ": SYSTEM REAL TIME; status = " << hex << (int) status << endl; -} - -//------------------------------------------------------------------------------ - -void BMidiText::TempoChange(int32 beatsPerMinute, uint32 time) -{ - WaitAndPrint(time); - cout << ": TEMPO CHANGE; beatsperminute = " << beatsPerMinute << endl; -} - -//------------------------------------------------------------------------------ - -void BMidiText::AllNotesOff(bool justChannel, uint32 time) -{ - WaitAndPrint(time); - cout << ": ALL NOTES OFF;" << endl; + printf("SYSTEM REAL TIME; status = %d\n", status); } //------------------------------------------------------------------------------ @@ -158,6 +159,8 @@ void BMidiText::ResetTimer(bool start) //------------------------------------------------------------------------------ void BMidiText::_ReservedMidiText1() { } +void BMidiText::_ReservedMidiText2() { } +void BMidiText::_ReservedMidiText3() { } //------------------------------------------------------------------------------ @@ -177,8 +180,7 @@ void BMidiText::WaitAndPrint(uint32 time) SnoozeUntil(time); - cout << dec << (time - startTime); + printf("%u: ", time - startTime); } //------------------------------------------------------------------------------ - diff --git a/src/kits/midi/Samples.cpp b/src/kits/midi/Samples.cpp index 5bfe4cf8f6..79c72a0260 100644 --- a/src/kits/midi/Samples.cpp +++ b/src/kits/midi/Samples.cpp @@ -1,7 +1,23 @@ -/** - * @file Samples.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans * - * @author Matthijs Hollemans + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #include "debug.h" @@ -128,4 +144,3 @@ void BSamples::_ReservedSamples2() { } void BSamples::_ReservedSamples3() { } //------------------------------------------------------------------------------ - diff --git a/src/kits/midi/Synth.cpp b/src/kits/midi/Synth.cpp index 5cf955613f..027e6ffb9d 100644 --- a/src/kits/midi/Synth.cpp +++ b/src/kits/midi/Synth.cpp @@ -1,7 +1,23 @@ -/** - * @file Synth.cpp +/* + * Copyright (c) 2002-2003 Matthijs Hollemans * - * @author Matthijs Hollemans + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #include "debug.h" @@ -239,27 +255,3 @@ void BSynth::_ReservedSynth3() { } void BSynth::_ReservedSynth4() { } //------------------------------------------------------------------------------ - -void BSynth::_init() -{ - UNIMPLEMENTED -} - -//------------------------------------------------------------------------------ - -status_t BSynth::_do_load(synth_mode synth) -{ - UNIMPLEMENTED - return B_ERROR; -} - -//------------------------------------------------------------------------------ - -status_t BSynth::_load_insts(entry_ref* ref) -{ - UNIMPLEMENTED - return B_ERROR; -} - -//------------------------------------------------------------------------------ -