From cad2ccb2e73951ebcf323a142ee0063841d3b392 Mon Sep 17 00:00:00 2001 From: twobit Date: Wed, 8 Aug 2012 02:03:53 +0200 Subject: [PATCH] tune file reader (not working/done yet) --- synth/{make_freq_table.py => freq_table.py} | 0 synth/main.c | 146 +++++++++++++++++++- synth/simple.tune | 64 +++++++++ synth/synth.c | 106 +++++++++++++- synth/synth.h | 44 +++++- 5 files changed, 353 insertions(+), 7 deletions(-) rename synth/{make_freq_table.py => freq_table.py} (100%) create mode 100644 synth/simple.tune mode change 120000 => 100644 synth/synth.c mode change 120000 => 100644 synth/synth.h diff --git a/synth/make_freq_table.py b/synth/freq_table.py similarity index 100% rename from synth/make_freq_table.py rename to synth/freq_table.py diff --git a/synth/main.c b/synth/main.c index e699ac0..7bd195f 100644 --- a/synth/main.c +++ b/synth/main.c @@ -1,29 +1,165 @@ #include #include #include +#include #include #include "synth.h" +enum { MIXRATE = 8000000 / (6 * 64) }; + +static SDL_AudioSpec spec = { MIXRATE, AUDIO_U16SYS, 1, 0, 1024, }; + static void fill_buffer(void* userdata, Uint8* stream, int len) { - for(int i = 0; i < len / 2; i++) ((uint16_t*)stream)[i] = synth_mix() * 50; + for(int i = 0; i < len / 2; i++) { + uint16_t m = synth_mix(); + assert(m < 0x100); + ((uint16_t*)stream)[i] = m * 50; + } } -SDL_AudioSpec spec = { 8000000 / (3 * 64), AUDIO_U16SYS, 1, 0, 1024, }; +// this parser is a complete hack +// put i can't care less right now +static int parse_tune(const char* filename) { + char line[256]; + FILE* file = fopen(filename, "r"); + if(!file) return -1; -int main(int argc ,char** argv) { - synth_init(); + char wave_names[256][256]; + memset(wave_names, 0, sizeof(wave_names)); + int wave_counter = 0; + + + char inst_names[256][256]; + memset(inst_names, 0, sizeof(inst_names)); + int inst_counter = 0; + + + char pattern_names[256][256]; + memset(pattern_names, 0, sizeof(pattern_names)); + int pattern_counter = 0; + + + int state = 0; + int line_nr = 0; + while(fgets(line, 256, file)) { + line_nr++; + + // skip empty line + if(line[0] == '\n') continue; + + // comments + if(line[0] == '#') continue; + + if(state == 0) { + if(strcmp("[WAVETABLE]\n", line)) return line_nr; + state = 1; + } + else if(state == 1) { + if(line[0] == '[') { + if(strcmp("[INSTRUMENTS]\n", line)) return line_nr; + state = 2; + } + else if(isalpha(line[0])) { + sscanf(line, "%s", wave_names[wave_counter]); + } + else if(line[0] == '\t') { + int a, b; + if(sscanf(line + 1, "%u %u", &a, &b) != 2) return line_nr; + wave_table[wave_counter][0] = a; + wave_table[wave_counter][1] = b; + wave_counter++; + } + else return line_nr; + } + else if(state == 2) { + if(line[0] == '[') { + if(strcmp("[PATTERNS]\n", line)) return line_nr; + state = 3; + } + else { + char wave_name[256]; + int pw, ps, d; + if(sscanf(line, "%s %u %u %u %s", + inst_names[inst_counter], &pw, &ps, &d, + wave_name) != 5) return line_nr; + + instruments[inst_counter].pulse_width = pw; + instruments[inst_counter].pulse_sweep = ps; + instruments[inst_counter].decay = d; + int i; + for(i = 0; i < 256; i++) + if(strcmp(wave_names[i], wave_name) == 0) break; + if(i == 256) return line_nr; + instruments[inst_counter].wave_table_pos = i; + inst_counter++; + } + } + else if(state == 3) { + if(line[0] == '[') { + if(strcmp("[PATTERNTABLE]\n", line)) return line_nr; + state = 4; + } + else { + if(!isalpha(line[0])) return line_nr; + sscanf(line, "%s", pattern_names[wave_counter]); + for(int i = 0; i < pattern_length && fgets(line, 256, file); i++) { + if(line[0] != '\t') return line_nr; + char* p = strch("aabccddeffgg" ,line[1]); + // TODO + if(p) { + patterns[pattern_counter][i][0] = line - p + (line[2] == '#') + (line[3] - '0') * 12; + int a; + sscanf(line + 4, "") + + patterns[pattern_counter][i][1] = a; + } + + } + pattern_counter++; + } + + + + } + else { + + + + } + } + if(state =! 4) return line_nr; + + + fclose(file); + return 0; +} + + + + +int main(int argc, char** argv) { + if(argc != 2) { + printf("usage: %s tunefile\n", argv[0]); + return 0; + } + + int error = parse_tune(argv[1]); + if(error != 0) { + fprintf(stderr, "%d: parsing error\n", error); + return 1; + } spec.callback = &fill_buffer; if(SDL_OpenAudio(&spec, &spec) < 0) { fprintf(stderr, "ERROR"); exit(1); } - printf("freq = %d\n", spec.freq); SDL_PauseAudio(0); + puts("playing..."); getchar(); diff --git a/synth/simple.tune b/synth/simple.tune new file mode 100644 index 0000000..de4262b --- /dev/null +++ b/synth/simple.tune @@ -0,0 +1,64 @@ +[WAVETABLE] + +bass00 + 0 3 + 0 1 + 255 255 + +bass01 + 0 2 + 255 255 + + + +[INSTRUMENTS] + +bass00 32768 10 0 bass00 +bass01 32768 10 0 bass01 + + +[PATTERNS] + +empty + . + . + . + . + . + . + . + . + . + . + . + . + . + . + . + . + +bass + c_3 + --- + c_4 + --- + c_3 + --- + c_4 + --- + c_3 + --- + c_4 + --- + c_3 + --- + c_4 + --- + + + +[PATTERNTABLE] + +bass empty empty +bass empty empty + diff --git a/synth/synth.c b/synth/synth.c deleted file mode 120000 index 482a33e..0000000 --- a/synth/synth.c +++ /dev/null @@ -1 +0,0 @@ -../firmware/synth.c \ No newline at end of file diff --git a/synth/synth.c b/synth/synth.c new file mode 100644 index 0000000..eade3fe --- /dev/null +++ b/synth/synth.c @@ -0,0 +1,105 @@ +#include +#include "synth.h" +#include "freq_table.h" + + +synth_instrument_t instruments[256]; +uint8_t wave_table[256][2]; +uint8_t patterns[256][pattern_length][2]; +uint8_t pattern_table[256][channel_count]; +uint8_t tune_length; + +int16_t sample; +int8_t tick; +int8_t row; +int8_t seq; + + +static synth_channel_t channels[channel_count]; + + +uint16_t synth_mix(void) +{ + if(sample == 0) { // new tick + for(int i = 0; i < channel_count; i++) { + synth_channel_t* chan = &channels[i]; + + const synth_instrument_t* inst = &instruments[chan->inst_nr]; + + if(chan->level > inst->decay) chan->level -= inst->decay; + else chan->level = 0; + + chan->pulse_width += inst->pulse_sweep; + + + chan->pos++; + if(wave_table[chan->pos][1] == 0xff) chan->pos += wave_table[chan->pos][0]; + + + // enter new row + if(tick == 0) { + uint8_t pattern_nr = pattern_table[seq][i]; + uint8_t note = patterns[pattern_nr][row][0]; + + if(note) { // new note, maybe? + if(note == 0xff) { + chan->level = 0; + } else { + chan->level = 80; // TODO: less? + chan->note = note; + chan->inst_nr = patterns[pattern_nr][row][1]; + inst = &instruments[chan->inst_nr]; + chan->pos = inst->wave_table_pos; + if(inst->pulse_width) chan->pulse_width = inst->pulse_width; + } + } + } + } + } + if(++sample == tick_length) { + sample = 0; + if(++tick == row_length) { + tick = 0; + if(++row == pattern_length) { + row = 0; + if(++seq == tune_length) { + seq = 0; + } + } + } + } + + + uint16_t output = 0; + for(int i = 0; i < channel_count; i++) { + synth_channel_t* chan = &channels[i]; + const synth_instrument_t* inst = &instruments[chan->inst_nr]; + + chan->phase += freq_table[(uint8_t)(chan->note + wave_table[chan->pos][0])]; + + uint8_t amp; + switch(wave_table[chan->pos][1]) { + case WAVE_PULSE: + amp = -(chan->phase < chan->pulse_width); + break; + + case WAVE_SAW: + amp = (chan->phase >> 8); + break; + + case WAVE_NOISE: // shitty noise + chan->phase = (chan->phase >> 1) ^ (-(chan->phase & 1) & 0xb400); + amp = (chan->phase >> 8); + break; + + default: + amp = 0; + break; + } + + output += ((amp & 0xff) * chan->level) >> 8; + } + + return output; +} + diff --git a/synth/synth.h b/synth/synth.h deleted file mode 120000 index c1ea587..0000000 --- a/synth/synth.h +++ /dev/null @@ -1 +0,0 @@ -../firmware/synth.h \ No newline at end of file diff --git a/synth/synth.h b/synth/synth.h new file mode 100644 index 0000000..4cda049 --- /dev/null +++ b/synth/synth.h @@ -0,0 +1,43 @@ +enum { WAVE_OFF, WAVE_PULSE, WAVE_SAW, WAVE_NOISE }; + +typedef struct { + uint8_t note; + uint8_t inst_nr; + uint8_t pos; + + uint16_t phase; + uint16_t pulse_width; + + uint8_t level; // envelop level + +} synth_channel_t; + + +typedef struct { + uint16_t pulse_width; + uint8_t pulse_sweep; + uint8_t decay; + uint8_t wave_table_pos; +} synth_instrument_t; + + +uint16_t synth_mix(void); + +enum { + channel_count = 3, + tick_length = 400, + row_length = 4, + pattern_length = 16 +}; + + +extern synth_instrument_t instruments[256]; +extern uint8_t wave_table[256][2]; +extern uint8_t patterns[256][pattern_length][2]; +extern uint8_t pattern_table[256][channel_count]; +extern uint8_t tune_length; + +extern int16_t sample; +extern int8_t tick; +extern int8_t row; +extern int8_t seq;