giuliomoro@181: /* giuliomoro@181: * render.cpp giuliomoro@181: * giuliomoro@181: * Created on: Oct 24, 2014 giuliomoro@181: * Author: parallels giuliomoro@181: */ giuliomoro@181: giuliomoro@301: #include giuliomoro@181: #include giuliomoro@187: #include giuliomoro@181: #include giuliomoro@181: #include giuliomoro@181: #include giuliomoro@181: giuliomoro@224: float gFreq; giuliomoro@224: float gPhaseIncrement = 0; giuliomoro@224: bool gIsNoteOn = 0; giuliomoro@224: int gVelocity = 0; giuliomoro@224: float gSamplingPeriod = 0; giuliomoro@224: giuliomoro@226: void midiMessageCallback(MidiChannelMessage message, void* arg){ giuliomoro@226: if(arg != NULL){ giuliomoro@226: rt_printf("Message from midi port %d: ", *(int*)arg); giuliomoro@226: } giuliomoro@224: message.prettyPrint(); giuliomoro@224: if(message.getType() == kmmNoteOn){ giuliomoro@224: gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; giuliomoro@224: gVelocity = message.getDataByte(1); giuliomoro@224: gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod; giuliomoro@224: gIsNoteOn = gVelocity > 0; giuliomoro@224: rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity); giuliomoro@224: } giuliomoro@224: } giuliomoro@181: // setup() is called once before the audio rendering starts. giuliomoro@181: // Use it to perform any initialisation and allocation which is dependent giuliomoro@181: // on the period size or sample rate. giuliomoro@181: // giuliomoro@181: // userData holds an opaque pointer to a data structure that was passed giuliomoro@181: // in from the call to initAudio(). giuliomoro@181: // giuliomoro@181: // Return true on success; returning false halts the program. giuliomoro@181: Midi midi; giuliomoro@226: int gMidiPort0 = 0; giuliomoro@301: bool setup(BelaContext *context, void *userData) giuliomoro@181: { giuliomoro@226: midi.readFrom(gMidiPort0); giuliomoro@226: midi.writeTo(gMidiPort0); giuliomoro@224: midi.enableParser(true); giuliomoro@226: midi.setParserCallback(midiMessageCallback, &gMidiPort0); giuliomoro@181: if(context->analogFrames == 0) { giuliomoro@226: rt_printf("Error: this example needs the analog I/O to be enabled\n"); giuliomoro@181: return false; giuliomoro@181: } giuliomoro@224: gSamplingPeriod = 1/context->audioSampleRate; giuliomoro@181: return true; giuliomoro@181: } giuliomoro@181: giuliomoro@181: // render() is called regularly at the highest priority by the audio engine. giuliomoro@181: // Input and output are given from the audio hardware and the other giuliomoro@181: // ADCs and DACs (if available). If only audio is available, numMatrixFrames giuliomoro@181: // will be 0. giuliomoro@181: giuliomoro@181: giuliomoro@181: enum {kVelocity, kNoteOn, kNoteNumber}; giuliomoro@301: void render(BelaContext *context, void *userData) giuliomoro@181: { giuliomoro@224: // one way of getting the midi data is to parse them yourself giuliomoro@224: // (you should set midi.enableParser(false) above): giuliomoro@224: /* giuliomoro@224: static midi_byte_t noteOnStatus = 0x90; //on channel 1 giuliomoro@181: static int noteNumber = 0; giuliomoro@181: static int waitingFor = kNoteOn; giuliomoro@184: static int playingNote = -1; giuliomoro@197: int message; giuliomoro@181: while ((message = midi.getInput()) >= 0){ giuliomoro@191: rt_printf("%d\n", message); giuliomoro@181: switch(waitingFor){ giuliomoro@181: case kNoteOn: giuliomoro@181: if(message == noteOnStatus){ giuliomoro@181: waitingFor = kNoteNumber; giuliomoro@181: } giuliomoro@181: break; giuliomoro@181: case kNoteNumber: giuliomoro@181: if((message & (1<<8)) == 0){ giuliomoro@181: noteNumber = message; giuliomoro@181: waitingFor = kVelocity; giuliomoro@181: } giuliomoro@181: break; giuliomoro@181: case kVelocity: giuliomoro@181: if((message & (1<<8)) == 0){ giuliomoro@184: int _velocity = message; giuliomoro@181: waitingFor = kNoteOn; giuliomoro@184: // "monophonic" behaviour, with priority to the latest note on giuliomoro@184: // i.e.: a note off from a previous note does not stop the current note giuliomoro@184: // still you might end up having a key down and no note being played if you pressed and released another giuliomoro@184: // key in the meantime giuliomoro@184: if(_velocity == 0 && noteNumber == playingNote){ giuliomoro@181: noteOn = false; giuliomoro@184: playingNote = -1; giuliomoro@184: velocity = _velocity; giuliomoro@184: } else if (_velocity > 0) { giuliomoro@184: noteOn = true; giuliomoro@184: velocity = _velocity; giuliomoro@184: playingNote = noteNumber; giuliomoro@184: f0 = powf(2, (playingNote-69)/12.0f) * 440; giuliomoro@184: phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; giuliomoro@184: } giuliomoro@181: rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity); giuliomoro@181: } giuliomoro@181: break; giuliomoro@181: } giuliomoro@181: } giuliomoro@199: */ giuliomoro@224: /* giuliomoro@197: int num; giuliomoro@197: //alternatively, you can use the built-in parser (only processes channel messages at the moment). giuliomoro@197: while((num = midi.getParser()->numAvailableMessages()) > 0){ giuliomoro@197: static MidiChannelMessage message; giuliomoro@197: message = midi.getParser()->getNextChannelMessage(); giuliomoro@197: message.prettyPrint(); giuliomoro@199: if(message.getType() == kmmNoteOn){ giuliomoro@199: f0 = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; giuliomoro@199: velocity = message.getDataByte(1); giuliomoro@199: phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; giuliomoro@199: noteOn = velocity > 0; giuliomoro@224: rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity); giuliomoro@199: } giuliomoro@197: } giuliomoro@224: */ giuliomoro@224: // the following block toggles the LED on an Owl pedal giuliomoro@224: // and asks the pedal to return the status of the LED giuliomoro@224: // using MIDI control changes giuliomoro@191: for(unsigned int n = 0; n < context->analogFrames; n++){ giuliomoro@191: static int count = 0; giuliomoro@191: static bool state = 0; andrewm@308: analogWriteOnce(context, n, 1, state); giuliomoro@191: if(count % 40000 == 0){ giuliomoro@191: state = !state; giuliomoro@224: midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status giuliomoro@191: midi.writeOutput(bytes, 6); giuliomoro@191: } giuliomoro@199: count++; giuliomoro@199: } giuliomoro@199: for(unsigned int n = 0; n < context->audioFrames; n++){ giuliomoro@224: if(gIsNoteOn == 1){ giuliomoro@181: static float phase = 0; giuliomoro@224: phase += gPhaseIncrement; giuliomoro@181: if(phase > 2 * M_PI) giuliomoro@181: phase -= 2 * M_PI; giuliomoro@224: float value = sinf(phase) * gVelocity/128.0f; andrewm@308: audioWrite(context, n, 0, value); andrewm@308: audioWrite(context, n, 1, value); giuliomoro@181: } else { andrewm@308: audioWrite(context, n, 0, 0); andrewm@308: audioWrite(context, n, 1, 0); giuliomoro@181: } giuliomoro@181: } giuliomoro@181: } giuliomoro@181: giuliomoro@181: // cleanup() is called once at the end, after the audio has stopped. giuliomoro@181: // Release any resources that were allocated in setup(). giuliomoro@181: giuliomoro@301: void cleanup(BelaContext *context, void *userData) giuliomoro@181: { giuliomoro@181: giuliomoro@181: }