chris@160: /* chris@160: * render.cpp chris@160: * chris@160: * Template render.cpp file for on-board heavy compiling chris@160: * chris@160: * N.B. this is currently *not* compatible with foleyDesigner source files! chris@160: * chris@160: * Created on: November 5, 2015 chris@160: * chris@160: * Christian Heinrichs chris@160: * chris@160: */ chris@160: giuliomoro@329: #include giuliomoro@198: #include chris@160: #include chris@160: #include "../include/Utilities.h" chris@160: #include "Heavy_bbb.h" chris@190: #include chris@190: #include chris@190: #include chris@160: /* chris@160: * HEAVY CONTEXT & BUFFERS chris@160: */ chris@160: chris@160: Hv_bbb *gHeavyContext; chris@160: float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL; chris@160: int gHvInputChannels = 0, gHvOutputChannels = 0; chris@160: chris@160: float gInverseSampleRate; chris@160: chris@160: /* chris@160: * HEAVY FUNCTIONS chris@160: */ chris@160: chris@160: void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) { chris@160: printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString); chris@160: } chris@160: chris@160: static void sendHook( chris@160: double timestamp, // in milliseconds chris@160: const char *receiverName, chris@160: const HvMessage *const m, chris@160: void *userData) { chris@160: chris@160: // only react to messages sent to receivers named "hello" chris@160: if (!strncmp(receiverName, "hello", 5)) { chris@160: } chris@160: chris@160: } chris@160: chris@160: /* chris@166: * SETUP, RENDER LOOP & CLEANUP chris@160: */ chris@160: giuliomoro@198: Midi midi; giuliomoro@329: bool setup(BelaContext *context, void *userData) { chris@160: chris@160: /* HEAVY */ chris@160: chris@160: gHeavyContext = hv_bbb_new(context->audioSampleRate); chris@160: chris@160: gHvInputChannels = hv_getNumInputChannels(gHeavyContext); chris@160: gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext); chris@160: chris@160: rt_printf("Starting Heavy context with %d input channels and %d output channels\n", chris@160: gHvInputChannels, gHvOutputChannels); chris@160: chris@160: if(gHvInputChannels != 0) { chris@160: gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float)); chris@160: } chris@160: if(gHvOutputChannels != 0) { chris@160: gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float)); chris@160: } chris@160: chris@160: gInverseSampleRate = 1.0 / context->audioSampleRate; chris@160: chris@160: // Set heavy print hook chris@160: hv_setPrintHook(gHeavyContext, &printHook); chris@160: // Set heavy send hook chris@160: hv_setSendHook(gHeavyContext, sendHook); chris@160: giuliomoro@198: midi.readFrom(0); giuliomoro@198: midi.writeTo(0); giuliomoro@198: midi.enableParser(true); chris@160: return true; chris@160: } chris@160: chris@160: giuliomoro@329: void render(BelaContext *context, void *userData) chris@160: { chris@160: chris@160: // De-interleave the data chris@160: if(gHvInputBuffers != NULL) { chris@160: for(int n = 0; n < context->audioFrames; n++) { chris@160: for(int ch = 0; ch < gHvInputChannels; ch++) { chris@160: if(ch >= context->audioChannels+context->analogChannels) { chris@160: // THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING chris@160: // 'sensor' outputs from routing channels of dac~ are passed through here chris@160: break; chris@160: } else { chris@160: // If more than 2 ADC inputs are used in the pd patch, route the analog inputs chris@160: // i.e. ADC3->analogIn0 etc. (first two are always audio inputs) chris@160: if(ch >= context->audioChannels) { chris@160: int m = n/2; chris@160: float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)]; chris@160: gHvInputBuffers[ch * context->audioFrames + n] = mIn; chris@160: } else { chris@160: gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch]; chris@160: } chris@160: } chris@160: } chris@160: } chris@160: } chris@160: chris@160: // replacement for bang~ object chris@160: //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b"); giuliomoro@198: { giuliomoro@198: int num; giuliomoro@289: unsigned int hvHashes[3]; giuliomoro@289: hvHashes[0] = hv_stringToHash("bela_notein"); giuliomoro@289: hvHashes[1] = hv_stringToHash("bela_ctlin"); giuliomoro@289: hvHashes[2] = hv_stringToHash("bela_pgmin"); giuliomoro@198: while((num = midi.getParser()->numAvailableMessages()) > 0){ giuliomoro@198: static MidiChannelMessage message; giuliomoro@198: message = midi.getParser()->getNextChannelMessage(); giuliomoro@198: switch(message.getType()){ giuliomoro@198: case kmmNoteOn: { giuliomoro@198: // message.prettyPrint(); giuliomoro@198: float noteNumber = message.getDataByte(0); giuliomoro@198: float velocity = message.getDataByte(1); giuliomoro@198: float channel = message.getChannel(); giuliomoro@198: // rt_printf("message: noteNumber: %f, velocity: %f, channel: %f\n", noteNumber, velocity, channel); giuliomoro@289: hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[0], 0, "fff", noteNumber, velocity, channel); giuliomoro@198: } giuliomoro@198: break; giuliomoro@198: case kmmControlChange: { giuliomoro@289: hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[1], 0, "fff", giuliomoro@198: (float)message.getDataByte(1), (float)message.getDataByte(0), (float)message.getChannel()); giuliomoro@198: } giuliomoro@198: break; giuliomoro@198: case kmmProgramChange: giuliomoro@289: hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[2], 0, "ff", giuliomoro@198: (float)message.getDataByte(0), (float)message.getChannel()); giuliomoro@198: break; giuliomoro@198: } giuliomoro@198: } giuliomoro@198: } giuliomoro@198: // hv_sendFloatToReceiver(gHeavyContext, "notein", 1.123f); giuliomoro@198: chris@160: chris@160: hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames); chris@160: chris@160: // Interleave the output data chris@160: if(gHvOutputBuffers != NULL) { chris@160: for(int n = 0; n < context->audioFrames; n++) { chris@160: chris@160: for(int ch = 0; ch < gHvOutputChannels; ch++) { chris@160: if(ch >= context->audioChannels+context->analogChannels) { chris@160: // THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING chris@160: // they are the content of the 'sensor output' dac~ channels chris@160: } else { chris@160: if(ch >= context->audioChannels) { chris@160: int m = n/2; chris@160: context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0); chris@160: } else { chris@160: context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n]; chris@160: } chris@160: } chris@160: } chris@160: } chris@160: } chris@160: chris@160: } chris@160: chris@160: giuliomoro@329: void cleanup(BelaContext *context, void *userData) chris@160: { chris@160: chris@160: hv_bbb_free(gHeavyContext); chris@160: if(gHvInputBuffers != NULL) chris@160: free(gHvInputBuffers); chris@160: if(gHvOutputBuffers != NULL) chris@160: free(gHvOutputBuffers); chris@160: chris@160: }