RobG 1,892 Posted November 10, 2012 Share Posted November 10, 2012 If you want to use oversampling then yes, UCA0BR0 = 8, but UCA0MCTL = UCOS16, no modulation bit (UCBRS0) Quote Link to post Share on other sites
larryfraz 9 Posted November 19, 2012 Author Share Posted November 19, 2012 Got the synth working with HW UART, Also added an attack control,and osc3 detune, as well as an LFO. Link is above! perspectivesound[dot]blogspot com. Quote Link to post Share on other sites
larryfraz 9 Posted December 14, 2012 Author Share Posted December 14, 2012 Here's a new clip of Lucy I think I got some noob luck with this and may enter it in POTM!? Lucy.brd image: Quote Link to post Share on other sites
larryfraz 9 Posted December 14, 2012 Author Share Posted December 14, 2012 #include <msp430g2553.h> #include "uart.h" #define CLOCKHZ 16000000 / 8 #define nNotes 12 //Lucy Lo-Res PWM Audio Synthesizer // By Larry Frazier, based on code by NatureTM, 43Oh group // Poly not implemented, but this is how // many notes can be hit at the same time // without forgetting the first #define MAX_POLYPHONY 5 #define MIDI_CHANNEL 0 // MIDI is 1-indexed so setting this to 0 is midi channel 1 #define USI_COUNTER_LOAD 16 // Synth variables unsigned int periodSetting = 61156; unsigned int osc2Period; unsigned int osc2Delta = ((61156)>>12); unsigned int osc2Diff; const unsigned int synthNotes[nNotes] = {61156, 57723, 54484, 51424, 48539, 45817, 43245, 40816, 38527, 36364, 34322, 32396}; // MIDI Variables char currentState = 1; char bitStateCount = 0; char nextBitFinal = 0; char opcode; char midiByte; char rawMidiByte; char newByte = 0; char newVelocity; char newNote; char notes[MAX_POLYPHONY] = {0}; char velocities[MAX_POLYPHONY] = {0}; char controllerNumber; char controllerValue; int noteIndex = 0; unsigned int USIData = 0; char newStat =0; char nextByte; char detuneAmt = 2; char osc2Vol=2; char osc2Pass =0; char osc3Vol= 63; char osc3Pass=0; char osc3Delta=0; unsigned int osc3Period; char intervals[8] = {0,2,3,4,5,7,9,10}; char osc3Int = 5; char osc3Phase =64; char osc3LastPhase; char osc3In= 64; char attack=64; int attVal; int i = 0; unsigned int out; char lfo1Speed; char lfo1Src; char lfo1Val; char lfo1Shape; char lfo1Counter; int vOsc2Detune =2; char lfoOut; int j; int lfoCounter; enum { saw1, saw2, tri1, tri2 }; void updateSynth(char on); char getNextByte(); void updateState(); void noteOn(); void noteOff(); void controlChange(); void updateControls(); void shiftLeft(char index); char getNoteIndex(char note); unsigned int getPWMValue(); char getAttValue(); unsigned int getOsc3Value(); void setOsc2Values(); void setOsc3Values(); char lfo( char shape, char value, char speed); void setLfo(); void uart_rx_isr(unsigned char c) { uart_putc(c); } void main(void) { volatile unsigned long i; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; BCSCTL2 |= DIVS_2; // SMCLK = MCLK / 4 = 4MHZ WDTCTL = WDTPW + WDTHOLD; // Stop WDT _BIS_SR(GIE); // enable interrupts P1DIR |= BIT0 + BIT6; // output P1OUT = 0; TA1CCTL1 = OUTMOD_7; // CCR1 reset/set P2DIR |= BIT1 + BIT2; P2OUT = 0; //output 2.2 TA1CTL = TASSEL_2 + MC_1 + ID_3; // SMCLK, up mode, /8 = 500KHz TA1CCTL0 |= CCIE; TA1CCR0 = 1; uart_init(); // register ISR called when data was received uart_set_rx_isr_ptr(uart_rx_isr); __bis_SR_register(GIE); while(1){ opcode = getNextByte(); if(opcode == (0x90 | MIDI_CHANNEL)) noteOn(); else if(opcode == (0x80 | MIDI_CHANNEL)) noteOff(); else if(opcode == (0xB0 | MIDI_CHANNEL)) controlChange(); } } void noteOn(){ do{ newNote = getNextByte(); if(newNote & 0x80){ newStat = 1; break; } newVelocity = getNextByte(); if(newVelocity & 0x80){ newStat = 1; break; } updateState(); }while(1); } void noteOff(){ do{ newNote = getNextByte(); if(newNote & 0x80){ newStat = 1; break; } newVelocity = 0; updateState(); }while(1); } void controlChange(){ do{ controllerNumber = getNextByte(); if(controllerNumber & 0x80){ newStat = 1; break; } controllerValue = getNextByte(); if(controllerValue & 0x80){ newStat = 1; break; } updateControls(); }while(1); } void updateControls(){ if(controllerNumber ==1){// controller 1 == mod wheel ==osc2 detune detuneAmt = (controllerValue>>4)+1;//scaled input setOsc2Values(); } if(controllerNumber == 7){//controller 7 == slider ==osc2 volume osc2Vol = controllerValue>>1; if (osc2Vol == 0) osc2Vol = 1; } if(controllerNumber == 11) { osc3Vol = (controllerValue>>4);// scaled osc3 volume if (osc3Vol == 0) osc3Vol = 1;} if(controllerNumber == 10) { osc3In = (controllerValue>>2);// this is not phase. equal number of Hz detune, I tried to fix this but it didn't sound as interesting if (osc3In == 0) osc3In = 1; if (osc3In > osc3LastPhase) { osc3Phase = periodSetting/(osc3In - osc3LastPhase); }else { periodSetting/(osc3Phase = osc3LastPhase -osc3In); } } if(controllerNumber == 12) { osc3Int = intervals[controllerValue>>3];// choose interval to detune setOsc3Values(); } if(controllerNumber == 13) { attack = (controllerValue>>4);// scaled attack value if (attack == 0) attack = 1;} if(controllerNumber == 91) { lfo1Shape = (controllerValue>>5);// index for lfo shape //if (lfo1Shape == 0) //lfo1Shape = 1; } if(controllerNumber == 93) { lfo1Speed = (controllerValue>>2 );// nothing special about these controller numbers, its just how my mk249c is laid out if (lfo1Speed == 0) lfo1Speed = 1;} } void setOsc2Values() {osc2Diff = (periodSetting>>vOsc2Detune); } unsigned int getPWMValue(){ unsigned int outVal; // shift left detuneAmt value bits => this is how much longer the period of osc2 is than osc1 if(osc2Pass == 0) { osc2Delta =osc2Delta+(osc2Diff); // keep doubling the delta till it laps if(osc2Delta >= periodSetting) { osc2Pass = 1; } } else{ osc2Delta =osc2Delta-(osc2Diff); // keep doubling the delta till it laps if(osc2Delta <= osc2Diff) { osc2Pass = 0; } } outVal = osc2Delta; return outVal; } void setOsc3Values() { osc3Period = (synthNotes[notes[noteIndex+osc3Int] % 12]>> ((notes[noteIndex+osc3Int] / 12)-1)); //octave down } unsigned int getOsc3Value(){ unsigned int outVal; // shift left detuneAmt value bits => this is how much longer the period of osc2 is than osc1 if(osc3Pass == 0) { osc3Delta = osc3Phase +osc3Delta+(osc3Period-periodSetting); // keep doubling the delta till it laps if(osc3Delta >= periodSetting ) { osc3Pass = 1; } } else{ osc3Delta =(osc3Phase +osc3Period-periodSetting); // keep doubling the delta till it laps if(osc3Delta <= periodSetting ) { osc3Pass = 0; } } outVal = osc3Delta; return outVal; } char getAttValue() { unsigned int time = 500000/attack; unsigned int cycles =(time/periodSetting); if ((attVal>1)&&(cycles>0)) { if(out ==0) { attVal=attVal>>1; out =cycles; }else out-- ; } else attVal = 1; return attVal; } void setLfo() { vOsc2Detune = lfo(lfo1Shape, detuneAmt, lfo1Speed); setOsc2Values(); } char lfo( char shape, char value, char speed) { lfoCounter = lfo1Counter; char firstHalf =1; unsigned int time = 500000/speed; unsigned int cycles =(time/periodSetting); switch(shape) { case saw1: case saw2: {if ((lfoCounter>=1)&&(cycles>0)) { if(j ==0) { lfoCounter=lfoCounter-1; j =cycles; } else j--; } else lfoCounter =1; if(shape == saw2) lfoOut = (value *(127 - lfoCounter))/127;//flip the saw wave else lfoOut = (value *lfoCounter)/127; } break; case tri1: case tri2: {if ((lfoCounter>=1)&&(cycles>0)) { if(j ==0) { if(firstHalf) lfoCounter=lfoCounter-2; else lfoCounter=lfoCounter+2; j =cycles; } else j--; if(lfoCounter<=1) firstHalf = 0; } else lfoCounter =1; if(shape == tri2) lfoOut = (value *(127 - lfoCounter))/127;//flip the triangle wave else lfoOut = (value *lfoCounter)/127; } break; } return lfoOut; } char getNextByte(){ if(newStat) { newStat = 0; return nextByte; } else { do{ P1OUT &= ~BIT0; while(!newByte){ } nextByte = uart_getByte(); }while((nextByte == 0xFE) || (nextByte == 0xFF)); P1OUT |= BIT0; return nextByte; } } #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_A0 (void){ setLfo(); TA1CCR0 = periodSetting; TA1CCR1 = ((getPWMValue()/osc2Vol +periodSetting)+(getOsc3Value()/osc3Vol))/(4*getAttValue());//(CCR0 >> 1); } void updateState(){ if(noteIndex == 0 && newVelocity != 0){ notes[0] = newNote; velocities[0] = newVelocity; updateSynth(1); noteIndex++; attVal = 127; out =0; lfoOut =0xFF; lfo1Counter =127; } else{ if(newVelocity != 0){ // add a new note when the poly cache is full, replacing the oldest if(MAX_POLYPHONY == noteIndex){ shiftLeft(0); notes[MAX_POLYPHONY - 1] = newNote; velocities[MAX_POLYPHONY - 1] = newVelocity; updateSynth(1); } // add a new note else{ notes[noteIndex] = newNote; velocities[noteIndex] = newVelocity; updateSynth(1); noteIndex++; } attVal = 127;//init values for new note sounding out =0; lfoOut =0xFF; lfo1Counter =127; } else if(getNoteIndex(newNote) < MAX_POLYPHONY){ shiftLeft(getNoteIndex(newNote)); noteIndex -= 2; if(noteIndex >= 0){ updateSynth(1); noteIndex++; } else{ updateSynth(0); noteIndex = 0; } } } } void shiftLeft(char index){ int i; for(i = index; i < MAX_POLYPHONY - 1; i++){ notes[i] = notes[i + 1]; velocities[i] = velocities[i + 1]; } } char getNoteIndex(char note){ int i; for(i = 0; i < MAX_POLYPHONY; i++) if(notes[i] == note) return i; return MAX_POLYPHONY + 1; } void updateSynth(char on){ if(on){ P2SEL |= BIT2; P1OUT ^= BIT6; } else{ P2SEL &= ~BIT2; P1OUT ^= BIT6; } if(noteIndex >= 0 && noteIndex < MAX_POLYPHONY){ periodSetting = (synthNotes[notes[noteIndex] % 12] >> (notes[noteIndex] / 12)); setOsc2Values();//set more vals here!?! setOsc3Values(); } } /* * This file is part of the MSP430 hardware UART example. * * Copyright © 2012 Stefan Wendler <sw@kaltpost.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /****************************************************************************** * Hardware UART example for MSP430. * * Stefan Wendler * sw@kaltpost.de * http://gpio.kaltpost.de * *****************************************************************************/ #ifndef __UART_H #define __UART_H /** * Initialize soft UART */ void uart_init(void); /** * Set pointer for ISR to call when data was received. * * @param[in] *isr_ptr pointer to ISR */ void uart_set_rx_isr_ptr(void (*isr_ptr)(unsigned char c)); /** * Read one character from UART blocking. * * @return character received */ unsigned char uart_getc(); /**return next byte in buffer * * @return next byte recieved * */ unsigned char uart_getByte(); /** * Write one chracter to the UART blocking. * * @param[in] *c the character to write */ void uart_putc(unsigned char c); /** * Write string to the UART blocking. * * @param[in] *str the 0 terminated string to write */ void uart_puts(const char *str); #endif /* * This file is part of the MSP430 hardware UART example. * * Copyright © 2012 Stefan Wendler <sw@kaltpost.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /****************************************************************************** * Hardware UART example for MSP430. * * Stefan Wendler * sw@kaltpost.de * http://gpio.kaltpost.de * modified by Larry Frazier (buffered input) larryfraz@yahoo.com * perspectivesound,blogspot.com ******************************************************************************/ #include <msp430.h> #include "msp430g2553.h" //#include <legacymsp430.h> #include "uart.h" /** * Receive Data (RXD) at P1.1 */ #define RXD BIT1 /** * Transmit Data (TXD) at P1.2 */ #define TXD BIT2 /** * Callback handler for receive */ extern char newByte; extern char midiByte; char buffer[256]; char ptr = 0; char bufOutPtr =0; void (*uart_rx_isr_ptr)(unsigned char c); void uart_init(void) { uart_set_rx_isr_ptr(0L); P1SEL = RXD ; P1SEL2 = RXD ; UCA0CTL1 |= UCSSEL_2; // SMCLK==4mhz UCA0BR0 = 8; // DIVIDES SMCLK = 31250 = MIDI SPEC w/UCOS16 oversample UCA0BR1 = 0; // UCA0MCTL |= UCOS16; // 16x oversample UCA0CTL1 &= ~UCSWRST ; // Initialize USCI state machine IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt } void uart_set_rx_isr_ptr(void (*isr_ptr)(unsigned char c)) { uart_rx_isr_ptr = isr_ptr; } unsigned char uart_getc() { while (!(IFG2&UCA0RXIFG)); // USCI_A0 RX buffer ready? return UCA0RXBUF; } void uart_putc(unsigned char c) { while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? UCA0TXBUF = c; // TX } unsigned char uart_getByte() { midiByte = buffer[bufOutPtr++]; if (bufOutPtr>255) bufOutPtr=0; if (bufOutPtr==ptr) newByte = 0; return midiByte; } void uart_puts(const char *str) { while(*str) uart_putc(*str++); } #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { //interrupt(USCIAB0RX_VECTOR) USCI0RX_ISR(void) if(uart_rx_isr_ptr != 0L) { (uart_rx_isr_ptr)(UCA0RXBUF);} //if((UCA0RXBUF != 0xFF )&& (UCA0RXBUF != 0xFE)) //{ midi messages to not add buffer[ptr++] = UCA0RXBUF; if(ptr > 255) ptr = 0; newByte = 1; //} } Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.