Skip to content

Instantly share code, notes, and snippets.

@unohee
Last active December 24, 2015 18:00
Show Gist options
  • Save unohee/9c2e9f931ea8c2740b0e to your computer and use it in GitHub Desktop.
Save unohee/9c2e9f931ea8c2740b0e to your computer and use it in GitHub Desktop.
ofxMidi / ofxMaxim Polyphonic Synthesizer Example
void ofApp::newMidiMessage(ofxMidiMessage& msg) {
//RtMidi Callback.
// make a copy of the latest message
midiMessage = msg;
//ASSIGNING NEW ENUMS FOR M-Audio Keystation 32----------------------------------
NOTE_STATUS KEY;
//Create new Enumeration to seperate two states: NOTE_ON but velocity is bigger than 0 and else.
//ofxMidi gives two enum based on raw midi status byte 0x90(NOTE_ON), 0x80(NOTE_OFF)
//from Midi keyboard. but mine doesnÕt do same thing.
/*
*MIDI.org says that
In MIDI systems, the activation of a particular note
and the release of the same note are considered as two separate events.
When a key is pressed on a MIDI keyboard instrument or MIDI keyboard controller,
the keyboard sends a Note On message on the MIDI OUT port.
The keyboard may be set to transmit on any one of the sixteen logical MIDI channels,
and the status byte for the Note On message will indicate the selected Channel number.
The Note On status byte is followed by two data bytes, which specify key number (indicating which key was pressed)
and velocity (how hard the key was pressed).
*/
note_on = false;
note_off = false;
//Assigning new Enums based on Velocity------------------------------------------
if(msg.velocity > 0){ //note on only gets velocity.
KEY = KEY_ON;//note on only gets velocity.
//or check ENUM directly from ofxMidi library.
if(MIDI_NOTE_ON) note_on = TRUE;
}
else{
//if velocity is zero..
//Case 1. if ofxMidi doesn't send NOTEOFF enum. we use this.
KEY = KEY_OFF;//then I say it is NOTE OFF.
//Case 2. If ofxMidi captures NOTEOFF from MIDI Device..
if(MIDI_NOTE_OFF) note_off = TRUE;
}
if (KEY == KEY_ON) note_on = TRUE;
if (KEY == KEY_OFF) note_off = TRUE;
//so now it's evenly same as usual midi device.
//--------------------------------------------------------------------------------
//Polyphony Method (Simplified Version. note that it doesn't have note stealing.)
//based on Maximilian polyphony example's structure. https://github.com/micknoise/Maximilian/blob/master/maximilian_examples/15.polysynth.cpp
//*check how many keys are pressed
if (note_on){
//then number of input note increments. (if it's 2 note. voice will be 2);
voice++;
}
if (note_off){
//erase note.
voice--;
}
//** and do iterations which keys were pressed.
for(int i = 1; i <108; i++){ //the range of midi note is 1-108
if(note_on){
//Keypressed.
isPressed[msg.pitch] = true;
}
if(note_off){
//Keyreleased.
isPressed[msg.pitch] = false;
}
if(isPressed[msg.pitch]){//NOTE_ON
if(voice==16){
voice = 0;
}
note[voice] = msg.pitch; //assign note value in each voice arrays.
OSCin[voice] = midiTofreq(note[voice]); //send mtof pitch to VCOs.
//and Trigger 2 Env.
ADSR1[voice].trigger = 1;
ADSR2[voice].trigger = 1;
}
if(!isPressed[msg.pitch]){//NOTE_OFF
for(int i=0; i<16; i++){
//stops Envelopes in Note OFF situation (0 velocity)
ADSR1[i].trigger = 0;
ADSR2[i].trigger = 0;
}
}
}
//printout
if(note_on){
for(int i = 0; i < voice; i++){
cout<< "Note On : "<< note[i] << endl;
}
cout<< voice << " Voice"<< endl;
}
if(note_off){
cout<< "Note Off : "<< msg.pitch << endl;
}
}
//--------------------------------------------------------------
void ofApp::audioOut(float * output, int bufferSize, int nChannels){
for(int i = 0; i < bufferSize; i++){
for(int i = 0; i < 16; i++){
//these envelope parameters will be updated as GUI modulates values..
//Filter Envelope
ADSR1[i].setAttack(env1atk);
ADSR1[i].setDecay(env1dec);
ADSR1[i].setSustain(env1sus);
ADSR1[i].setRelease(env1rel);
//AMP Envelope
ADSR2[i].setAttack(env2atk);
ADSR2[i].setDecay(env2dec);
ADSR2[i].setSustain(env2rel);
ADSR2[i].setRelease(env2sus);
VCOout[i] = VCO[i].sawn(porta[i].lopass(OSCin[i], 0.001)) + subOsc[i].sawn(OSCin[i]/2);
//use lopass filter in frequency input for adding glide(portamento) feel.
VCFout[i] = VCF[i].lores(VCOout[i], 500*ADSRout[i]*10, 2);
ADSRout[i] = ADSR1[i].adsr(1.0,ADSR1[i].trigger); //ADSR1 controls filter.
ampOut += VCFout[i] * ADSR2[i].adsr(1.0, ADSR2[i].trigger) / (16 * bufferSize) * 50; // divide it same size of voices. otherwise it burst.
}
outputTwoChannel.stereo(ampOut, outputTwoChannels, 0.5); //simple way to map mono sounds to stereo channel.
output[i*nChannels] = outputTwoChannels[0];
output[i*nChannels + 1] = outputTwoChannels[1];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment