Jan Ostman
Published

Micro Virtual Analog Synthesizer

Can the LPC810 ARM MCU play music?

Full instructions provided4,455
Micro Virtual Analog Synthesizer

Story

Read more

Code

output_a_256_16_bit_sinetable_at_44_1khz.c

C/C++
output_a_256_16_bit_sinetable_at_44_1khz.c
//**************************************************************************/
//    Synth main.c with Arduino style definitions
//**************************************************************************/
#include "wiring.h"
#include "LPC8xx.h"

/* Control register bit definition. */
#define MRT_INT_ENA          (0x1<<0)
#define MRT_REPEATED_MODE    (0x00<<1)
#define MRT_ONE_SHOT_INT     (0x01<<1)
#define MRT_ONE_SHOT_STALL   (0x02<<1)

/* Status register bit definition */
#define MRT_STAT_IRQ_FLAG    (0x1<<0)
#define MRT_STAT_RUN         (0x1<<1)

int32_t err=0;
volatile int32_t DAC=0;
uint8_t phase=0;


 int16_t sine[256] = {
		   0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
		   0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
		   0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
		   0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
		   0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
		   0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
		   0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
		   0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
		   0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
		   0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
		   0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
		   0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
		   0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
		   0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
		   0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
		   0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
		   0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e,
		   0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef,
		   0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86,
		   0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be,
		   0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a,
		   0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc,
		   0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d,
		   0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a,
		   0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3,
		   0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894,
		   0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc,
		   0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c,
		   0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c,
		   0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22,
		   0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5,
		   0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc
 };


void MRT_IRQHandler(void) {
  pinMode(3,INPUT);
  if ( LPC_MRT->Channel[0].STAT & MRT_STAT_IRQ_FLAG ) {
    LPC_MRT->Channel[0].STAT = MRT_STAT_IRQ_FLAG;      /* clear interrupt flag */

    DAC=0x8000+sine[phase++];
  }
  pinMode(3,OUTPUT);
  return;
}

void mrtInit(uint32_t delay)
{
  /* Enable clock to MRT and reset the MRT peripheral */
  LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<10);
  LPC_SYSCON->PRESETCTRL &= ~(0x1<<7);
  LPC_SYSCON->PRESETCTRL |= (0x1<<7);

  LPC_MRT->Channel[0].INTVAL = delay;
  LPC_MRT->Channel[0].INTVAL |= 0x1UL<<31;

  LPC_MRT->Channel[0].CTRL = MRT_REPEATED_MODE|MRT_INT_ENA;

  /* Enable the MRT Interrupt */
#if NMI_ENABLED
  NVIC_DisableIRQ( MRT_IRQn );
  NMI_Init( MRT_IRQn );
#else
  NVIC_EnableIRQ(MRT_IRQn);
#endif
  return;
}

int main(void)
{
  /* Initialise the GPIO block */
	  /* Enable AHB clock to the GPIO domain. */
	  LPC_SYSCON->SYSAHBCLKCTRL |=  (1 << 6);
	  LPC_SYSCON->PRESETCTRL    &= ~(1 << 10);
	  LPC_SYSCON->PRESETCTRL    |=  (1 << 10);
      LPC_SWM->PINENABLE0 = 0xffffffffUL; //All 6 GPIO enabled
      /* Configure the multi-rate timer for 44K ticks */
      mrtInit(__SYSTEM_CLOCK/44100);
      pinMode(3,OUTPUT);
      while(1) {
    	   if(DAC >= err) {
    		   digitalWrite(3,HIGH);
    	   err += 0xFFFF-DAC;
    	     }
    	   else
    	     {
    		   digitalWrite(3,LOW);
    	     err -= DAC;
    	     }
       }
}

the_dcf.c

C/C++
the_dcf.c
//---------------- DCF block ---------------------------------------
    //C implementation for a 4pole lowpass DCF with resonance:

    vi=DCO;
    vo = ((vo * (65536 - f)) + (t1 * f))/65536; //+3db
    t1 = ((t1 * (65536 - f)) + (t2 * f))/65536; //+6db
    t2 = ((t2 * (65536 - f)) + (t3 * f))/65536; //+9db
    t3 = ((t3 * (65536 - f)) + (t4 * f))/65536; //+12db
    t4 = ((t4 * (65536 - f)) + (t5 * f))/65536; //+15db
    t5 = ((t5 * (65536 - f)) + (t6 * f))/65536; //+18db
    t6 = ((t6 * (65536 - f)) + (t7 * f))/65536; //+21db
    t7 = ((t7 * (65536 - f)) + (t8 * f))/65536; //+24db
    t8 = vi-((vo*q)/65536);                     //resonance feedback
    if (vo>32767) vo=32767;
    if (vo<-32767) vo=-32767;
    DCF=vo;
    //-----------------------------------------------------------------

the_dco_block.c

