// // Copyright: Copyright 2003 Craig Stuart Sapp // Programmer: Craig Stuart Sapp // Creation Date: Thu Jan 30 02:09:41 PST 2003 // Last Modified: Thu Jan 30 04:36:19 PST 2003 // Filename: henon.c // Web Address: http://peabody.sapp.org/class/dmp2/lab/henon/henon.c // Syntax: C; Max4/MSP2 External Object; CodeWarrior 6.0 // OS: Mac OS 9; PPC // // Description: Fractal melody generator using the Henon map: // y[n] = 1 + a y[n-1]^2 + b y[n-2] // #include "ext.h" typedef struct { t_object max_data; // Max/MSP data, MUST come first in struct double y; // current sequence output double yy; // last sequence output double starty; // starting y value; double startyy; // starting yy value; double alpha; // alpha parameter for henon map double beta; // beta parameter for henon map double alphamin; // minimum range for alpha double alphamax; // maximum range for alpha double betamin; // minimum range for beta double betamax; // A now-defunct video tape format long minnote; // The minimum note number which will be output long maxnote; // The maximum note number which will be output void* output; // output bang function pointer } MyObject; void* object_data = NULL; // function declarations: void* create_object (long alphainit, long betainit); void InputAlpha (MyObject* mo, long value); void InputAlpha (MyObject* mo, long value); void InputBang (MyObject* mo); double henonmap (double y, double yy, double alpha, double beta); double scaleDataToRange (long value, double min, double max); long midilimit (long value); ///////////////////////////////////////////////////////////////////////// // // Initialization functions // ////////////////////////////// // // main -- called once when the object is created in a patcher window. // void main(void) { setup((t_messlist**)&object_data, (method)create_object, NULL, sizeof(MyObject), NULL, A_DEFLONG, A_DEFLONG, A_NOTHING); addbang((method)InputBang); // inlet 1 addinx ((method)InputAlpha, 2); // inlet 2 addinx ((method)InputBeta, 1); // inlet 3 } ////////////////////////////// // // create_object -- create the data storage for the mydiff object and // and setup input 1. // void* create_object(long alphainit, long betainit) { MyObject* mo = (MyObject*)newobject(object_data); mo->starty = 0.0; mo->startyy = 0.0; mo->y = mo->starty; mo->yy = mo->startyy; mo->alphamin = -2.0; mo->alphamax = -1.0; mo->betamin = -0.25; mo->betamax = 0.25; mo->alpha = scaleDataToRange(alphainit, mo->alphamin, mo->alphamax); mo->beta = scaleDataToRange(betainit, mo->betamin, mo->betamax); mo->minnote = 21; mo->maxnote = 109; mo->output = intout(mo); // outlet 1 intin(mo, 1); // inlet 2 intin(mo, 2); // inlet 3 return mo; } ///////////////////////////////////////////////////////////////////////// // // Behavior functions // ////////////////////////////// // // InputAlpha -- behavior of the object when a new number comes // in on inlet 1. When a number is received, calculate // the alpha parameter for the map, and reset the starting // point for the sequence. // void InputAlpha(MyObject* mo, long value) { mo->alpha = scaleDataToRange(value, mo->alphamin, mo->alphamax); mo->y = mo->starty; mo->yy = mo->startyy; } ////////////////////////////// // // InputBeta -- behavior of the object when a new number comes // in on inlet 2. When a number is received, calculate // the beta parameter for the map, and reset the starting // point for the sequence. // void Input2(MyObject* mo, long value) { mo->beta = scaleDataToRange(value, mo->betamin, mo->betamax); mo->y = mo->starty; mo->yy = mo->startyy; } ////////////////////////////// // // InputBang -- behavior of the object when a "bang" message is received. // void InputBang(MyObject* mo) { double newy; long midinote; // calculate the next value in the sequence and store it newy = henonmap(mo->y, mo->yy, mo->alpha, mo->beta); mo->yy = mo->y; mo->y = newy; // scale the new y value to the range from 0 to 127 for output midinote = midilimit((int)((newy+1.0)/2.0*127.0 + 0.5)); // only bang a new output if the new note value is in range if ((midinote > mo->minnote) && (midinote < mo->maxnote)) { outlet_int(mo->output, midinote); } } ///////////////////////////////////////////////////////////////////////// // // Non-interface functions: // ////////////////////////////// // // henonmap -- generate the next value in the Henon map. // double henonmap(double y, double yy, double alpha, double beta) { return 1.0 + alpha * y * y + beta * yy; } ////////////////////////////// // // midilimit -- limit a number to the range from 0 to 127. // if the input is less than 0, return 0. // if the input is greater than 127, return 127. // long midilimit(long value) { if (value < 0) return 0; if (value > 127) return 127; return value; } ////////////////////////////// // // scaleDataToRange -- convert a MIDI note number in the range from 0 to 127 // into a floating-point number in the range from min to max. // double scaleDataToRange(long value, double min, double max) { return value/127.0 * (max - min) + min; }