From 2403b07ec0a7586108798271fa04eb034445f51d Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 24 Dec 2012 15:39:35 +0100 Subject: updates to documentation, code cleanup, comments --- bytetunes.cpp | 249 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 132 insertions(+), 117 deletions(-) (limited to 'bytetunes.cpp') diff --git a/bytetunes.cpp b/bytetunes.cpp index 470d51f..ce9f557 100644 --- a/bytetunes.cpp +++ b/bytetunes.cpp @@ -1,13 +1,28 @@ +/* + * bytebeat.cpp - parse and play bytebeat songs + * Date: December 2012 + * Author: bnewbold@robocracy.org + * + * For use with libmaple, to run on ARM Cortex-M3 microcontrollers. + * + * This version only parses tunes in "perfect" S-EXPR format. + * + * Outputs PWM audio on pin 16 and listens on SerialUSB for new tunes. + * + * See TODO file for problems. + * + * This file is released under the General Public License version 3 (GPLv3). + */ #include "wirish.h" -//#include #include -//#include -#define DEFAULT "(& (>> t 6) (& (* 2 t) (>> t 1)))" -#define NUMNODE 160 -#define PWM_OUT_PIN 33 +#define DEFAULT_TUNE "(& (>> t 6) (& (* 2 t) (>> t 1)))" +#define NUMNODE 160 +#define LED_PIN 33 +#define MONITOR_PIN 31 +// S-EXPR data structure stuff struct node { char type; char cval; @@ -15,73 +30,59 @@ struct node { struct node *lval; struct node *rval; }; +struct node *new_node(char type, char cval, unsigned int ival, + struct node *lval, struct node *rval); +static struct node active_table[NUMNODE]; +static struct node node_table[NUMNODE]; +static int newest_node = 0; +// S-EXPR parser stuff int isdigit(char); void print_sexpr(struct node *sexpr); -int execute(struct node *sexpr, unsigned int t); int find_split(char* s, int start, int end); struct node *parse(char *s, int start, int end); -struct node *new_node(char type, char cval, unsigned int ival, - struct node *lval, struct node *rval); +int digtoi(char *s, int start, int end); -static struct node active_table[NUMNODE]; -static struct node node_table[NUMNODE]; -static int newest_node = 0; +// bytetune machine output stuff +int execute(struct node *sexpr, unsigned int t); node *machine; node *new_machine; void handler_sample(void); - -unsigned char sin_8bit(int counter, int period); -char inbuffer[256]; - -int sstrlen(char *s, int max); - HardwareTimer gen(1); HardwareTimer pwm(4); - int counter = 0; -int isdigit(char c) { - return (c >= '0' and c <= '9'); -} +// other stuff +char inbuffer[256]; +int inbuffer_index; +int sstrlen(char *s, int max); -/* -from math import sin -count = 64 -print [int(127+127*sin(3.14159268*2*i/count)) for i in range(count)] -*/ -unsigned char sine_lookup[] __FLASH__ = {127, 139, 151, 163, 175, 186, 197, 207, 216, - 225, 232, 239, 244, 248, 251, 253, 254, 253, 251, 248, 244, 239, 232, 225, - 216, 207, 197, 186, 175, 163, 151, 139, 126, 114, 102, 90, 78, 67, 56, 46, - 37, 28, 21, 14, 9, 5, 2, 0, 0, 0, 2, 5, 9, 14, 21, 28, 37, 46, 56, 67, 78, - 90, 102, 114}; +// ====================== primary control flow functions ====================== +// runs once at power up to configure hardware peripherals void setup() { int i; - pinMode(PWM_OUT_PIN, OUTPUT); - pinMode(31, OUTPUT); - pinMode(33, OUTPUT); - pinMode(16, PWM); - pinMode(4, OUTPUT); - digitalWrite(1, 1); - - // initialize with DEFAULT machines - machine = parse((char*)DEFAULT, 0, strlen((char*)DEFAULT)-1); + + // for monitoring interrupt loop length + pinMode(LED_PIN, OUTPUT); + pinMode(MONITOR_PIN, OUTPUT); + + // initialize with DEFAULT_TUNE + machine = parse((char*)DEFAULT_TUNE, 0, strlen((char*)DEFAULT_TUNE)-1); for (i=0;i "); + inbuffer_index = 0; while (1) { + // read in characters one at a time inbuffer[inbuffer_index] = SerialUSB.read(); + if (inbuffer[inbuffer_index] > 127) { + // if not an ASCII character ignore it + continue; + } SerialUSB.print(inbuffer[inbuffer_index]); - if (inbuffer[inbuffer_index] == 8) { - if (inbuffer_index > 0) { - inbuffer_index--; - } - } else if (inbuffer[inbuffer_index] == '\n' || + if (inbuffer[inbuffer_index] == '\n' || inbuffer[inbuffer_index] == '\r') { + // on submit, zero terminate the string and break out to parse inbuffer[inbuffer_index] = '\0'; SerialUSB.println(); break; - } else { - inbuffer_index++; } + inbuffer_index++; if (inbuffer_index == 256) { SerialUSB.println("\n\rInput too long!"); return; @@ -124,15 +127,17 @@ void loop() { } len = sstrlen(inbuffer, 256); if (len == 256 || len < 1) { + // too long or short SerialUSB.println("Invalid input!"); return; } + // ok, we're going to try parsing newest_node = 0; new_machine = parse(inbuffer, 0, len-2); if (new_machine == NULL) { return; } - // swap in new machine + // if we got this far, swap in the new machine gen.pause(); for (i=0;i 62) - //high = sine_lookup[0]; - high = 118; - else - high = sine_lookup[1+(int)(63*t)]; - - return (int)(high * weight + low * (1.0 - weight)); + // set LED and monitor line low + digitalWrite(LED_PIN, 0); + digitalWrite(MONITOR_PIN, 0); } -int sstrlen(char *s, int max) { - int i; - for (i=0; itype) { // atom @@ -265,6 +251,7 @@ int execute(struct node *sexpr, unsigned int t) { } else { SerialUSB.print("unexpected unary oper: "); SerialUSB.println(sexpr->cval); + return 127; } // binary case 'b': @@ -292,17 +279,18 @@ int execute(struct node *sexpr, unsigned int t) { default: SerialUSB.print("unexpected binary oper: "); SerialUSB.print(sexpr->cval); - return NULL; - // XXX: halt + return 127; } default: SerialUSB.print("execute: unknown type: "); SerialUSB.print(sexpr->type); - return NULL; - // XXX: halt + return 127; } } +// finds the seperating whitespace character between the two arguments to a +// binary S-EXPR operator +// returns either the index of the seperator or -1 if there was a problem int find_split(char *s, int start, int end) { int depth = 0; int i; @@ -316,19 +304,17 @@ int find_split(char *s, int start, int end) { if (depth < 0) { SerialUSB.print("parse: unmatched ')'\n"); return -1; - // XXX: fail } } if (depth > 0) { SerialUSB.print("parse: unmatched '('\n"); return -1; - // XXX: fail } SerialUSB.print("parse: could not find split\n"); return -1; - // XXX: fail } +// prints out the S-EXPR to SerialUSB void print_sexpr(struct node *sexpr) { char oper = '_'; char twice = 0; @@ -347,7 +333,8 @@ void print_sexpr(struct node *sexpr) { print_sexpr(sexpr->rval); SerialUSB.print(")"); } else { - SerialUSB.print("unexpected unary: "); + SerialUSB.println(); + SerialUSB.print("print_sexpr: unexpected unary: "); SerialUSB.println(sexpr->cval); } // binary operators @@ -371,21 +358,24 @@ void print_sexpr(struct node *sexpr) { print_sexpr(sexpr->rval); SerialUSB.print(')'); } else { - SerialUSB.print("unexpected binary: "); + SerialUSB.println(); + SerialUSB.print("print_sexpr: unexpected binary: "); SerialUSB.println(sexpr->cval); - // XXX: + return; } } } +// creates a new node struct in the node table struct node *new_node(char type, char cval, unsigned int ival, struct node *lval, struct node *rval) { struct node *n; newest_node++; if (newest_node >= NUMNODE) { - SerialUSB.print("node table overrun\n"); - // XXX: + SerialUSB.println(); + SerialUSB.println("node table overrun!"); + return NULL; } n = &node_table[newest_node]; n->type = type; @@ -396,18 +386,43 @@ struct node *new_node(char type, char cval, unsigned int ival, return n; } +// ====================== misc helper functions ====================== + +// "safe" string length. breaks on newline or NULL char, checks at most 'max' +// characters +int sstrlen(char *s, int max) { + int i; + for (i=0; i= '0' and c <= '9'); +} + +// libmaple-specific re-definition // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated objects that need libmaple may fail. __attribute__((constructor)) void premain() { init(); } -int main(void) { - setup(); - - while (true) { - loop(); - } - - return 0; -} -- cgit v1.2.3