C/C++
the_dco_block.c
//-------------------- 3 DCO block ------------------------------------------
    DCO1 += FREQ1; //increment phase accumulator1 with phase1
    DCO2 += FREQ2; //increment phase accumulator2 with phase2
    DCO3 += FREQ3; //increment phase accumulator3 with phase3
    DCO=((((DCO1 & 0x7F0000)+(DCO2 & 0x7F0000)+(DCO3 & 0x7F0000))/65536)-192)*171;
    //---------------------------------------------------------------------------

env_block.

C/C++
env_block.
//--------------------- ENV block ---------------------------------
    if (!envstat--) {
    envstat=1024;
    if (TRIG>0) {
    	if (state==0) {
    		volume += ATTACK;
    		if (volume>0xFFFF) {
    			volume=0xFFFF;
    			state++;
    		}
    	}
    	if (state==1) {
    		volume -= DECAY;
    		if (volume<SUSTAIN) {
    			volume=SUSTAIN;
    			state++;
    		}
    	}

    else {
    		volume -= RELEASE;
    		if (volume<0) {
    			volume=0;
    		}
    }
    }
    }
    ENV=(volume*DCF)>>16;
    //-----------------------------------------------------------------

roland_sawstring_demo_on_the_lpc810_micro_synth.c

C/C++
roland_sawstring_demo_on_the_lpc810_micro_synth.c
//**************************************************************************/
//    Analog Modeling Synth main code
//**************************************************************************/
#include "wiring.h"
#include "LPC8xx.h"

/* Control register bit definition. */
#define MRT_INT_ENA          (0x1<<0)
#define MRT_REPEATED_MODE    (0x00<<1)
#define MRT_ONE_SHOT_INT     (0x01<<1)
#define MRT_ONE_SHOT_STALL   (0x02<<1)

/* Status register bit definition */
#define MRT_STAT_IRQ_FLAG    (0x1<<0)
#define MRT_STAT_RUN         (0x1<<1)

#define SAW 0
#define SQUARE 1
#define SINE 2


//-------- Synth parameters --------------
uint8_t WAVEFORM=SAW;     //SAW/SQUARE/SINE
uint32_t FREQ1 = 0x10000; //0x10000=C4
uint32_t FREQ2 = 0x10100; //0x10000=C4
uint32_t FREQ3 = 0x0FF00; //0x10000=C4
int32_t CUTOFF=65535;     //freq 0-65535
int32_t RESONANCE=0;      //reso=0-65535
uint8_t TRIG=1;           //MIDItrig 1=note ON
uint32_t ATTACK=98;		  //Attackrate in 30mS steps
uint32_t DECAY=98;        //Decayrate in 30mS steps
int32_t SUSTAIN=0xFFFF;   //Sustainlevel 0-65535
uint32_t RELEASE=1;       //Releaserate in 30mS steps
//-----------------------------------------


volatile uint16_t DAC=0;

uint32_t DCO1;
uint32_t DCO2;
uint32_t DCO3;

uint8_t state=0;    //needs to be reset on a new trig
uint16_t envstat=1; //needs to be reset on a new trig
int32_t volume=0;

int32_t t1;
int32_t t2;
int32_t t3;
int32_t t4;
int32_t t5;
int32_t t6;
int32_t t7;
int32_t t8;

int32_t vi;
int32_t vo;

int16_t DCO;
int16_t DCF;
int32_t ENV;
int16_t LFO;
uint16_t lfocounter=1;
uint8_t phase;



const int16_t sine[256] = {
		   0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
		   0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
		   0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
		   0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
		   0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
		   0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
		   0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
		   0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
		   0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
		   0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
		   0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
		   0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
		   0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
		   0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
		   0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
		   0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
		   0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e,
		   0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef,
		   0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86,
		   0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be,
		   0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a,
		   0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc,
		   0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d,
		   0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a,
		   0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3,
		   0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894,
		   0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc,
		   0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c,
		   0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c,
		   0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22,
		   0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5,
		   0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc
};

