/* * $Header: /home/dto/octal/RCS/squaregen.c,v 1.11 2000/07/19 08:00:06 dto Exp dto $ * (C) 2000 David O'Toole $Date: 2000/07/19 08:00:06 $ * * Simple Square Wave Generator Machine for GNU OCTAL. Block-oriented output. * This is intended as a working example of how to write a machine for the OCTAL API. * It is not really intended for use in songs, as it is not very pretty-sounding. * You can also use C++ if you prefer; use ox_wrappers (see the Developer's Guide) * * $Revision: 1.11 $ * * This software is distributed under the terms of the * GNU General Public License (GPL). Read the included file * COPYING for more information. * */ /* static const char rcsid[]="$Id: squaregen.c,v 1.11 2000/07/19 08:00:06 dto Exp dto $"; */ #include "machine.h" // OCTAL machine interface #include #include #include #include /* some info about my machine type, to be passed to OCTAL during ox_init() */ enum {ix_note = 0, ix_vol=1}; /* indexes of parameters in an event */ enum {my_track = 0 }; /* we only have one track for now */ enum {my_num_params = 2}; param_spec my_params[] = { { OX_FORMAT_NOTE, OX_WIDGET_SLIDER, "note", "Which note to play.", 0, NOTE_RANGE, 0 }, { OX_FORMAT_SMALL, OX_WIDGET_SLIDER, "vol", "Volume: 00-FE", 0x00, 0xFE, 0x80, } }; typedef struct _my_state { freq pitch; /* calculated from note param whenever it changes */ samp vol; /* calculated from vol param whenever it changes */ samp phase; /* current phase of wave */ int play; /* use this to tell when we have noteoff */ } my_state; /* initialize the library and tell OCTAL about yourself */ int ox_init(machine_type* t) { t->long_name = "Sine Wave Generator"; t->short_name = "sinewave"; t->max_tracks = 1; t->input_channels = 0; t->output_channels = 1; t->num_params = my_num_params; t->param_specs = my_params; /* give it the address of my array of param structs */ return(1); } void ox_create(machine* m) { my_state* s; s = m->pkg->alloc(sizeof(my_state)); s->vol = 0x80; s->play = 0; /* don't start until you get a note */ m->state = (void*)s; } /* free the memory when you destroy machines */ void ox_destroy(machine* m) { m->pkg->free(m->state); } void ox_update(machine* m, int track, int param_index, param value) { my_state *s = (my_state*)m->state; switch(param_index) { case ix_note: if (value == OX_NOTE_OFF) s->play = 0; else { s->pitch = m->pkg->note2freq(value); s->play = 1; } break; case ix_vol: s->vol = ((float)value) / 255.0; /* scale from 0x00..0xFE to floating point 0..1 */ break; } } void ox_desc(char* dest, int which_param, param value) { float x; int percent; switch (which_param) { case ix_note: strcpy(dest, "$"); break; case ix_vol: x = ((float)value) / 255.0; /* scale from 0x00..0xFE to floating point 0..1 */ percent = (int)(x * 100); sprintf(dest, "%d%%", percent); break; default: sprintf(dest, "ERROR"); } } int ox_work(machine* m, int block_size) { my_state* s; samp* mout; /* mono output for this machine */ freq phaseinc; freq phase; samp vol; int i; s = (my_state*)m->state; /* grab our state data address */ mout = m->lout; /* since lout=rout for mono machines, I could use either */ phaseinc = (freq)(s->pitch/44100.0); phase = s->phase; vol = s->vol; if (!s->play) return (0); /* nothing to generate */ for (i=0; i < block_size; i++) { if (phase >= 1.0) phase -= 1.0; mout[i] = vol * sin(phase * 3.14157); phase += phaseinc; } //s->play = 0; s->phase = phase; /* put state data back in state struct */ return(1); /* generated successfully */ } void ox_track(machine* m, int change) { /* leave this blank for effects, or if you don't have polyphony */ } /* End $Source: /home/dto/octal/RCS/squaregen.c,v $ */