diff --git a/commands.txt b/commands.txt new file mode 100644 index 0000000..22551d4 --- /dev/null +++ b/commands.txt @@ -0,0 +1,5 @@ + +Jacker Pattern Channel Commands +=============================== + + V xx: change channel volume to xx diff --git a/midi.hpp b/midi.hpp index f96dd8b..6794eeb 100644 --- a/midi.hpp +++ b/midi.hpp @@ -57,7 +57,7 @@ struct Message { }; unsigned char data1; unsigned char data2; - unsigned char rest; + unsigned char data3; // usually unused }; long data; unsigned char bytes[4]; diff --git a/model.cpp b/model.cpp index 37e94ba..8758eec 100644 --- a/model.cpp +++ b/model.cpp @@ -99,6 +99,9 @@ void PatternEvent::sanitize_value() { value = std::min(std::max(value,0x21),0x7f); } break; case ParamValue: + { + value = std::min(std::max(value,0),0xff); + } break; case ParamVolume: case ParamCCIndex: case ParamCCValue: diff --git a/player.cpp b/player.cpp index 5b7367e..d36a333 100644 --- a/player.cpp +++ b/player.cpp @@ -60,7 +60,25 @@ void MessageQueue::on_cc(int bus, int ccindex, int ccvalue) { push(msg); } -void MessageQueue::on_note(int bus, int channel, int note, int velocity/*=0x7f*/) { +void MessageQueue::on_command(int bus, Message::Type command, int value, int value2, int value3) { + if (value == ValueNone) + return; + if (value2 == ValueNone) + value2 = 0; + if (value3 == ValueNone) + value3 = 0; + assert(model); + Message msg; + init_message(bus,msg); + msg.type = command; + msg.bus = bus; + msg.status = value; + msg.data1 = value2; + msg.data2 = value3; + push(msg); +} + +void MessageQueue::on_note(int bus, int channel, int note, int velocity) { if (note == ValueNone) return; if (velocity == ValueNone) @@ -99,7 +117,7 @@ void MessageQueue::status_msg() { Player::Channel::Channel() { note = ValueNone; - volume = 0x7f; + volume = 1.0f; } //============================================================================= @@ -210,7 +228,7 @@ void Player::play_event(int track, const class PatternEvent &event) { int note = event.value; if (note == ValueNone) return; - rt_messages.on_note(track, event.channel, note); + rt_messages.on_note(track, event.channel, note, ValueNone); } void Player::mix_events(MessageQueue &queue, int samples) { @@ -256,8 +274,14 @@ void Player::mix_frame(MessageQueue &queue) { // first run: process all cc events for (int channel = 0; channel < pattern.get_channel_count(); ++channel) { - queue.on_cc(event.track, row.get_value(channel, ParamCCIndex), - row.get_value(channel, ParamCCValue)); + int command = row.get_value(channel, ParamCommand); + int ccindex = row.get_value(channel, ParamCCIndex); + int ccvalue = row.get_value(channel, ParamCCValue); + if (command != ValueNone) { + queue.on_command(event.track, (Message::Type)command, + row.get_value(channel, ParamValue), ccindex, ccvalue); + } + queue.on_cc(event.track, ccindex, ccvalue); } // second run: process volume and notes @@ -279,52 +303,58 @@ void Player::handle_message(Message msg) { Bus &bus = buses[msg.bus]; Channel &values = bus.channels[msg.bus_channel]; - if (msg.command == MIDI::CommandControlChange) { - switch(msg.data1) { - case MIDI::ControllerAllNotesOff: - { - for (NoteArray::iterator iter = bus.notes.begin(); - iter != bus.notes.end(); ++iter) { - *iter = -1; - } - on_message(msg); - } break; - default: - { - on_message(msg); - } break; - } - return; - } else if (msg.command == MIDI::CommandNoteOff) { - if (values.note != ValueNone) { - int note = values.note; - values.note = ValueNone; - // see if that note is actually being played - // on our channel, if yes, kill it. - if (bus.notes[note] == msg.bus_channel) { - bus.notes[note] = -1; - msg.data1 = note; - msg.data2 = 0; - on_message(msg); - } - } - return; - } else if (msg.command == MIDI::CommandNoteOn) { - if (values.note != ValueNone) { - int note = values.note; - values.note = ValueNone; - // no matter where the note is played, kill it. - bus.notes[note] = -1; - Message off_msg(msg); - off_msg.command = MIDI::CommandNoteOff; - off_msg.data1 = note; - off_msg.data2 = 0; - on_message(off_msg); - } - values.note = msg.data1; - bus.notes[values.note] = msg.bus_channel; - on_message(msg); - return; + if (msg.type == Message::TypeMIDI) { + if (msg.command == MIDI::CommandControlChange) { + switch(msg.data1) { + case MIDI::ControllerAllNotesOff: + { + for (NoteArray::iterator iter = bus.notes.begin(); + iter != bus.notes.end(); ++iter) { + *iter = -1; + } + on_message(msg); + } break; + default: + { + on_message(msg); + } break; + } + return; + } else if (msg.command == MIDI::CommandNoteOff) { + if (values.note != ValueNone) { + int note = values.note; + values.note = ValueNone; + // see if that note is actually being played + // on our channel, if yes, kill it. + if (bus.notes[note] == msg.bus_channel) { + bus.notes[note] = -1; + msg.data1 = note; + msg.data2 = 0; + on_message(msg); + } + } + return; + } else if (msg.command == MIDI::CommandNoteOn) { + if (values.note != ValueNone) { + int note = values.note; + values.note = ValueNone; + // no matter where the note is played, kill it. + bus.notes[note] = -1; + Message off_msg(msg); + off_msg.command = MIDI::CommandNoteOff; + off_msg.data1 = note; + off_msg.data2 = 0; + on_message(off_msg); + } + values.note = msg.data1; + int volume = std::min((int)((float)(msg.data2) * values.volume), 0x7f); + msg.data2 = volume; + bus.notes[values.note] = msg.bus_channel; + on_message(msg); + return; + } + } else if (msg.type == Message::TypeCommandChannelVolume) { + values.volume = std::min((float)(msg.status) / 0x7f, 1.0f); } } diff --git a/player.hpp b/player.hpp index d1dc65e..803416c 100644 --- a/player.hpp +++ b/player.hpp @@ -14,6 +14,9 @@ struct Message : MIDI::Message { TypeEmpty = 0, // midi package TypeMIDI = 1, + + // command + TypeCommandChannelVolume = 'V', }; Type type; @@ -33,8 +36,9 @@ public: volatile int position; // in frames volatile long long read_samples; - void on_note(int bus, int channel, int value, int velocity=0x7f); + void on_note(int bus, int channel, int value, int velocity); void on_cc(int bus, int ccindex, int ccvalue); + void on_command(int bus, Message::Type command, int value, int value2, int value3); void all_notes_off(int bus); void status_msg(); @@ -55,7 +59,7 @@ public: }; struct Channel { - int volume; + float volume; int note; Channel();