EmbedEd
/
mbed_theremin
xypad theremin for LPC1768
note.cpp
- Committer:
- exopiped
- Date:
- 2016-03-14
- Revision:
- 2:c5eeaf1c8e69
- Parent:
- 1:aa184d2eb2e3
File content as of revision 2:c5eeaf1c8e69:
/* * note.cpp -- manage production of notes in response to * touch screen input */ #include "mbed.h" #include "InterruptIn.h" #include "debug.h" #include "dma.h" #include "envlp.h" #include "wave.h" #include "touch.h" #include "jswitch.h" #include "note.h" #define TURN_DMA_OFF_AFTER_EACH_NOTE 0 typedef enum {NOTE_ATTACK,NOTE_DECAY,NOTE_SUSTAIN,NOTE_RELEASE,NOTE_OFF} NOTE_STATE; static void note_start(void); static void note_state_machine(void); static void note_fill_buf(void); static void note_attack(void); static bool note_attack_done(void); static bool note_decay_done(void); static void note_release(void); static bool note_release_done(void); static bool note_released(void); static void note_end(void); static unsigned note_freq=0; // frequency in Hz static NOTE_STATE note_state=NOTE_OFF; static int note_bufno= NIL; // NIL or index of dma buffer static int note_attack_bufcount; static int note_attack_delta; static int note_attack_bufs; static int note_decay_bufs; static int note_decay_bufcount; static int note_decay_delta; static int note_release_delta; static int note_first_bufval; static int note_last_bufval; static int note_release_numerator; static int note_release_denominator; void note_init(void) { note_freq = 0; note_state = NOTE_OFF; note_bufno = NIL; note_attack_bufcount=0; note_decay_bufcount=0; dma_init(); } void note_start(void) { if (wave_type_changed()) { wave_type_incr(); } wave_reset(); note_freq = touch_frequency(); note_attack_bufs=envlp_get_attack_bufs(); note_decay_bufs=envlp_get_decay_bufs(); note_release_delta = envlp_get_release_delta(); note_release_numerator = ENVLP_MAX - note_release_delta; note_release_denominator = ENVLP_MAX; // fill first two buffers note_attack(); note_set_bufno(0); note_state_machine(); note_fill_buf(); note_set_bufno(1); note_state_machine(); note_fill_buf(); note_bufno=NIL; dma_enable(); } void note_end(void) { dma_disable(); note_state=NOTE_OFF; note_bufno=NIL; } /* * note_update * update the frequency and attenuation factor for the * current note. If the current envelope first and last * add up to less than 2, end the note. * otherwise check to see if it is time to fill a dma buffer. * if so fill the one specified by note_fillbuf. */ void note_update(void) { // execute note state machine note_state_machine(); if(note_bufno!=NIL) { note_fill_buf(); } // handle presence or absence of touch if (touch_debounce()) { wait_ms(10); // wait 10 msec if touch present if (note_released() || !note_active()) { note_start(); } } else { if (note_active()) { if (!note_released()) { note_release(); } } } } void note_state_machine(void) { // execute state machine that manages envelope switch (note_state) { case NOTE_ATTACK: if (note_attack_done()) { note_state = NOTE_DECAY; } note_freq = touch_frequency(); break; case NOTE_DECAY: if(note_decay_done()) { note_state = NOTE_SUSTAIN; } note_freq = touch_frequency(); break; case NOTE_SUSTAIN: note_freq = touch_frequency(); break; case NOTE_RELEASE: if (note_release_done()) { note_end(); break; } break; case NOTE_OFF: default: break; } } /* * note_fill_buf * Use the first and last buffer envelope values, and the * wave values returned by wave_nextval() to compute the * envelop-modified wave values, and then apply the changes * necessary to output the values to the DAC data register. */ void note_fill_buf(void) { int j,start_env,end_env,env_val,wave_val,buf_val,amplitude; int *bufptr; bufptr = dma_get_bufptr(note_bufno); start_env = note_first_bufval; end_env = note_last_bufval; amplitude = touch_amplitude(); for (j=0;j<DMA_BUFSIZE;j++) { env_val=start_env+(end_env - start_env)*j/DMA_BUFSIZE; wave_val = wave_nextval(note_freq); buf_val = wave_val * env_val / ENVLP_MAX; buf_val=amplitude*buf_val/TOUCH_MAX_AMPLITUDE; bufptr[j]= DAC_POWER_MODE | ((buf_val << 6) & 0xFFC0); } note_bufno = NIL; switch (note_state) { case NOTE_ATTACK: note_attack_bufcount++; break; case NOTE_DECAY: note_decay_bufcount++; break; case NOTE_SUSTAIN: note_first_bufval = note_last_bufval; break; case NOTE_RELEASE: note_first_bufval = note_last_bufval; note_last_bufval = note_first_bufval * note_release_numerator / note_release_denominator; break; case NOTE_OFF: default: ; } } /* * note_release * touch has been lifted, note begins to decay */ void note_release(void) { note_state = NOTE_RELEASE; } /* * note_released * return true if note has been released * but not yet ended */ bool note_released(void) { return (note_state == NOTE_RELEASE); } bool note_active(void) { return (note_state < NOTE_OFF); } /* ** note_set_bufno * Set the index of the dma buffer to fill. * */ void note_set_bufno(int bufno) { note_bufno = bufno; } void note_attack(void) { note_state = NOTE_ATTACK; note_attack_bufcount = 0; note_attack_delta = ENVLP_MAX / note_attack_bufs; note_first_bufval=note_attack_bufcount*note_attack_delta; note_last_bufval=note_first_bufval + note_attack_delta; } bool note_attack_done(void) { if (note_attack_bufcount >= note_attack_bufs) { note_decay_bufcount = 0; note_decay_delta = (ENVLP_MAX >> 1) / note_decay_bufs; note_first_bufval = note_last_bufval; return true; } else { note_first_bufval=note_attack_bufcount*note_attack_delta; note_last_bufval=note_first_bufval+note_attack_delta; } return false; } bool note_decay_done(void) { if (note_decay_bufcount >= note_decay_bufs) { note_first_bufval = note_last_bufval; return true; } else { note_last_bufval=note_first_bufval - note_decay_delta; if (note_last_bufval < 0) { note_last_bufval=0; } } return false; } bool note_release_done(void) { if (note_first_bufval < 25) return true; return false; }