aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE7
-rw-r--r--NOTES63
-rw-r--r--README18
-rw-r--r--TODO7
-rw-r--r--bytetunes.cpp249
-rwxr-xr-xbytetunes.py8
-rw-r--r--expr.py18
-rw-r--r--notes.txt25
-rwxr-xr-xsexpr.py16
-rw-r--r--sine_lookup.c18
10 files changed, 231 insertions, 198 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4b6a141
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,7 @@
+
+See the header comments for licensing information about each file. Any
+unspecified code and content is released to the public domain, globally, with
+no restrictions.
+
+bytetunes in the ./tunes directory are attributed to their authors, i'm unsure
+if such simple works are even covered under copyright.
diff --git a/NOTES b/NOTES
deleted file mode 100644
index 3228164..0000000
--- a/NOTES
+++ /dev/null
@@ -1,63 +0,0 @@
-
-opcodes
- note: no unary, increment, decrement
- arthithmetic: + - * / %
- bitwise: l r & | ^ ~
- "<<" is l, ">>" is r
- all are atoms or binary operators, so recursive compilation to a forth-like?
- order of ops:
- ~
- * / %
- + -
- << >>
- &
- ^
- |
-
-final console interface:
- #hashtag (exact) -> searches identica for tunes
- @username (exact) -> parses identica feed for tunes
- _1234... -> plays track from memory
- expression -> compiles and plays expression
- [else] -> searches greedily for a valid expression; if not found, ignores
-
-bytetros?
-
-
-
-void proc_token()
-
-int[32] itable
-struct { node* car, nlist* cdr } nlist
-tlist* tcons(token*, )
-
-struct { } token
-token[140] ttable
-struct { char type, int* iptr, int * } node
-ntable[140]
-int h2i(char*)
-
-
-s-exp method:
-tokenize: glom numbers
-preparse: match parens, return s-expr
-parse: turn into prefix notation
-validate: check against rules
-compile: optionally remove trivial identities ("~~") and evaluate static expressions
-
-general method:
-grammar parser, returns ast
-
-----------
-
-MACHINE:
-
-struct { char type, char cval, int ival, node* lval, node* rval } node
-
-types:
- n number
- v variable
- b binary operator
- u unary operator
-
-SEXP
diff --git a/README b/README
index fa407af..c75afd8 100644
--- a/README
+++ b/README
@@ -9,13 +9,24 @@
players for bytebeat music.
+./bin/bytetunes.sh is a shell wrapper to compile C tunes (with gcc) and play
+ them back (with aplay)
+
+./bytetunes.py is a python program to parse and play (to stdout/aplay) tunes in
+ "normal" C-syntax
+
+./bytetunes.cpp is an interactive microcontroller program (for libmaple and ARM
+ Cortex-M3 controllers) with PWM audio output that parses and plays tunes in
+ limited S-EXPR syntax
+
### Example Tunes
-the original (to me):
+The original (to me) UNIX one-liner:
echo "main(i){for(i=0;;i++)putchar((i*(i>>8|i>>9)&46&i>>8)^(i&i>>13|i>>6));}" | gcc -x c - && ./a.out | aplay
-my favorite (thus far):
+My favorite tune (thus far):
+
(t*9&t>>4|t*5&t>>7|t*3&t/1024)-1
### References
@@ -39,10 +50,9 @@ commentary, other:
http://countercomplex.blogspot.de/2011/06/16-byte-frontier-extreme-results-from.html
http://canonical.org/~kragen/bytebeat/
http://pouet.net/topic.php?which=8357
- "Discovering novel computer music techniques by exploring the space of short computer programs"
- http://arxiv.org/abs/1112.1368
http://royal-paw.com/2012/01/bytebeats-in-c-and-python-generative-symphonies-from-extremely-small-programs/
http://www.metafilter.com/111959/Todays-formulaic-music
+ http://arxiv.org/abs/1112.1368 "Discovering novel computer music techniques by exploring the space of short computer programs"
similar:
http://yaxu.org/haskell-hack/
diff --git a/TODO b/TODO
index f9c12bf..1946393 100644
--- a/TODO
+++ b/TODO
@@ -1,2 +1,5 @@
-- handle negative numbers
-- use libc tokenization?
+- all: handle negative numbers (unary '-' operator)
+- bytebeat.cpp: crude line editor: backspace, cursors, filter non-ascii chars
+- bytebeat.cpp: divide by zeros should not totally crash... catch HW exception? check args?
+- better README.html, incl. fritzig circuit
+- more tests
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 <stdio.h>
#include <string.h>
-//#include <stdlib.h>
-#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<NUMNODE;i++) {
active_table[i] = node_table[i];
}
- // configure PWM output
- pinMode(PWM_OUT_PIN, OUTPUT);
+ // configure PWM output on pin 16 (Timer 4, Channel 1)
+ pinMode(16, PWM); // primary PWM audio output
pwm.setMode(1, TIMER_PWM);
pwm.setPrescaleFactor(1);
- pwm.setOverflow(255); // 8-bit resolution
- pwm.setCompare(3, 128); // initialize to "zero"
-
+ pwm.setOverflow(255); // 8-bit resolution
+ pwm.setCompare(3, 128); // initialize to "zero"
// configure 8KHz ticker and interrupt handler
gen.pause();
- gen.setPeriod(125); // 8Khz
+ gen.setPeriod(125); // 8Khz
gen.setCompare(1, 1);
gen.setMode(1, TIMER_OUTPUT_COMPARE);
gen.attachInterrupt(1, handler_sample);
@@ -91,32 +92,34 @@ void setup() {
gen.resume();
}
-int inbuffer_index;
-
+// runs continuously, reading new machines from SerialUSB input
void loop() {
int len, i;
+
SerialUSB.println();
SerialUSB.println("Currently playing:");
print_sexpr(machine);
SerialUSB.println();
SerialUSB.println("Input a tune in exact s-expr syntax:");
SerialUSB.print("> ");
+
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<NUMNODE;i++) {
active_table[i] = node_table[i];
@@ -146,55 +151,32 @@ void loop() {
gen.resume();
}
+// gets called by 8KHz timer interrupt. pushes out the next audio sample to PWM
+// output
void handler_sample(void) {
- digitalWrite(33, 1);
- digitalWrite(31, 1);
- //pwm.setCompare(1, sin_8bit(counter, 799)); // 10Hz sine wave
+ // set LED and monitor line high (so we can check with a 'scope how long
+ // this function call lasts)
+ digitalWrite(LED_PIN, 1);
+ digitalWrite(MONITOR_PIN, 1);
+
+ // execute and write truncated result
pwm.setCompare(1, (0x000000FF & execute(machine, counter)));
- //pwmWrite(16, sin_8bit(counter, 800));
counter++;
- //SerialUSB.print('.');
- digitalWrite(33, 0);
- digitalWrite(31, 0);
-}
-unsigned char sin_8bit(int counter, int period) {
- int high, low;
- float t = (counter % period) / (float)period;
- float weight = t - (int)t;
- low = sine_lookup[(int)(63*t)];
- if (63*t > 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; i<max; i++) {
- if (s[i] == '\n' || s[i] == '\0') {
- return i+1;
- }
- }
- return max;
+int main(void) {
+ setup();
+ while (true) { loop(); }
+ return 0;
}
-int digtoi(char *s, int start, int end) {
- int num = 0;
- for(;start<=end;start++) {
- if (! isdigit(s[start])) {
- SerialUSB.print("parse: not a digit: ");
- SerialUSB.println(s[start]);
- return -1;
- }
- num = num*10 + (s[start] - '0');
- }
- return num;
-}
+// ====================== tune parsing and playback functions =================
+// does what it says; returns NULL if there is a problem
struct node *parse(char *s, int start, int end) {
struct node *lval, *rval;
char cval;
@@ -251,6 +233,10 @@ struct node *parse(char *s, int start, int end) {
return NULL;
}
+// calculates a single audio sample (index 't') from tune 'sexpr'.
+// returns an int, which should be truncated to 8bit length for playback
+// if there is a problem, tries to print out to SerialUSB and returns "zero"
+// value
int execute(struct node *sexpr, unsigned int t) {
switch (sexpr->type) {
// 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<max; i++) {
+ if (s[i] == '\n' || s[i] == '\0') {
+ return i+1;
+ }
+ }
+ return max;
+}
+
+// finds a (positive) integer.
+// returns -1 if there is a problem.
+int digtoi(char *s, int start, int end) {
+ int num = 0;
+ for(;start<=end;start++) {
+ if (! isdigit(s[start])) {
+ SerialUSB.print("parse: not a digit: ");
+ SerialUSB.println(s[start]);
+ return -1;
+ }
+ num = num*10 + (s[start] - '0');
+ }
+ return num;
+}
+
+int isdigit(char c) {
+ return (c >= '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;
-}
diff --git a/bytetunes.py b/bytetunes.py
index 597ef3a..53bfa0e 100755
--- a/bytetunes.py
+++ b/bytetunes.py
@@ -1,9 +1,15 @@
#!/usr/bin/env python
-from expr import *
+"""
+bytetunes.py
+
+small CLI wrapper around expr.py for parsing and playing bytebeat tunes.
+"""
import sys
+from expr import *
+
DEFAULT = "(t>>6)&(2*t)&(t>>1)"
def play(s):
diff --git a/expr.py b/expr.py
index 0336ddd..c19b2de 100644
--- a/expr.py
+++ b/expr.py
@@ -1,5 +1,9 @@
"""
+Crude bytetunes parsing and playback routines in python.
+
+Probably has lots of bugs; see TODO file.
+
PARENS: '(' (EXPR | ATOM) ')'
EXPR: (BINARY | PARENS | NOT)
BINARY: (ATOM | EXPR) BOPER (ATOM | EXPR)
@@ -140,6 +144,7 @@ def schemify(ast):
def test_parse():
"""
+ TODO
"""
def tokenize(s):
@@ -244,7 +249,8 @@ def test_preparse():
assert preparse(tokenize("()()()()()()")) == []
assert preparse(tokenize("(((((())))))")) == []
assert preparse(tokenize("(1 + (2 >> 3) / 5)")) == \
- [('PARENS', ('NUM', 1), ('OPER', '+'), ('PARENS', ('NUM', 2), ('OPER', 'r'), ('NUM', 3)), ('OPER', '/'), ('NUM', 5))]
+ [('PARENS', ('NUM', 1), ('OPER', '+'), ('PARENS', ('NUM', 2),
+ ('OPER', 'r'), ('NUM', 3)), ('OPER', '/'), ('NUM', 5))]
print "\tall passed!"
def test_parse():
@@ -260,8 +266,10 @@ def test_parse():
assert parse(preparse(tokenize("()"))) == tuple()
assert parse(preparse(tokenize("0"))) == ('ATOM', ('NUM', 0))
assert parse(preparse(tokenize("~1"))) == ('NOT', ('ATOM', ('NUM', 1)))
- assert parse(preparse(tokenize("~~1"))) == ('NOT', ('NOT', ('ATOM', ('NUM', 1))))
- assert parse(preparse(tokenize("~~t"))) == ('NOT', ('NOT', ('ATOM', ('VAR',))))
+ assert parse(preparse(tokenize("~~1"))) == \
+ ('NOT', ('NOT', ('ATOM', ('NUM', 1))))
+ assert parse(preparse(tokenize("~~t"))) == \
+ ('NOT', ('NOT', ('ATOM', ('VAR',))))
assert parse(preparse(tokenize("1<<1"))) == \
('BINARY', 'l', ('ATOM', ('NUM', 1)), ('ATOM', ('NUM', 1)))
assert parse(preparse(tokenize("1^1"))) == \
@@ -276,8 +284,10 @@ def test_parse():
assert parse(preparse(tokenize("1 ~"))) == "SHOULD FAIL"
except:
pass
- assert strmachine(parse(preparse(tokenize("1 + 2 * 3 ^ 5 | 6 & 7 >> 8 + ~ 9")))) == \
+ assert strmachine(parse(preparse(tokenize(
+ "1 + 2 * 3 ^ 5 | 6 & 7 >> 8 + ~ 9")))) == \
"(| (^ (+ 1 (* 2 3)) 5) (& 6 (>> 7 (+ 8 (~ 9)))))"
+ print "\tall passed!"
def test_tokenize():
print "------ test_tokenize"
diff --git a/notes.txt b/notes.txt
new file mode 100644
index 0000000..5935000
--- /dev/null
+++ b/notes.txt
@@ -0,0 +1,25 @@
+
+opcodes
+ note: no unary, increment, decrement
+ arthithmetic: + - * / %
+ bitwise: l r & | ^ ~
+ "<<" is l, ">>" is r
+ all are atoms or binary operators, so recursive compilation to a forth-like?
+ order of ops:
+ ~
+ * / %
+ + -
+ << >>
+ &
+ ^
+ |
+
+final console interface:
+ #hashtag (exact) -> searches twitter/identica for tunes
+ @username (exact) -> parses twitter/identica feed for tunes
+ _1234... -> plays track from memory
+ expression -> compiles and plays expression
+ <else> -> searches greedily for a valid expression; if not found, ignores
+
+bytetros?
+
diff --git a/sexpr.py b/sexpr.py
index baea66e..d508fe0 100755
--- a/sexpr.py
+++ b/sexpr.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
"""
-This code is intentionally very c-style
+This code is intentionally very c-style; it was written to make later
+development of microcontroller code faster.
"""
import sys
@@ -91,9 +92,11 @@ def strmachine(sexpr):
oper = '<'
if sexpr['cval'] == 'r':
oper = '>'
- return "(%s%s %s %s)" % (oper, oper, strmachine(sexpr['lval']), strmachine(sexpr['rval']))
+ return "(%s%s %s %s)" % (oper, oper, strmachine(sexpr['lval']),
+ strmachine(sexpr['rval']))
elif sexpr['cval'] in '+-*/^|&':
- return "(%s %s %s)" % (sexpr['cval'], strmachine(sexpr['lval']), strmachine(sexpr['rval']))
+ return "(%s %s %s)" % (sexpr['cval'], strmachine(sexpr['lval']),
+ strmachine(sexpr['rval']))
raise Exception("unexpected binary: %s" % sexpr['cval'])
def execute(sexpr, t):
@@ -146,7 +149,8 @@ def test_parse():
DEFAULT,
]
for t in tlist:
- assert strmachine(ezparse(t)) == t, "\n%s <- GOT\n%s <- EXPECTED" % (strmachine(ezparse(t)), t)
+ assert strmachine(ezparse(t)) == t, \
+ "\n%s <- GOT\n%s <- EXPECTED" % (strmachine(ezparse(t)), t)
flist = [
'',
'~',
@@ -157,7 +161,8 @@ def test_parse():
]
for f in flist:
try:
- assert strmachine(ezparse(t)) == "SHOULDFAIL", "%s <- SHOULD HAVE FAILED"% t
+ assert strmachine(ezparse(t)) == "SHOULDFAIL", \
+ "%s <- SHOULD HAVE FAILED"% t
except:
pass
print "passed all parse tests!"
@@ -184,3 +189,4 @@ def main():
if __name__=='__main__':
main()
+
diff --git a/sine_lookup.c b/sine_lookup.c
index 1d12f76..a6e41a5 100644
--- a/sine_lookup.c
+++ b/sine_lookup.c
@@ -1,7 +1,19 @@
+/*
+ * This crude interpolated sine lookup table implementation is useful for
+ * testing PWM audio output from microcontrollers.
+ *
+ * If you want something that will actually sound like a sine wave, you should
+ * bump up to 128 or more samples and higher bit resolution.
+ */
#include <stdio.h>
-
+/*
+# python generator code for the below table
+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[] = {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,
@@ -16,7 +28,8 @@ unsigned char sin_8bit(int counter, int period) {
float weight = (63*t) - (int)(63*t);
low = sine_lookup[(int)(63*t)];
if (63*t >= 62)
- high = sine_lookup[0];
+ //high = sine_lookup[0];
+ high = 118; // not sure why sine_lookup[0] creates a glitch...
else
high = sine_lookup[1+(int)(63*t)];
//printf("\tl=%d h=%d w=%f\n", low, high, weight);
@@ -29,3 +42,4 @@ void main() {
printf("%d\t%d\n", i, sin_8bit(i, 800));
}
}
+