Jan Ostman
Published

Micro Virtual Analog Synthesizer

Can the LPC810 ARM MCU play music?

Full instructions provided4,487
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
34 projects • 167 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.
Contact

Comments

Please log in or sign up to comment.