andrewm@268: /*
andrewm@268:  * render.cpp
andrewm@268:  *
andrewm@268:  *  Created on: Oct 24, 2014
andrewm@268:  *      Author: parallels
andrewm@268:  */
andrewm@268: 
andrewm@268: 
giuliomoro@301: #include <Bela.h>
andrewm@268: #include <Utilities.h>
andrewm@268: 
andrewm@268: const int kStepLengthSlow = 1000;
andrewm@268: const int kStepLengthFast = 500;
andrewm@268: 
andrewm@268: int gStepLengthSamples = kStepLengthSlow;
andrewm@268: 
andrewm@268: const int gPinA1 = P8_27;
andrewm@268: const int gPinA2 = P8_28;
andrewm@268: const int gPinB1 = P8_29;
andrewm@268: const int gPinB2 = P8_30;
andrewm@268: const int gPinServo = P9_16;
andrewm@268: 
andrewm@268: int gStepCounter = 0;
andrewm@268: int gPhase = 0;
andrewm@268: 
andrewm@268: int gServoCounter = 0;
andrewm@268: 
andrewm@268: 
andrewm@268: enum {
andrewm@268: 	kStateMoveRight1 = 0,
andrewm@268: 	kStateMoveLeft1,
andrewm@268: 	kStateMoveRight2,
andrewm@268: 	kStateMoveLeft2,
andrewm@268: 	kStateMoveRight3,
andrewm@268: 	kStateMoveLeft3,
andrewm@268: 	kStateSpin,
andrewm@268: 	kStateMax
andrewm@268: };
andrewm@268: 
andrewm@268: int gState = 0;
andrewm@268: int gStateCounter = 0;
andrewm@268: 
andrewm@268: // setup() is called once before the audio rendering starts.
andrewm@268: // Use it to perform any initialisation and allocation which is dependent
andrewm@268: // on the period size or sample rate.
andrewm@268: //
andrewm@268: // userData holds an opaque pointer to a data structure that was passed
andrewm@268: // in from the call to initAudio().
andrewm@268: //
andrewm@268: // Return true on success; returning false halts the program.
andrewm@268: 
giuliomoro@301: bool setup(BelaContext *context, void *userData)
andrewm@268: {	
andrewm@268: 	// This project makes the assumption that the audio and digital
andrewm@268: 	// sample rates are the same. But check it to be sure!
andrewm@268: 	if(context->audioFrames != context->digitalFrames) {
andrewm@268: 		rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n");
andrewm@268: 		return false;
andrewm@268: 	}
andrewm@268: 	
andrewm@310: 	pinMode(context, 0, gPinA1, OUTPUT);
andrewm@310: 	pinMode(context, 0, gPinA2, OUTPUT);
andrewm@310: 	pinMode(context, 0, gPinB1, OUTPUT);
andrewm@310: 	pinMode(context, 0, gPinB2, OUTPUT);
andrewm@310: 	pinMode(context, 0, gPinServo, OUTPUT);
andrewm@268: 		
andrewm@268: 	return true;
andrewm@268: }
andrewm@268: 
andrewm@268: // render() is called regularly at the highest priority by the audio engine.
andrewm@268: // Input and output are given from the audio hardware and the other
andrewm@268: // ADCs and DACs (if available). If only audio is available, numMatrixFrames
andrewm@268: // will be 0.
andrewm@268: 
giuliomoro@301: void render(BelaContext *context, void *userData)
andrewm@268: {
andrewm@268: 	for(unsigned int n = 0; n < context->audioFrames; n++) {
andrewm@268: 		if(gPhase == 0 || gPhase == 1) {
andrewm@308: 			digitalWriteOnce(context, n, gPinB1, HIGH);
andrewm@308: 			digitalWriteOnce(context, n, gPinB2, LOW);
andrewm@268: 		}
andrewm@268: 		else {
andrewm@308: 			digitalWriteOnce(context, n, gPinB1, LOW);
andrewm@308: 			digitalWriteOnce(context, n, gPinB2, HIGH);			
andrewm@268: 		}
andrewm@268: 		
andrewm@268: 		if(gPhase == 1 || gPhase == 2) {
andrewm@308: 			digitalWriteOnce(context, n, gPinA1, HIGH);
andrewm@308: 			digitalWriteOnce(context, n, gPinA2, LOW);
andrewm@268: 		}
andrewm@268: 		else {
andrewm@308: 			digitalWriteOnce(context, n, gPinA1, LOW);
andrewm@308: 			digitalWriteOnce(context, n, gPinA2, HIGH);			
andrewm@268: 		}
andrewm@268: 		
andrewm@268: 		if(--gServoCounter > 0) 
andrewm@308: 			digitalWriteOnce(context, n, gPinServo, HIGH);
andrewm@268: 		else
andrewm@308: 			digitalWriteOnce(context, n, gPinServo, LOW);
andrewm@268: 		
andrewm@268: 		if(++gStepCounter >= gStepLengthSamples) {
andrewm@268: 			gStateCounter++;
andrewm@268: 			
andrewm@268: 			switch(gState) {
andrewm@268: 				case kStateMoveRight1:
andrewm@268: 				case kStateMoveRight2:
andrewm@268: 				case kStateMoveRight3:
andrewm@268: 					gPhase = (gPhase + 1) & 3;
andrewm@268: 					break;
andrewm@268: 				case kStateMoveLeft1:
andrewm@268: 				case kStateMoveLeft2:
andrewm@268: 				case kStateMoveLeft3:				
andrewm@268: 					gPhase = (gPhase + 3) & 3;	
andrewm@268: 					break;
andrewm@268: 				case kStateSpin:
andrewm@268: 					gPhase = (gPhase + 1) & 3;
andrewm@268: 					break;		
andrewm@268: 			}
andrewm@268: 			
andrewm@268: 			if(gState == kStateSpin) {
andrewm@268: 				if(gStateCounter >= 48) {
andrewm@268: 					gStateCounter = 0;
andrewm@268: 					gState = 0;
andrewm@268: 					gStepLengthSamples = kStepLengthSlow;
andrewm@268: 				}				
andrewm@268: 			}
andrewm@268: 			else {
andrewm@268: 				if(gStateCounter >= 16) {
andrewm@268: 					gStateCounter = 0;
andrewm@268: 					gState++;
andrewm@268: 					if(gState & 1)
andrewm@268: 						gServoCounter = 120;
andrewm@268: 					else
andrewm@268: 						gServoCounter = 80;
andrewm@268: 					if(gState == kStateSpin)
andrewm@268: 						gStepLengthSamples = kStepLengthFast;
andrewm@268: 				}
andrewm@268: 			}
andrewm@268: 			
andrewm@268: 			gStepCounter = 0;
andrewm@268: 		}
andrewm@268: 	}
andrewm@268: }
andrewm@268: 
andrewm@268: // cleanup() is called once at the end, after the audio has stopped.
andrewm@268: // Release any resources that were allocated in setup().
andrewm@268: 
giuliomoro@301: void cleanup(BelaContext *context, void *userData)
andrewm@268: {
andrewm@268: 	
andrewm@268: }