xypad theremin for LPC1768

Dependencies:   MODDMA mbed

Files at this revision

API Documentation at this revision

Comitter:
exopiped
Date:
Sun Mar 13 01:12:40 2016 +0000
Child:
1:aa184d2eb2e3
Commit message:
Rebuilt from original code from April 2014

Changed in this revision

MODDMA.lib Show annotated file Show diff for this revision Revisions of this file
debug.cpp Show annotated file Show diff for this revision Revisions of this file
debug.h Show annotated file Show diff for this revision Revisions of this file
dma.cpp Show annotated file Show diff for this revision Revisions of this file
dma.h Show annotated file Show diff for this revision Revisions of this file
envlp.cpp Show annotated file Show diff for this revision Revisions of this file
envlp.h Show annotated file Show diff for this revision Revisions of this file
i2c.h Show annotated file Show diff for this revision Revisions of this file
jswitch.cpp Show annotated file Show diff for this revision Revisions of this file
jswitch.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
note.cpp Show annotated file Show diff for this revision Revisions of this file
note.h Show annotated file Show diff for this revision Revisions of this file
switch.h Show annotated file Show diff for this revision Revisions of this file
touch.cpp Show annotated file Show diff for this revision Revisions of this file
touch.h Show annotated file Show diff for this revision Revisions of this file
wave.cpp Show annotated file Show diff for this revision Revisions of this file
wave.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA.lib	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/MODDMA/#97a16bf2ff43
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,68 @@
+/*
+ ** debug.cpp -- a few handy debug functions
+ */
+#include "mbed.h"
+#include "debug.h"
+#include "string.h"
+ 
+ RawSerial rs(USBTX, USBRX);
+
+ static char debug_hexnyb(char);
+
+ void debug_putstr(char *sptr)
+ {
+     int j,len;
+
+     len = strlen(sptr);
+     if (len>64) len = 64;
+     for (j=0;j<len;j++) {
+         debug_putch(sptr[j]);
+     }
+ }
+
+ int debug_putch(char ch) {
+     return rs.putc(ch);
+ }
+
+ void debug_hexbyte(char inch)
+ {
+     char lonyb,hinyb;
+
+     lonyb = inch & 0x0F;
+     hinyb = (inch >> 4) & 0x0F;
+     (void)debug_putch(debug_hexnyb(hinyb));
+     (void)debug_putch(debug_hexnyb(lonyb));
+ }
+
+ char debug_hexnyb(char inval)
+ {
+     switch (inval) {
+     case 0 ... 9:
+         return (char)(0x30 | inval);
+     case 10 ... 15:
+         return (char)(0x37 + inval);
+     }
+     return ('.');
+ }
+
+void debug_hexshort(short inval)
+ {
+     char loch,hich;
+
+     loch = inval & 0xFF;
+     hich = (inval>>8) & 0xFF;
+     debug_hexbyte(hich);
+     debug_hexbyte(loch);
+ }
+
+void debug_crlf(void)
+ {
+     (void)debug_putch(0x0D);
+     (void)debug_putch(0x0A);
+ }
+
+void debug_space(void)
+ {
+     (void)debug_putch(0x20);
+ }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,12 @@
+/*
+ * debug.h -- simple debug interface
+ */
+#ifndef DEBUG_H
+#define DEBUG_H
+void debug_putstr(char *sptr);
+int debug_putch(char ch);
+void debug_hexbyte(char); 
+void debug_hexshort(short inval);
+void debug_crlf(void);
+void debug_space(void);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dma.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,141 @@
+/* 
+ * dma.cpp 
+ * Send a buffer repeatedly to the DAC using DMA.
+ */
+#include "mbed.h"
+#include "note.h"
+#include "MODDMA.h"
+#include "dma.h"
+
+int buffer[2][DMA_BUFSIZE];
+
+AnalogOut sig(p18);  // analog output object ( uses pin 18)
+
+MODDMA dma;
+MODDMA_Config *conf0, *conf1;
+
+int *dma_get_bufptr(int bufno)
+{
+    return buffer[bufno];
+}
+
+void dma_init(void) {
+        
+    // Prepare the GPDMA system for buffer0.
+    conf0 = new MODDMA_Config;
+    conf0
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t) &buffer[0] )
+     ->dstMemAddr    ( MODDMA::DAC )
+     ->transferSize  ( 512 )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::DAC )
+     ->attach_tc     ( &TC0_callback )
+     ->attach_err    ( &ERR0_callback )     
+    ; // config end
+    
+    
+    // Prepare the GPDMA system for buffer1.
+    conf1 = new MODDMA_Config;
+    conf1
+     ->channelNum    ( MODDMA::Channel_1 )
+     ->srcMemAddr    ( (uint32_t) &buffer[1] )
+     ->dstMemAddr    ( MODDMA::DAC )
+     ->transferSize  ( 512 )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::DAC )
+     ->attach_tc     ( &TC1_callback )
+     ->attach_err    ( &ERR1_callback )     
+    ; // config end
+
+    
+//
+// By default, the Mbed library sets the PCLK_DAC clock value
+// to 24MHz. One wave cycle in each buffer is DMA_BUFSIZE
+// (512) points long. The sample rate of the output is to be 
+// WAVE_SAMPLE_RATE (22050) samples per second, regardless of.
+// wave frequency.  So the DACCNTVAL will be 24000000/22050
+// or 1088.
+//
+
+    LPC_DAC->DACCNTVAL = 1088; // for 22050 sample rate
+
+//
+// the wave templates will be one dma buffer long, so the
+// lowest frequency that can be produced is 
+//  WAVE_SAMPLE_RATE/DMA_BUFSIZE = 22050/512 = 43 Hz
+// the highest frequency wave that can be produced is
+// roughly half the sample rate, or 11025 Hz.
+//
+}
+
+void dma_enable(void)
+{
+    // Prepare first configuration.
+    if (!dma.Prepare( conf0 )) {
+        error("Doh!");
+    }
+    
+    // Begin (enable DMA and counter). Note, don't enable
+    // DBLBUF_ENA as we are using DMA double buffering.
+    LPC_DAC->DACCTRL |= (3UL << 2); 
+}
+
+void dma_disable(void)
+{
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.Disable((MODDMA::CHANNELS)conf0->channelNum());
+    dma.Disable((MODDMA::CHANNELS)conf1->channelNum());
+
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+     
+    dma.Disable((MODDMA::CHANNELS)conf0->channelNum());
+   
+    if (note_active()) {
+        // Notify note.cpp that it is time to refill buffer[0]
+        note_set_bufno(0);
+       
+        // Swap to buffer1
+        dma.Prepare( conf1 );
+
+        // Clear DMA IRQ flags.
+        if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+    } else {
+        dma.Disable((MODDMA::CHANNELS)conf1->channelNum());
+    }
+}
+
+// Configuration callback on Error
+void ERR0_callback(void) {
+    error("Oh no! My Mbed EXPLODED!");
+}
+
+// Configuration callback on TC
+void TC1_callback(void) {
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.Disable((MODDMA::CHANNELS)conf1->channelNum());
+    
+    if (note_active()) {
+        // Notify note.cpp that it is time to refill buffer[1]
+        note_set_bufno(1);
+
+        // Swap to buffer0
+        dma.Prepare( conf0 );
+        
+        // Clear DMA IRQ flags.
+        if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+    } else {
+        dma.Disable((MODDMA::CHANNELS)conf0->channelNum());
+    }
+}
+
+// Configuration callback on Error
+void ERR1_callback(void) {
+    error("Oh no! My Mbed EXPLODED!");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dma.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,17 @@
+#ifndef DMA_H
+#define DMA_H
+
+#define DMA_BUFSIZE 512
+#define DAC_POWER_MODE (1<<16) 
+
+void dma_init(void);
+void dma_enable(void);
+void dma_disable(void);
+int *dma_get_bufptr(int bufno);
+void TC0_callback(void);
+void ERR0_callback(void);
+void TC1_callback(void);
+void ERR1_callback(void);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/envlp.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,111 @@
+/*
+ * envlp.c -- manage the note's envelope state machine
+ */
+#include "mbed.h"
+#include "debug.h"
+#include "touch.h"
+#include "jswitch.h"
+#include "envlp.h"
+/*
+ * sound envelope follows ADSR pattern 
+ * (Attack, Decay, Sustain, Release) 
+ * three parameters below control the envelope shape 
+ * It should be easy to consider these default values 
+ * and modify the code below to set the variables 
+ * envlp_attack_bufs, envlp_release_bufs, 
+ * and envlp_release_delta dynamically, 
+ * depending upon external inputs 
+ */ 
+#define ATTACK_BUFFERS_MIN  2
+#define ATTACK_BUFFERS_MAX 20
+#define ATTACK_BUFFERS 5     // attack buffers
+#define DECAY_BUFFERS_MIN 1
+#define DECAY_BUFFERS_MAX 40
+#define DECAY_BUFFERS  ATTACK_BUFFERS/2 // decay buffers
+#define RELEASE_DELTA_MIN 1
+#define RELEASE_DELTA_MAX 128
+#define RELEASE_DELTA  8    // inverse release duration param
+
+/*
+ * local envelope functions
+ */
+static void envlp_set_attack_bufs(void);
+static void envlp_set_decay_bufs(void);
+static void envlp_set_release_delta(void);
+
+/*
+ * local envelop veriables
+ */
+static int envlp_attack_bufs;
+static int envlp_decay_bufs;
+static int envlp_release_delta;
+
+void envlp_init(void)
+{
+    envlp_attack_bufs=ATTACK_BUFFERS;  
+    envlp_decay_bufs=DECAY_BUFFERS;  
+    envlp_release_delta=RELEASE_DELTA;
+}
+
+void envlp_update(void)
+{
+    envlp_set_attack_bufs();
+    envlp_set_decay_bufs();
+    envlp_set_release_delta();
+}
+
+void envlp_set_attack_bufs()
+{
+    unsigned char js_val;
+
+    js_val = js_read((JS_UP | JS_DOWN));
+    if (js_val & JS_UP) {
+        if (envlp_attack_bufs < ATTACK_BUFFERS_MAX) {
+            envlp_attack_bufs++;
+        }
+    } else if(js_val & JS_DOWN) {
+        if (envlp_attack_bufs > ATTACK_BUFFERS_MIN) {
+            envlp_attack_bufs--;
+        }
+    }
+}
+
+int envlp_get_attack_bufs(void)
+{
+    return envlp_attack_bufs;
+}
+
+void envlp_set_decay_bufs(void)
+{
+    if (envlp_attack_bufs>1) {
+        envlp_decay_bufs = envlp_attack_bufs/2;
+    } else {
+        envlp_decay_bufs = 1;
+    }
+}
+
+int envlp_get_decay_bufs(void)
+{
+    return envlp_decay_bufs;
+}
+
+void envlp_set_release_delta(void)
+{
+    unsigned char js_val;
+
+    js_val = js_read((JS_LEFT | JS_RIGHT));
+    if (js_val & JS_LEFT) {
+        if (envlp_release_delta < RELEASE_DELTA_MAX) {
+            envlp_release_delta++;
+        }
+    } else if(js_val & JS_RIGHT) {
+        if (envlp_release_delta > RELEASE_DELTA_MIN) {
+            envlp_release_delta--;
+        }
+    }
+}
+
+int envlp_get_release_delta(void)
+{
+    return envlp_release_delta;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/envlp.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,16 @@
+#ifndef ENVLP_H
+#define ENVLP_H
+/*
+ * envlp.h -- Functions which help note.cpp produce 
+ * an ADSR (Attack,Decay,Sustain,Release) envelope 
+ */
+#define ENVLP_MAX (0x1FF)
+
+void envlp_init(void);
+void envlp_update(void);
+int envlp_get_attack_bufs(void);
+int envlp_get_decay_bufs(void);
+int envlp_get_release_delta(void);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/i2c.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,59 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef MBED_I2C_API_H
+#define MBED_I2C_API_H
+
+#include "device.h"
+
+#if DEVICE_I2C
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct i2c_s i2c_t;
+
+enum {
+  I2C_ERROR_NO_SLAVE = -1,
+  I2C_ERROR_BUS_BUSY = -2
+};
+
+void i2c_init         (i2c_t *obj, PinName sda, PinName scl);
+void i2c_frequency    (i2c_t *obj, int hz);
+int  i2c_start        (i2c_t *obj);
+int  i2c_stop         (i2c_t *obj);
+int  i2c_read         (i2c_t *obj, int address, char *data, int length, int stop);
+int  i2c_write        (i2c_t *obj, int address, const char *data, int length, int stop);
+void i2c_reset        (i2c_t *obj);
+int  i2c_byte_read    (i2c_t *obj, int last);
+int  i2c_byte_write   (i2c_t *obj, int data);
+
+#if DEVICE_I2CSLAVE
+void i2c_slave_mode   (i2c_t *obj, int enable_slave);
+int  i2c_slave_receive(i2c_t *obj);
+int  i2c_slave_read   (i2c_t *obj, char *data, int length);
+int  i2c_slave_write  (i2c_t *obj, const char *data, int length);
+void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jswitch.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * jswitch.cpp -- debounces and reads pins 12 
+ *    (SW_DOWN), 13(SW_LEFT),14(SW_CENTER),15(SW_UP),
+ *    and 16(SE_RIGHT) of the mbed 40 pin dip board    
+ */
+#include "mbed.h" 
+#include "debug.h"
+#include "jswitch.h"
+
+#define JS_BLANKING_MSEC 333
+
+DigitalIn js_down(p12);
+DigitalIn js_left(p13);
+DigitalIn js_center(p14);
+DigitalIn js_up(p15);
+DigitalIn js_right(p16);
+
+Timer js_timer;
+
+static unsigned char js_oldest=0;
+static unsigned char js_older=0;
+static unsigned char js_old=0;
+static unsigned char js_now=0;
+static unsigned char js_official=0;
+static int js_msec=0;
+
+void js_init(void)
+{
+    js_official = 0;
+    js_now = 0;
+    js_old = 0;
+    js_older = 0;
+    js_oldest = 0;
+    js_timer.start();
+}
+/*
+ * js_debounce -- button presses will not be reported 
+ * any more that once every 333 msec. 
+ */
+void js_debounce(void){
+    if ((js_timer.read_ms()-js_msec)>JS_BLANKING_MSEC) {
+        if (js_official==0) {
+            js_oldest = js_older; 
+            js_older=js_old;
+            js_old=js_now;
+            js_now = ( (js_center << 4) 
+                       | (js_up << 3) 
+                       | (js_down << 2) 
+                       | (js_left << 1) 
+                       | js_right );
+            js_official|=(js_now&js_old&js_older&js_oldest);
+            if (js_official>0) {
+                js_msec=js_timer.read_ms();
+//                debug_hexbyte(js_official);
+            }
+        } else {
+            js_now=0;
+            js_old=0;
+            js_older=0;
+            js_oldest=0;
+        }
+    }
+}
+/*
+ *   js_read -- reads buttons indicated by the mask.
+ *   once read the masked button indications are cleared
+ */
+unsigned char js_read(unsigned char mask)
+{
+    unsigned char retval;
+
+    retval = js_official & mask;
+    js_official &= ~retval; 
+    return retval;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jswitch.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,16 @@
+/*
+ * jswitch.h -- header for jswitch.cpp, which reads the 
+ *    joystick pins, and provides debounced version
+ *    of the pins to js_read() caller. 
+ */
+ #ifndef JSTICK_H
+ #define JSTICK_H
+ #define JS_CENTER 0x10
+ #define JS_UP     0x04
+ #define JS_DOWN   0x08
+ #define JS_LEFT   0x01
+ #define JS_RIGHT  0x02
+ void js_init(void);
+ void js_debounce(void);
+ unsigned char js_read(unsigned char mask);
+ #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,33 @@
+/* 
+ * main.cpp 
+ * Sending digital note waveforms out the onboard DAC 
+ * in responses to touches on an XY pad(resistive touchscreen) 
+ * X changes audio volume..  Y changes audio frequency 
+ * Varies from forty Hz to 1047 Hz (C6) 
+ */
+#include "mbed.h"
+#include "debug.h"
+#include "dma.h"
+#include "wave.h"
+#include "note.h"
+#include "jswitch.h"
+#include "touch.h"
+#include "envlp.h"
+
+int main(void)
+{
+    js_init();  // initialize joystick
+    envlp_init(); // initialize envelope parameters
+    wave_init();  // starts with default wave type
+    touch_init();  // initialize touchscreen controller
+    note_init();    // initialize note production    
+
+    while (1==1) {
+        js_debounce();  // debounce joystick
+        envlp_update(); // update envelope parameters
+        wave_update();  // update waveform choice
+        note_update();  // update note or start a new one
+        wait_ms(2);  // lower limit on loop timing
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/87f2f5183dfb
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/note.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,279 @@
+/* 
+ *  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"
+
+DigitalOut led2(LED2);   // lit during NOTE_RELEASE state
+
+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();
+    debug_hexshort((short)note_attack_bufs);
+    debug_putch(' ');
+    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;
+    debug_hexshort((short)note_release_numerator);
+    debug_crlf();
+
+    // 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();
+    dma_enable();
+}
+
+void note_end(void)
+{
+    dma_disable();
+    note_state=NOTE_OFF;
+    note_bufno=NIL;
+    led2 = 0;
+}
+
+/* 
+ * 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 dma buffer sent, refill it
+    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=NULL;
+
+    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;  // buffer is filled
+    switch (note_state) {
+    case NOTE_ATTACK:
+        note_attack_bufcount++;
+        break;
+    case NOTE_DECAY:
+        note_decay_bufcount++;
+        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_SUSTAIN:
+    case NOTE_OFF:
+    default:
+        ;
+    }
+}
+
+/*
+ * note_release 
+ *    touch has been lifted, note begins to decay 
+ */
+void note_release(void)
+{
+    led2 = 1;
+    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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/note.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,14 @@
+#ifndef NOTE_H
+#define NOTE_H
+/*
+ * note.h 
+ *    Start, update, release or end note, and fill dma buffers for
+ *    one note at a time.
+ */
+#define NIL (-1)
+
+void note_init(void);
+void note_update(void);
+bool note_active(void);
+void note_set_bufno(int bufno);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/switch.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,10 @@
+/*
+ * jstick.h -- header for jstick.cpp, which reads the 
+ *    joystick pins, and provides debounced version
+ *    of the pins to js_read() caller. 
+ */
+ #ifndef JSTICK_H
+ #define JSTICK_H
+ void js_init(void);
+ bool js_debounce(void);
+ #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/touch.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,322 @@
+/*
+ * touch.cpp -- touch screen monitor
+ */
+#include "mbed.h"
+#include "debug.h"
+#include "touch.h"
+
+#define NIL (-1)
+/* 
+ * Connecting the touch screen 
+ *    STMPE610 MODE pin is tied low for I2C interface
+ *    STMPE610 A0 pin tied low for I2C address 0x41
+ *                       (0x82 when shifted left 1)
+ *    STMPE610 A0 pin tied high for I2C address 0x44
+ *                        (0x88 when shifted left 1)
+ *   
+ *    I2C works on board pins 9 and 10. (SDA, SDL)
+ *     ( STMPE610 pins SDAT and  SCLK )
+ *   
+ * Setting up the touch screen 
+ *  
+ * Disable Touch Screen and A/D clock -- SYS_CTRL2 
+ *    Set TSC_OFF bit high, ADC_OFF bit high
+ *  
+ * ConfigureTouch Screen -- TSCFG register 
+ *    Set up for 4 sample averaging
+ *    Touch detect delay of 1 msec
+ *    Settling time of 1 msec
+ *  
+ * Touchscreen Window -- WDW_TR_X, WDW_TR_Y, WDW_BL_X, WDW_BLY
+ *     Set up for full screen ( default condition )
+ *      
+ */
+
+typedef enum {TOUCH_NOTOUCH,TOUCH_DEBOUNCE,TOUCH_PRESENT} TOUCH_STATE;
+
+
+#define TSC_ADDR  0x82     // (i2c address for touchscreen)<<1
+
+// CHIP_ID register
+#define CHIP_ID       0x00  // 16 bit register
+
+// ID_VER register
+#define ID_VER        0x02  // 8 bit register
+
+// SYS_CTRL1 Reset control register
+#define SYS_CTRL1     0x03
+#define SOFT_RESET 0x02
+
+// SYS_CTRL2 clock control register
+#define SYS_CTRL2     0x04
+#define ADC_OFF    0x01
+#define TSC_OFF    0x02
+#define GPIO_OFF   0x04
+
+// ADC_CTRL registers
+#define ADC_CTRL1     0x20
+#define ADC_CTRL2     0x21
+
+// Interrupt control, enable and status registers
+#define INT_CTRL      0x09
+#define INT_EN        0x0A
+#define INT_STA       0x0B
+
+// TSC_CTRL touchscreen control register
+#define TSC_CTRL             0x40
+#define TSC_TOUCH_DET    0x80 // 1 when touch detected else 0 
+#define TSC_TRACK_MASK   0x70 // 0 => no window tracking
+#define TSC_OP_MOD_MASK  0x0E // 0 => XYZ acquisition
+#define TSC_EN_MASK      0x01 // enable touchscreen
+
+// TSC_CFG touchscreen config register
+#define TSC_CFG       0x41
+#define TSC_AVG4    0x80
+#define TSC_DLY_1MS 0x20
+#define TSC_STL_1MS 0x03
+
+#define TSC_I_DRIVE   0x58
+#define MAMP_50      0x01
+
+// FIFO_TH touchscreen fifo threshold register
+#define FIFO_TH       0x4A
+
+// TSC_DATA_X X data register
+#define TSC_DATA_X    0x4D
+
+// TSC_DATA_Y  Y data register
+#define TSC_DATA_Y    0x4F
+
+// FIFO_STA  touchscreen fifo control-status register
+#define FIFO_STA      0x4B
+#define FIFO_OFLOW 0x80
+#define FIFO_FULL  0x40
+#define FIFO_EMPTY 0x20
+#define FIFO_TRGD  0x10
+#define FIFO_RESET 0x01
+
+// TSC_DATA touchscreen data register
+#define TSC_DATA      0xD7
+
+// GPIO_AF -- GPIO Alternate FunctionRegister
+#define GPIO_AF       0x17
+
+DigitalOut led4(LED4);
+
+i2c_t touch_ctrl;  // i2c interface struct for touch screen
+
+static bool touch_present(void);
+static void touch_compute_params(void);
+
+static char tsc_reset[2]={SYS_CTRL1, SOFT_RESET};
+static char clox_on[2]={SYS_CTRL2,0x00};
+static char adc_ctrl1[2]={ADC_CTRL1,0x49};
+static char adc_ctrl2[2]={ADC_CTRL2,0x01};
+static char gpio_af[2]={GPIO_AF,0};
+static char fifo_clear[2]={FIFO_STA,0x01};
+static char fifo_operate[2]={FIFO_STA,0x00};
+static char touch_int_en[2]={INT_EN,0x02};//enable FIFO_TH int
+static char clr_intrupts[2]={INT_STA,0xFF};
+static char ena_intrupt[2]={INT_CTRL,0x02};
+static char tsc_cfg[2]={TSC_CFG,( TSC_AVG4 
+                                  | TSC_DLY_1MS 
+                                  | TSC_STL_1MS )};
+static char tsc_enable[2]={TSC_CTRL,3};
+static char tsc_ctrl=TSC_CTRL;
+static char tsc_i_drive[2]={TSC_I_DRIVE,MAMP_50};
+static char fifo_th[2]={FIFO_TH,1};
+static char fifo_ctrl_sta=FIFO_STA;
+static char tsc_data=TSC_DATA;
+
+static int touch_audio_freq = 1000;
+static int touch_audio_amplitude = 0;
+static char touch_status=0; // result of reading TSC_CTR
+static char fifo_status=0;  // result of reading FIFO_CTRL_STA
+
+short touch_x,touch_y;
+ 
+// used by state machine that debounces touch detection 
+TOUCH_STATE touch_state=TOUCH_NOTOUCH;
+#define GOOD_TOUCH_COUNT 8
+#define NO_TOUCH_COUNT 8
+ 
+bool touch_init(void)
+{
+    char chipid[2];
+
+    i2c_init(&touch_ctrl,p28,p27);
+    i2c_frequency(&touch_ctrl,100000);
+    wait_ms(1);
+
+    // read chip id
+    i2c_write(&touch_ctrl,TSC_ADDR,CHIP_ID,2,0);
+    i2c_read(&touch_ctrl,TSC_ADDR,chipid,2,1);
+    wait_ms(1);
+
+    // reset touch screen chip
+    i2c_write(&touch_ctrl,TSC_ADDR,tsc_reset,2,1);
+    wait_ms(5);
+
+    i2c_write(&touch_ctrl,TSC_ADDR,tsc_i_drive,2,1);
+    wait_ms(1);
+
+    // turn on ADC and TSC clocks
+    i2c_write(&touch_ctrl,TSC_ADDR,clox_on,2,1);
+    wait_ms(3);
+
+    // enable touch interrupt
+    i2c_write(&touch_ctrl,TSC_ADDR,touch_int_en,2,1);
+    wait_ms(1);
+
+    // 80 clock cycles for ADC conv, 12 bit ADC, internal ref
+    i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl1,2,1);
+    wait_ms(2);
+
+    // ADC clock = 3.25 MHz
+    i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl2,2,1);
+    wait_ms(1);
+
+    // 4 sample averaging and 1ms delays
+    i2c_write(&touch_ctrl,TSC_ADDR,tsc_cfg,2,1); 
+    wait_ms(1);
+
+    // gpio alt function register to 0
+    i2c_write(&touch_ctrl,TSC_ADDR,gpio_af,2,1);
+    wait_ms(1);
+
+    // FIFO threshold not zero
+    i2c_write(&touch_ctrl,TSC_ADDR,fifo_th,2,1);
+    wait_ms(1);
+
+    // FIFO Reset
+    i2c_write(&touch_ctrl,TSC_ADDR,fifo_clear,2,1);
+    wait_ms(1);
+
+    // FIFO out of reset
+    i2c_write(&touch_ctrl,TSC_ADDR,fifo_operate,2,1);
+    wait_ms(1);
+
+    // enable touchscreen, no window tracking, x,y mode
+    i2c_write(&touch_ctrl,TSC_ADDR,tsc_enable,2,1);
+    wait_ms(1);
+
+    i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1);
+    wait_ms(1);
+
+    i2c_write(&touch_ctrl,TSC_ADDR,ena_intrupt,2,1);
+    wait_ms(1);
+
+    touch_state = TOUCH_NOTOUCH;
+    return true;
+}
+
+bool touch_debounce(void)
+{
+    static int debounce_count=0;
+
+    switch (touch_state) {
+    case TOUCH_NOTOUCH:
+        if (touch_present()) {
+            debounce_count=0;
+            touch_state = TOUCH_DEBOUNCE;
+        }
+        break;
+
+    case TOUCH_DEBOUNCE:
+        if (touch_present()) {
+            if (++debounce_count > GOOD_TOUCH_COUNT) {
+                touch_state = TOUCH_PRESENT;
+            }
+        } else {
+            touch_state = TOUCH_NOTOUCH;
+        }
+        break;
+
+    case TOUCH_PRESENT:
+        if (touch_present()) {
+            touch_compute_params();
+            return true;
+        } else {
+            touch_state = TOUCH_NOTOUCH;
+        }
+        break;
+
+    }
+    return false;
+}
+
+int touch_frequency(void)
+{
+    return touch_audio_freq;
+}
+
+int touch_amplitude(void)
+{
+    return touch_audio_amplitude;
+}
+void touch_compute_params(void)
+{
+    if(0>touch_get_xy(&touch_x,&touch_y)) return;
+    touch_audio_freq = TOUCH_MIN_FREQUENCY 
+        + (TOUCH_MAX_FREQUENCY - TOUCH_MIN_FREQUENCY)
+        * touch_y/0xFFF;
+    touch_audio_amplitude = TOUCH_MAX_AMPLITUDE*touch_x/0xFFF;
+//    debug_hexshort((short)touch_audio_freq);
+//    debug_putch(',');
+//    debug_hexshort((short)touch_audio_amplitude);
+//    debug_crlf();
+}
+
+bool touch_present(void)
+{
+    i2c_init(&touch_ctrl,p28,p27); // sync i2c routines
+    i2c_frequency(&touch_ctrl,100000); // 100kHz clock
+
+    i2c_write(&touch_ctrl,TSC_ADDR,&tsc_ctrl,1,0);
+    i2c_read(&touch_ctrl,TSC_ADDR,&touch_status,1,1);
+
+    if ((touch_status & TSC_EN_MASK)==0) {  // i2c error 
+        led4=1;                             // disables screen
+        wait_ms(10);
+        touch_init();                       // re-init fixes
+        return false;
+    } else if ((touch_status & TSC_TOUCH_DET)>0) {
+        return true;
+    }
+    return false; 
+}
+
+int touch_get_xy(short *x,short *y)
+{
+    unsigned char packed_xy[3];
+
+    if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0)
+        return NIL;
+    if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0)
+        return NIL;
+    while ((fifo_status & FIFO_EMPTY)!=FIFO_EMPTY ) {
+        if (i2c_write(&touch_ctrl,TSC_ADDR,&tsc_data,1,0) < 0)
+            return NIL; 
+        if(i2c_read(&touch_ctrl,TSC_ADDR,(char *)packed_xy,3,1)<0)
+            return NIL;
+        if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0)
+            return NIL;
+        if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0)
+            return NIL;
+    }
+    if(i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1)<0)
+        return NIL;
+    *x = (short)(packed_xy[0]<<4) 
+       | (short)((packed_xy[1] & 0xF0)>>4);
+    *y = 0xFFF -((short)((packed_xy[1] & 0x0F)<<8) 
+               | (short)(packed_xy[2]));
+    // 0xFFF or 0x000 is some kind of glitch
+    if (*x==0xFFF && *y==0xFFF) return NIL;
+    if (*x==0 && *y==0) return NIL;
+//    debug_hexshort(*x);
+//    debug_putch(',');
+//    debug_hexshort(*y);
+//    debug_crlf();
+    return 0; 
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/touch.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,14 @@
+/*
+ * touch.h -- interface definition for touch screen monitor
+ */
+#ifndef TOUCH_H
+#define TOUCH_H
+#define TOUCH_MAX_AMPLITUDE 255
+#define TOUCH_MAX_FREQUENCY 1047
+#define TOUCH_MIN_FREQUENCY 43
+bool touch_init(void);
+int touch_get_xy(short *x,short *y);
+bool touch_debounce(void);
+int touch_frequency(void);
+int touch_amplitude(void);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wave.cpp	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,108 @@
+/*
+ * wave.cpp -- wave templates for use in Digital 
+ *    Theremin demo program 
+ */
+#include "mbed.h"
+#include "dma.h"
+#include "jswitch.h"
+#include "wave.h"
+
+// Default wave type is the SAW
+static int wavetype = WAVE_TYPE_DEFAULT;
+// Next wave type requested
+static bool next_wavetype=false;
+// The wave template buffer size is DMA_BUFSIZE
+static int waveform[1+WAVE_TYPE_LAST - WAVE_TYPE_FIRST][DMA_BUFSIZE];
+// Accumulated phase
+static unsigned accum_phi = 0;
+
+/*
+ * the phase accumulator ranges between 0 and 99999. 
+ * corresponding to 0 and 2*pi radians.  The frequency 
+ * supplied to the wave_nextval() function determines the 
+ * magnitude of the  change in the phase accumulator value, 
+ * according to the formula: 
+ *       delta-phase = 100000*frequency/WAVE_SAMPLE_RATE
+ * The next value of phase_accumulator is: 
+ *       (phase_accumulator + delta-phase) % 100000
+ * phase_accumulator is converted to wave table index using 
+ * the formula: 
+ *        index = (DMA_BUFSIZE - 1)*phase_accumulator/0xFFFF
+ */
+
+void wave_init(void)
+{
+    int j;
+
+    accum_phi = 0;
+    wavetype = WAVE_TYPE_DEFAULT;
+
+    for (j=0;j<DMA_BUFSIZE;j++) {
+        waveform[WAVE_TYPE_SAW][j] = j;
+    }
+
+    for (j=0;j<DMA_BUFSIZE;j++) {
+        if (j<DMA_BUFSIZE/2) {
+            waveform[WAVE_TYPE_SQUARE][j] = DMA_BUFSIZE; 
+        } else {
+            waveform[WAVE_TYPE_SQUARE][j] = 0;
+        }
+    }
+
+    for (j=0;j<DMA_BUFSIZE;j++) {
+        if (j<DMA_BUFSIZE/2) {
+            waveform[WAVE_TYPE_TRIANGLE][j] = 2*j;
+        } else {
+            waveform[WAVE_TYPE_TRIANGLE][j]
+                =DMA_BUFSIZE-2*(j-DMA_BUFSIZE/2);
+        }
+    }
+}
+
+void wave_reset(void)
+{
+    accum_phi=0;
+}
+/* 
+ * wave_nextval 
+ *       delta-phase = 100000*frequency/WAVE_SAMPLE_RATE
+ * The next value of phase_accumulator is: 
+ *       (phase_accumulator + delta-phase) % 100000
+ * phase_accumulator is converted to wave table index using 
+ * the formula: 
+ *        index = DMA_BUFSIZE * phase_accumulator / 100000 
+ */
+int wave_nextval(unsigned freq)
+{
+    unsigned delta_phi,index;
+
+    delta_phi= 100000*freq/WAVE_SAMPLE_RATE;
+    accum_phi = (accum_phi + delta_phi)%100000;
+    index = ((DMA_BUFSIZE - 1) * accum_phi)/100000;
+    return waveform[wavetype][index];
+}
+
+void wave_update(void)
+{
+    unsigned char js_val;
+
+    js_val = js_read(JS_CENTER);
+    if ((js_val & JS_CENTER)==JS_CENTER) {
+        next_wavetype = true;
+    }
+}
+
+bool wave_type_changed(void)
+{
+    return next_wavetype;
+}
+
+void wave_type_incr(void)
+{
+    next_wavetype = false;
+    wavetype = 1+wavetype;
+    if (wavetype > WAVE_TYPE_LAST) {
+        wavetype = WAVE_TYPE_FIRST;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wave.h	Sun Mar 13 01:12:40 2016 +0000
@@ -0,0 +1,19 @@
+#ifndef WAVE_H
+#define WAVE_H
+
+#define WAVE_TYPE_FIRST    0
+#define WAVE_TYPE_SAW      0
+#define WAVE_TYPE_TRIANGLE 1
+#define WAVE_TYPE_SQUARE   2
+#define WAVE_TYPE_LAST     2
+#define WAVE_TYPE_DEFAULT WAVE_TYPE_SAW
+#define WAVE_SAMPLE_RATE   22050
+
+void wave_init(void);
+void wave_reset(void);
+void wave_update(void);
+int wave_nextval(unsigned freq);
+bool wave_type_changed(void);
+void wave_type_incr(void);
+#endif
+