view scripts/hvresources/render.cpp @ 198:62f6269f4b3e

Added support for MidiIn to heavy (with example patch and subpatches).
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 05 Feb 2016 06:17:35 +0000
parents 3b8a28edae41
children c768ed1055b0
line wrap: on
line source
/*
 * render.cpp
 *
 *  Template render.cpp file for on-board heavy compiling
 *
 *  N.B. this is currently *not* compatible with foleyDesigner source files!
 *
 *  Created on: November 5, 2015
 *
 *  Christian Heinrichs
 *
 */

#include <BeagleRT.h>
#include <Midi.h>
#include <cmath>
#include "../include/Utilities.h"
#include "Heavy_bbb.h"
#include <string.h>
#include <stdlib.h>
#include <string.h>
/*
 *	HEAVY CONTEXT & BUFFERS
 */

Hv_bbb *gHeavyContext;
float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL;
int gHvInputChannels = 0, gHvOutputChannels = 0;

float gInverseSampleRate;

/*
 *	HEAVY FUNCTIONS
 */

void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) {
  printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString);
}

static void sendHook(
    double timestamp, // in milliseconds
    const char *receiverName,
    const HvMessage *const m,
    void *userData) {

  // only react to messages sent to receivers named "hello"
  if (!strncmp(receiverName, "hello", 5)) {
  }

}

/*
 * SETUP, RENDER LOOP & CLEANUP
 */

Midi midi;
bool setup(BeagleRTContext *context, void *userData)	{

	/* HEAVY */

	gHeavyContext = hv_bbb_new(context->audioSampleRate);

	gHvInputChannels = hv_getNumInputChannels(gHeavyContext);
	gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext);

	rt_printf("Starting Heavy context with %d input channels and %d output channels\n",
			  gHvInputChannels, gHvOutputChannels);

	if(gHvInputChannels != 0) {
		gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float));
	}
	if(gHvOutputChannels != 0) {
		gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float));
	}

	gInverseSampleRate = 1.0 / context->audioSampleRate;

	// Set heavy print hook
	hv_setPrintHook(gHeavyContext, &printHook);
	// Set heavy send hook
	hv_setSendHook(gHeavyContext, sendHook);

	midi.readFrom(0);
	midi.writeTo(0);
	midi.enableParser(true);
	return true;
}


void render(BeagleRTContext *context, void *userData)
{

	// De-interleave the data
	if(gHvInputBuffers != NULL) {
		for(int n = 0; n < context->audioFrames; n++) {
			for(int ch = 0; ch < gHvInputChannels; ch++) {
				if(ch >= context->audioChannels+context->analogChannels) {
					// THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING
					// 'sensor' outputs from routing channels of dac~ are passed through here
					break;
				} else {
					// If more than 2 ADC inputs are used in the pd patch, route the analog inputs
					// i.e. ADC3->analogIn0 etc. (first two are always audio inputs)
					if(ch >= context->audioChannels)	{
						int m = n/2;
						float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)];
						gHvInputBuffers[ch * context->audioFrames + n] = mIn;
					} else {
						gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch];
					}
				}
			}
		}
	}

	// replacement for bang~ object
	//hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b");
	{
		int num;
		while((num = midi.getParser()->numAvailableMessages()) > 0){
			static MidiChannelMessage message;
			message = midi.getParser()->getNextChannelMessage();
			switch(message.getType()){
			case kmmNoteOn: {
//					message.prettyPrint();
					float noteNumber = message.getDataByte(0);
					float velocity = message.getDataByte(1);
					float channel = message.getChannel();
//					rt_printf("message: noteNumber: %f, velocity: %f, channel: %f\n", noteNumber, velocity, channel);
					hv_vscheduleMessageForReceiver(gHeavyContext, "hv_notein", 0, "fff", noteNumber, velocity, channel);
				}
				break;
			case kmmControlChange: {
				hv_vscheduleMessageForReceiver(gHeavyContext, "hv_ctlin", 0, "fff",
						(float)message.getDataByte(1), (float)message.getDataByte(0), (float)message.getChannel());
				}
				break;
			case kmmProgramChange:
				hv_vscheduleMessageForReceiver(gHeavyContext, "hv_pgmin", 0, "ff",
						(float)message.getDataByte(0), (float)message.getChannel());
				break;
			}
		}
	}
//	hv_sendFloatToReceiver(gHeavyContext, "notein", 1.123f);


	hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames);

	// Interleave the output data
	if(gHvOutputBuffers != NULL) {
		for(int n = 0; n < context->audioFrames; n++) {

			for(int ch = 0; ch < gHvOutputChannels; ch++) {
				if(ch >= context->audioChannels+context->analogChannels) {
					// THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING
					// they are the content of the 'sensor output' dac~ channels
				} else {
					if(ch >= context->audioChannels)	{
						int m = n/2;
						context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0);
					} else {
						context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n];
					}
				}
			}
		}
	}

}


void cleanup(BeagleRTContext *context, void *userData)
{

	hv_bbb_free(gHeavyContext);
	if(gHvInputBuffers != NULL)
		free(gHvInputBuffers);
	if(gHvOutputBuffers != NULL)
		free(gHvOutputBuffers);

}