void MRT_IRQHandler(void) {

  pinMode(3,INPUT);

  if ( LPC_MRT->Channel[0].STAT & MRT_STAT_IRQ_FLAG ) {
    LPC_MRT->Channel[0].STAT = MRT_STAT_IRQ_FLAG;      /* clear interrupt flag */


    //-------------------- 3 DCO block ------------------------------------------
    DCO1 += FREQ1; //increment phase accumulator1 with phase1
    DCO2 += FREQ2; //increment phase accumulator2 with phase2
    DCO3 += FREQ3; //increment phase accumulator3 with phase3
    switch (WAVEFORM) {
        case SAW:
          DCO=((((DCO1 & 0x7FFFFF)+(DCO2 & 0x7FFFFF)+(DCO3 & 0x7FFFFF))/65536)-192)*171;
          break;
        case SQUARE:
          DCO=((((DCO1 & 0x400000)+(DCO2 & 0x400000)+(DCO3 & 0x400000))/65536)-96)*341;
          break;
        case SINE:
          DCO=(sine[(DCO1>>15)&255]/4)+(sine[(DCO2>>15)&255]/4)+(sine[(DCO3>>15)&255]/4);
          break;
    }
    //---------------------------------------------------------------------------


    //---------------- DCF block ---------------------------------------
    //C implementation for a 4pole lowpass DCF with resonance:

    vi=DCO;
    vo = ((vo * (65536 - CUTOFF)) + (t1 * CUTOFF))/65536; //+3db
    t1 = ((t1 * (65536 - CUTOFF)) + (t2 * CUTOFF))/65536; //+6db
    t2 = ((t2 * (65536 - CUTOFF)) + (t3 * CUTOFF))/65536; //+9db
    t3 = ((t3 * (65536 - CUTOFF)) + (t4 * CUTOFF))/65536; //+12db
    t4 = ((t4 * (65536 - CUTOFF)) + (t5 * CUTOFF))/65536; //+15db
    t5 = ((t5 * (65536 - CUTOFF)) + (t6 * CUTOFF))/65536; //+18db
    t6 = ((t6 * (65536 - CUTOFF)) + (t7 * CUTOFF))/65536; //+21db
    t7 = ((t7 * (65536 - CUTOFF)) + (t8 * CUTOFF))/65536; //+24db
    t8 = vi-((vo*RESONANCE)/65536);                     //resonance feedback
    DCF=vo;
    //-----------------------------------------------------------------

    //--------------------- ENV block ---------------------------------
    if (!envstat--) {
    envstat=1024;
    if (TRIG>0) {
    	if (state==0) {
    		volume += ATTACK;
    		if (volume>0xFFFF) {
    			volume=0xFFFF;
    			state++;
    		}
    	}
    	if (state==1) {
    		volume -= DECAY;
    		if (volume<SUSTAIN) {
    			volume=SUSTAIN;
    			state++;
    		}
    	}

    else {
    		volume -= RELEASE;
    		if (volume<0) {
    			volume=0;
    		}
    }
    }
    }
    ENV=(volume*DCF)>>16;
    //-----------------------------------------------------------------

    DAC=0x8000+ENV;




  }
  pinMode(3,OUTPUT);
  return;
}

void mrtInit(uint32_t delay)
{
  /* Enable clock to MRT and reset the MRT peripheral */
  LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<10);
  LPC_SYSCON->PRESETCTRL &= ~(0x1<<7);
  LPC_SYSCON->PRESETCTRL |= (0x1<<7);

  LPC_MRT->Channel[0].INTVAL = delay;
  LPC_MRT->Channel[0].INTVAL |= 0x1UL<<31;

  LPC_MRT->Channel[0].CTRL = MRT_REPEATED_MODE|MRT_INT_ENA;

  /* Enable the MRT Interrupt */
#if NMI_ENABLED
  NVIC_DisableIRQ( MRT_IRQn );
  NMI_Init( MRT_IRQn );
#else
  NVIC_EnableIRQ(MRT_IRQn);
#endif
  return;
}

int main(void)
{
  /* Initialise the GPIO block */
	  /* Enable AHB clock to the GPIO domain. */
	  LPC_SYSCON->SYSAHBCLKCTRL |=  (1 << 6);
	  LPC_SYSCON->PRESETCTRL    &= ~(1 << 10);
	  LPC_SYSCON->PRESETCTRL    |=  (1 << 10);
      LPC_SWM->PINENABLE0 = 0xffffffffUL; //All 6 GPIO enabled
      /* Configure the multi-rate timer for 44K ticks */
      mrtInit(__SYSTEM_CLOCK/33488);
      pinMode(3,OUTPUT);


      while(1) {
    	  asm volatile(
    			                "        mov	r0,r3 \n"
    			                "        mov	r1,#0xA0 \n"
    			  	  	"        lsl    r1,#24   \n"   //r1=0xA000
    			  	  	"        mov	r2,#0x10   \n"
    			  	  	"        lsl    r2,#8    \n"
    			      		"        add	r2,#0x0C   \n" //r2=0x100C
    			  	  	"        add    r1,r2     \n"  //r1=0xA000100C LPC_GPIO_PORT->W0[3]
	  	    	  	  	"        mov	r6,#0xFF   \n"
	  	  	    	  	"        lsl    r6,#8    \n"
	      		    		"        add	r6,#0xFF   \n" //r6=0xFFFF
    			  	  	"        mov	r5,#0x01 \n"
    			      		"        lsl    r5,#16   \n"   //r5=0x00010000
    			  	  	"loop%=: ldrh   r7,[r0,#0]   \n"
    			  	  	"        add	r2,r7 \n"  //r2=phacc
    			  	  	"		 mov	r4,r2 \n"
    	    		  		"        and	r4, r5 \n"
    	    		  		"		 str	r4, [r1] \n" //LPC_GPIO_PORT->W0[3]
 		  			"        and	r2, r6 \n"
    			  	  	"		 mov    r4,#0  \n"
		  			"		 str	r4, [r1] \n" //LPC_GPIO_PORT->W0[3]
    	    		  		"		 b		loop%=        \n"
    			  	  	  	    : [dac] "=m" (DAC)
    	    		  );

    	  
       }
}

Credits

Jan Ostman

Jan Ostman

34 projects • 161 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.

Comments