void CLogicalChannel::handle(byte status, byte *params) { byte cmd = (status & 0xF0); switch(cmd) { case 0x80: case 0x90: if(cmd == 0x80 || cmd == 0x90) { if(cmd == 0x80 || params[1] == 0x00) { handleNoteOff(params[0]); } else { handleNoteOn(params[0], params[1]); } } break; case 0xB0: handleCC(params[0], params[1]); break; case 0xE0: handlePitchBend(params[0], params[1]); break; } }
// Handle decoding incoming MIDI traffic a byte at a time -- remembers // what it needs to from one call to the next. // // This is a private function & not meant to be called from outside this class. // It's used whenever data is available from the serial port. // void Midi::recvByte(int value) { int tmp; int channel; int bigval; /* temp 14-bit value for pitch, song pos */ if (recvMode_ & MODE_PROPRIETARY && value != STATUS_END_PROPRIETARY) { /* If proprietary handling compiled in, just pass all data received * after a START_PROPRIETARY event to proprietary_decode * until get an END_PROPRIETARY event */ #ifdef CONFIG_MIDI_PROPRIETARY proprietaryDecode(value); #endif return; } if (value & 0x80) { /* All < 0xf0 events get at least 1 arg byte so * it's ok to mask off the low 4 bits to figure * out how to handle the event for < 0xf0 events. */ tmp = value; if (tmp < 0xf0) tmp &= 0xf0; switch (tmp) { /* These status events take 2 bytes as arguments */ case STATUS_EVENT_NOTE_OFF: case STATUS_EVENT_NOTE_ON: case STATUS_EVENT_VELOCITY_CHANGE: case STATUS_EVENT_CONTROL_CHANGE: case STATUS_PITCH_CHANGE: case STATUS_SONG_POSITION: recvBytesNeeded_ = 2; recvByteCount_ = 0; recvEvent_ = value; break; /* 1 byte arguments */ case STATUS_EVENT_PROGRAM_CHANGE: case STATUS_AFTER_TOUCH: case STATUS_SONG_SELECT: recvBytesNeeded_ = 1; recvByteCount_ = 0; recvEvent_ = value; return; /* No arguments ( > 0xf0 events) */ case STATUS_START_PROPRIETARY: recvMode_ |= MODE_PROPRIETARY; #ifdef CONFIG_MIDI_PROPRIETARY proprietaryDecodeStart(); #endif break; case STATUS_END_PROPRIETARY: recvMode_ &= ~MODE_PROPRIETARY; #ifdef CONFIG_MIDI_PROPRIETARY proprietaryDecodeEnd(); #endif break; case STATUS_TUNE_REQUEST: handleTuneRequest(); break; case STATUS_SYNC: handleSync(); break; case STATUS_START: handleStart(); break; case STATUS_CONTINUE: handleContinue(); break; case STATUS_STOP: handleStop(); break; case STATUS_ACTIVE_SENSE: handleActiveSense(); break; case STATUS_RESET: handleReset(); break; } return; } if (++recvByteCount_ == recvBytesNeeded_) { /* Copy out the channel (if applicable; in some cases this will be meaningless, * but in those cases the value will be ignored) */ channel = (recvEvent_ & 0x0f) + 1; tmp = recvEvent_; if (tmp < 0xf0) { tmp &= 0xf0; } /* See if this event matches our MIDI channel * (or we're accepting for all channels) */ if (!channelIn_ || (channel == channelIn_) || (tmp >= 0xf0)) { switch (tmp) { case STATUS_EVENT_NOTE_ON: /* If velocity is 0, it's actually a note off & should fall thru * to the note off case */ if (value) { handleNoteOn(channel, recvArg0_, value); break; } case STATUS_EVENT_NOTE_OFF: handleNoteOff(channel, recvArg0_, value); break; case STATUS_EVENT_VELOCITY_CHANGE: handleVelocityChange(channel, recvArg0_, value); break; case STATUS_EVENT_CONTROL_CHANGE: handleControlChange(channel, recvArg0_, value); break; case STATUS_EVENT_PROGRAM_CHANGE: handleProgramChange(channel, value); break; case STATUS_AFTER_TOUCH: handleAfterTouch(channel, value); break; case STATUS_PITCH_CHANGE: bigval = (value << 7) | recvArg0_; handlePitchChange(bigval); break; case STATUS_SONG_POSITION: bigval = (value << 7) | recvArg0_; handleSongPosition(bigval); break; case STATUS_SONG_SELECT: handleSongSelect(value); break; } } /* Just reset the byte count; keep the same event -- might get more messages trailing from current event. */ recvByteCount_ = 0; } recvArg0_ = value; }
void SysexComm::handleNoteOff(MidiKeyboardState* source, int midiChannel, int midiNoteNumber) { handleNoteOn(source, midiChannel, midiNoteNumber, 0); }
// Process a MIDI Note On message void MidiSostenutoPedal::noteOn(uint8_t channel, uint8_t note, uint8_t velocity) { bitSet(prePedalNotes[channel & 0xF][(note & 0x7F) / 32], (note & 0x7F) % 32); // Remember as channel pre-pedal note if (bitRead(pressed, channel & 0xF)) // If pedal pressed, reset channel held note bitClear(heldNotes[channel & 0xF][(note & 0x7F) / 32], (note & 0x7F) % 32); handleNoteOn(channel, note, velocity); }
//////////////////////////////////////////////////////////// // MAIN void main() { int i; // osc control / 16MHz / internal osccon = 0b01111010; apfcon0 = APFCON0_MASK; // configure io. Initially all outputs are // disabled except for the LED and all outputs // states are zeroed trisa = 0b11111111; trisc = 0b11111111; T_LED = 0; ansela = 0b00000000; anselc = 0b00000000; porta = 0b00000000; portc = 0b00000000; P_WPU = 1; // weak pull up on switch input option_reg.7 = 0; // weak pull up enable // initialise MIDI comms init_usart(); intcon.7 = 1; //GIE intcon.6 = 1; //PEIE // Configure timer 0 (controls systemticks) // timer 0 runs at 4MHz // prescaled 1/16 = 250kHz // rollover at 250 = 1kHz // 1ms per rollover option_reg.5 = 0; // timer 0 driven from instruction cycle clock option_reg.3 = 0; // timer 0 is prescaled option_reg.2 = 0; // } option_reg.1 = 1; // } 1/16 prescaler option_reg.0 = 1; // } intcon.5 = 1; // enabled timer 0 interrrupt intcon.2 = 0; // clear interrupt fired flag // enable interrupts intcon.7 = 1; //GIE intcon.6 = 1; //PEIE // Initialise the table of port info pointers port[0] = &port0; port[1] = &port1; port[2] = &port2; port[3] = &port3; port[4] = &port4; port[5] = &port5; port[6] = &port6; port[7] = &port7; // allow time for input to settle then load // EEPROM settings, allowing a hold of MODE // to restore default settings delay_ms(5); loadPortInfo((!P_MODE)); #ifdef RELAY_SWITCHER // In relay switching mode set all output latches LOW // and set default tristate (INPUT/1 selected for OFF) T_OUT0 = !port0.cfg.invert; T_OUT1 = !port1.cfg.invert; T_OUT2 = !port2.cfg.invert; T_OUT3 = !port3.cfg.invert; T_OUT4 = !port4.cfg.invert; T_OUT5 = !port5.cfg.invert; T_OUT6 = !port6.cfg.invert; T_OUT7 = !port7.cfg.invert; P_OUT0 = 0; P_OUT1 = 0; P_OUT2 = 0; P_OUT3 = 0; P_OUT4 = 0; P_OUT5 = 0; P_OUT6 = 0; P_OUT7 = 0; #else // In transistor switching mode set default "off" // states and enable digital outputs P_OUT0 = !!port0.cfg.invert; P_OUT1 = !!port1.cfg.invert; P_OUT2 = !!port2.cfg.invert; P_OUT3 = !!port3.cfg.invert; P_OUT4 = !!port4.cfg.invert; P_OUT5 = !!port5.cfg.invert; P_OUT6 = !!port6.cfg.invert; P_OUT7 = !!port7.cfg.invert; T_OUT0 = 0; T_OUT1 = 0; T_OUT2 = 0; T_OUT3 = 0; T_OUT4 = 0; T_OUT5 = 0; T_OUT6 = 0; T_OUT7 = 0; #endif int ledCount = 0; int modeHeld = 0; byte enableNrpn = 0; byte nrpnLo = 0; byte nrpnHi = 0; byte pwm=0; int cycles = 0; for(;;) { // Fetch the next MIDI message byte msg = receiveMessage(); if(msg && !ledCount) ledCount = LEDCOUNT_BRIEF; // NOTE ON if(((msg & 0xf0) == 0x90) && midiParams[1]) { handleNoteOn(msg&0xF, midiParams[0], midiParams[1]); } // NOTE OFF else if((((msg & 0xf0) == 0x80)||((msg & 0xf0) == 0x90))) { handleNoteOff(msg&0xF, midiParams[0]); } // CONTROLLER else if((msg & 0xf0) == 0xb0) { if(enableNrpn) { switch(midiParams[0]) { case MIDI_NRPN_HI: nrpnHi = midiParams[1]; break; case MIDI_NRPN_LO: nrpnLo = midiParams[1]; break; case MIDI_DATA_HI: case MIDI_DATA_LO: if(nrpnHi < NUM_PORTS) handleNrpn(port[nrpnHi], nrpnLo, midiParams[1], (midiParams[0] == MIDI_DATA_LO)); else if(nrpnHi == NRPN_HI_EEPROM && nrpnLo == NRPN_LO_SAVE) savePortInfo(); break; default: handleCC(msg&0xF, midiParams[0], midiParams[1]); break; } } else { handleCC(msg&0xF, midiParams[0], midiParams[1]); } } // PITCH BEND else if((msg & 0xf0) == 0xe0) { handlePitchBend(msg&0xF, midiParams[0]); } if(ledCount) P_LED = !!(--ledCount); // EVERY MS if(timerTicked) { timerTicked = 0; // Decrement nonzero port latch counts for(i=0;i<NUM_PORTS;++i) { if(port[i]->status.count>0) --port[i]->status.count; } // If the MODE button is held for 1 second // this enables the receiving of config info if(!enableNrpn) { if(P_MODE)//mode button released { modeHeld = 0; } else if(++modeHeld >= 1000)// mode button pressed for more than 1 second { P_LED = 1; delay_s(1); P_LED = 0; enableNrpn = 1; } } else if(isDirtyConfig)//config has been updated { if(!P_MODE)// { P_LED = 1; delay_s(1); P_LED = 0; savePortInfo(); isDirtyConfig = 0; } else { ++cycles; if(!(cycles & 0x1FF) && !ledCount) ledCount = LEDCOUNT_MEDIUM; } } else { ++cycles; if(!(cycles & 0x7FF) && !ledCount) ledCount = LEDCOUNT_LONG; } } #ifdef RELAY_SWITCHER // Manage outputs for relay switcher. PWM is ignored and switching // is done on the TRIS bit. The outputs are active low for ON and // floating for OFF #define OUT_STATE(P) !(P.status.count) #define OUT_STATEN(P) !!(P.status.count) T_OUT0 = port0.cfg.invert? OUT_STATEN(port0) : OUT_STATE(port0); T_OUT1 = port1.cfg.invert? OUT_STATEN(port1) : OUT_STATE(port1); T_OUT2 = port2.cfg.invert? OUT_STATEN(port2) : OUT_STATE(port2); T_OUT3 = port3.cfg.invert? OUT_STATEN(port3) : OUT_STATE(port3); T_OUT4 = port4.cfg.invert? OUT_STATEN(port4) : OUT_STATE(port4); T_OUT5 = port5.cfg.invert? OUT_STATEN(port5) : OUT_STATE(port5); T_OUT6 = port6.cfg.invert? OUT_STATEN(port6) : OUT_STATE(port6); T_OUT7 = port7.cfg.invert? OUT_STATEN(port7) : OUT_STATE(port7); P_OUT0 = 0; P_OUT1 = 0; P_OUT2 = 0; P_OUT3 = 0; P_OUT4 = 0; P_OUT5 = 0; P_OUT6 = 0; P_OUT7 = 0; #elif TRS_SWITCHER // Manage outputs for TRS relay switcher. PWM is ignored and switching // is active high #define OUT_STATE(P) !!(P.status.count) #define OUT_STATEN(P) !(P.status.count) P_OUT0 = port0.cfg.invert? OUT_STATEN(port0) : OUT_STATE(port0); P_OUT1 = port1.cfg.invert? OUT_STATEN(port1) : OUT_STATE(port1); P_OUT2 = port2.cfg.invert? OUT_STATEN(port2) : OUT_STATE(port2); P_OUT3 = port3.cfg.invert? OUT_STATEN(port3) : OUT_STATE(port3); P_OUT4 = port4.cfg.invert? OUT_STATEN(port4) : OUT_STATE(port4); P_OUT5 = port5.cfg.invert? OUT_STATEN(port5) : OUT_STATE(port5); P_OUT6 = port6.cfg.invert? OUT_STATEN(port6) : OUT_STATE(port6); P_OUT7 = port7.cfg.invert? OUT_STATEN(port7) : OUT_STATE(port7); #else // Manage outputs for transistor switchers. PWM is used and switching // is active high #define OUT_STATE(P) (P.status.count && (pwm < P.status.duty)) #define OUT_STATEN(P) (!P.status.count && (pwm < P.status.duty)) P_OUT0 = port0.cfg.invert? OUT_STATEN(port0) : OUT_STATE(port0); P_OUT1 = port1.cfg.invert? OUT_STATEN(port1) : OUT_STATE(port1); P_OUT2 = port2.cfg.invert? OUT_STATEN(port2) : OUT_STATE(port2); P_OUT3 = port3.cfg.invert? OUT_STATEN(port3) : OUT_STATE(port3); P_OUT4 = port4.cfg.invert? OUT_STATEN(port4) : OUT_STATE(port4); P_OUT5 = port5.cfg.invert? OUT_STATEN(port5) : OUT_STATE(port5); P_OUT6 = port6.cfg.invert? OUT_STATEN(port6) : OUT_STATE(port6); P_OUT7 = port7.cfg.invert? OUT_STATEN(port7) : OUT_STATE(port7); if(++pwm>100) pwm=0; #endif } }
// Process a MIDI Note On message void MidiDamperPedal::noteOn(uint8_t channel, uint8_t note, uint8_t velocity) { if (bitRead(heldNotes[channel & 0xF][(note & 0x7F) / 32], (note & 0x7F) % 32)) bitClear(heldNotes[channel & 0xF][(note & 0x7F) / 32], (note & 0x7F) % 32); // Reset channel held note handleNoteOn(channel, note, velocity); }
// Handle decoding incoming MIDI traffic a byte at a time -- remembers // what it needs to from one call to the next. // // This is a private function & not meant to be called from outside this class. // It's used whenever data is available from the serial port. // void USBMidi::dispatchPacket(uint32 p) { union EVENT_t e; e.i=p; // !!!!!!!!!!!!!!!! Add a sysex handler FIX THIS VERY VERY SHORTLY !!!!!!!!!!!!!! if (recvMode_ & MODE_PROPRIETARY && CIN_IS_SYSEX(e.p.cin)) { /* If sysex handling compiled in, just pass all data received * to the sysex handler */ #ifdef CONFIG_MIDI_PROPRIETARY // handleSysex(p); #endif return; } switch (e.p.cin) { case CIN_3BYTE_SYS_COMMON: if (e.p.midi0 == MIDIv1_SONG_POSITION_PTR) { handleSongPosition(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); } break; case CIN_2BYTE_SYS_COMMON: switch (e.p.midi0) { case MIDIv1_SONG_SELECT: handleSongSelect(e.p.midi1); break; case MIDIv1_MTC_QUARTER_FRAME: // reference library doesnt handle quarter frame. break; } break; case CIN_NOTE_OFF: handleNoteOff(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); break; case CIN_NOTE_ON: handleNoteOn(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); break; case CIN_AFTER_TOUCH: handleVelocityChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); break; case CIN_CONTROL_CHANGE: handleControlChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); break; case CIN_PROGRAM_CHANGE: handleProgramChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); break; case CIN_CHANNEL_PRESSURE: handleAfterTouch(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); break; case CIN_PITCH_WHEEL: handlePitchChange(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); break; case CIN_1BYTE: switch (e.p.midi0) { case MIDIv1_CLOCK: handleSync(); break; case MIDIv1_TICK: break; case MIDIv1_START: handleStart(); break; case MIDIv1_CONTINUE: handleContinue(); break; case MIDIv1_STOP: handleStop(); break; case MIDIv1_ACTIVE_SENSE: handleActiveSense(); break; case MIDIv1_RESET: handleReset(); break; case MIDIv1_TUNE_REQUEST: handleTuneRequest(); break; default: break; } break; } }