Reply by Wayne S April 28, 20122012-04-28
I have not read all the posts in this string, but David W. Schultz post strikes
a chord with me :-).

The approach sounds similar to something I did to implement a HART modem
which shifted between 1200Hz and 2200Hz. I used DMA to output to an
external 6 bit DAC and used phase into a sine table lookup. I'm using an
MSP430F5310. I also use a double buffer DMA approach with the DMA
triggered at 19200 rate. The only interrupt critical step is every milliSecond
the DMA interrupt has to be serviced to start the next buffer. Then I
pre-compute the next buffer. The phase variable is incremented at the
appropriate rate for the frequency output. I used a timer to trigger the
DMA at 19200 rate. which is 16x 1200. The 5310 has a decent amount
of memory, so my buffers were large.

Use a phase variable for each frequency, index into the sine table and
add the results. With double buffering the DMA output gives you time
to pre-compute the next buffer signal. It seems like what you want to
do should be possible. The sample rate, buffer size determine the
DMA interrupt rate.

case DMAIV_DMA0IFG:
// set up DMA 1
DMACTL0 = DMA1TSEL__TA0CCR2;
DMA1CTL |= DMAEN;
// set up next buffer
toggle_bit(tx_buf, 1);
ops_SetFlagTask(HartMod_TxByte);
ops_ExitLowPower();
break;

case DMAIV_DMA1IFG:
// set up DMA 0
DMACTL0 = DMA0TSEL__TA0CCR2;
DMA0CTL |= DMAEN;
// set up next buffer
toggle_bit(tx_buf, 1);
ops_SetFlagTask(HartMod_TxByte);
ops_ExitLowPower();
break;

PS, I needed to use the SMCLK at a fairly fast rate, I also stopped the FLL
as it causes this clock to jump around. It also means Low power mode
is limited to keeping the FLL off and only shutting off the CPU. This
results in about 0.5% frequency accuracy, which was acceptable in
my case.

Good luck

At 4/24/2012 10:48 PM, you wrote:
>On 04/24/2012 04:35 PM, zylaxice wrote:
>> Hi all, I am currently working on some code for an MSP430F2619. I am
>> using a 32-value sine lookup table, and pushing the sequential values
>> out to the DAC12 via DMA, with the speed (and thus the note
>> frequency) controlled by TimerB. So far,this is working well. I can
>> produce any number of reasonable sounding pure tones/notes at
>> frequencies from 130.8Hz (C3) to 987.7Hz (B5), and this is more than
>> enough range for my needs, three full octaves.
>>
>> However, this only plays one tone at a time. I have been wracking my
>> brains trying to figure out how to use this to generate a "chord,"
>> more than one note played at the same time. I know that musically
>> this can be as simple as adding two sine waves together, but since I
>> don't have two simultaneously existing sine waves, just one that I
>> change the frequency of, I am at a loss.
>>
>> Does anyone have any suggestions on how to achieve this, or
>> references that they think might push me in the right direction?
>>
>> Thank you, David
>>The obvious way, although you can't use the DMAC for it, is the Direct
>Digital Synthesis (DDS) method of using a phase register.
>
>You have one phase register of say 16 bits per tone. At each timer tick
>you add a number to the phase register. The magnitude is different for
>each tone and determines the period. Then use the upper 5 bits of each
>phase register to index into the sine table, add the results together,
>and send it to the DAC.
>
>--
>David W. Schultz
>http://home.earthlink.net/~david.schultz
>"Who? What? Where? When? Aahhhg!" - Duck Dodgers

Beginning Microcontrollers with the MSP430

Reply by Onestone April 28, 20122012-04-28
I don't think it really is the way to do it. You have 31.6 us for a
987.7Hz tone on a fairly crude 32 step table. Given that this is a sine
table, you cannot simply interpolate linearly between steps, your steps
* 32768 are:-
0
6392.7 2589
12538.7
18204.9
23170.4
27245.6
30273.6
32138.3
32768
...etc

linear interpolation leads to a scaled value of 2589 vs 2602 for the
first step at 400hz, a small 0.5% error, but this varies with frequency,
and step number, add to those errors for all notes in a chord and it
could sound quite discordant. then again you have to perform multiple
interpolations in 505 clock cycles at 16Mhz. Even with tables to store
the step intervals for all possible notes in 3 octaves you still have to
perform some simple maths, as well as modifying non-linear notes into
linear addresses. This method reduces the potential for jitter that
exists with my simple scheme, since there is only one interrupt, but the
problem then lies in doing all the calculations in the 505 clock cycles
between steps.

At the end of the day the optimum solution really depends on what the Op
really needs to achieve. Given a few simple tunes and the huge memory on
the 2619 I'd do it all with tables, given a limit of 3 octaves and
therefore a limited number of possible chords you could also do that in
tables, and handle pure tones as he was previously.

Al
On 28/04/2012 7:39 AM, Dana Myers wrote:
> Robert - that's *exactly* what I was suggesting, explained differently.
> It's
> really the way to do it.
>
> Dana
> On Fri, Apr 27, 2012 at 7:58 AM, Onestone wrote:
>
>> **
>> So many ways to skin that cat!
>>
>> Al
>> On 28/04/2012 12:20 AM, Robert wrote:
>>> How about you have a sine table, but instead of setting your interrupt
>> time based on a single frequency divided by the # of samples, you instead
>> pick a fixed interrupt time. For example, it seems your fastest interrupt
>> rate currently would be at (1/987.7 Hz)/32 = 31.6 us. So use that as your
>> interrupt time all the time.
>>> At each interrupt, you calculate for each sine wave where you'll be in
>> that list of 32 samples, 0 - 31. If you're trying to create a sine wave at
>> 400 Hz, your increment each interrupt would be (400 Hz/987.7 Hz). Calculate
>> this using fixed-point #s, or course, such as 8p8. Since you have a limited
>> number of tones, the increment can be precalculated for each one.
>>> Now, you when you get an interrupt, for each frequency, you add to a
>> position value by the increment for each frequency and take the
>> corresponding value from the sine wave table. Since you're in between two
>> values, you'll probably want to extrapolate between the two values in the
>> table. Do this for each frequency and add them together.
>>> Whether you can get this done in 31.6 us, I don't know, but it seems
>> like a clean way of getting tones, and is scalable up until you run out of
>> CPU cycles.
>>> --- In m..., Onestone wrote:
>>>> Hi Matthias, I still think you're misunderstanding. First of all two
>>>> tones would never require the same CCR, secondly chords don't contain
>>>> duplicates of the same note (at least in my experience), so 7 unique
>>>> tones can be played simultaneously with 7 CCr registers. And those tones
>>>> can vary in real time, ie register CCRB1 doesn't have to be C, at each
>>>> note, a fresh set of unique notes are available. My code sample
>>>> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
>>>> case. In the case of a 16MHz clock 7 tones would require 217 clock
>>>> cycles maximum to process in the isrs, plus whatever overhead is needed
>>>> in the foreground routine, so there would still be obvious limits to the
>>>> maximum access rate. However since the OP wants a range from 130.8Hz to
>>>> 987.7Hz a worst case event would mean an upper limit of 74 entries per
>>>> table. however there is nothign to stop the user from having tables of
>>>> different resolutions, or of varying the step size for different notes.
>>>> ie a 256 entry table played at a fixed rate to give 100Hz would give a
>>>> 200hz output if the step through the table was 2 instead of 1. this is,
>>>> of course, another way of getting a wide frequency range using a single
>>>> clock source. In this case longer tables sound better than short ones.
>>>> In the case of a single table with variable step sizes to create notes
>>>> of different frequencies it would be possible to use a single timer, and
>>>> simply add all the different values for each step interval in a single
>>>> ISR, however the range of frequencies is more limited. If I remember my
>>>> note frequencies there are a limited number of base frequencies, and
>>>> then the harmonics of these, which the above method results in, form the
>>>> remaining available notes, so a combination of methods could well work.
>>>>
>>>> Of course, having said all of this, if the OP only needs to play a few
>>>> different note combinations, or a few short tunes then, given the huge
>>>> amount of available memory why note simply pre-calculate them and store
>>>> them in flash?
>>>>
>>>> Al
>>>>
>>>>
>>>> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
>>>>> Onestone:
>>>>>
>>>>>> Hi Matthias. The idea is to use a single table, but probably a higher
>>>>>> resolution table than 32 entries, and to still use the basic concept
>> of
>>>>>> timed access to generate different notes. It would be virtually
>>>>>> impossible, I believe, to do this with a single timer, and limited
>>>>>> jitter, how would you work out the next time interval for, say a 4
>> note
>>>>>> chord? where the frequencies are not some convenient binary multiple?
>>>>> Hi Al,
>>>>>
>>>>> It seems I understand your algorithm quite different then you. Each
>> note
>>>>> use it's own counter (e.g. the 7 CCR registers) for the sample clock.
>>>>>
>>>>>> Then, where one note is a much higher frequency than another you have
>>>>>> multiple instances of the higher note per instance of the lower note,
>> so
>>>>>> tracking order of tones with a single timer becomes cpu intensive.
>>>>> That is true. You need to prepare the settings for the next tone in the
>>>>> mainloop (CCR and position in the lookup table). One idea is a sorted
>> table
>>>>> in RAM, sorted by next CCR. A special case has to be handled if 2 (or
>> more)
>>>>> tones requires the same CCR. Even with your method the jitter is
>> higher in
>>>>> case 2 (or more) CCR-interrupts need to get served at the same
>> CCR-value.
>>>>> However my method is only suitable for very low frequencies.
>>>>>
>>>>> M.
>>>>>
>>>>>> Certainly it would be far easier to use a single timer per tone. Also
>>>>>> you'd need to take scaling into account. By using a timer per note you
>>>>>> reduce the calculations (using a differential sine table) to DACOUT >>>>>> DACOUT + TABLE(Nx) where N is the table entry, x is the tone, and
>> TABLE
>>>>>> is a table of signed differential sine values. The simplest form of
>> this
>>>>>> would use 1 register per note, so N1 =R4, N2 = R5 etc. Then the ISR
>>>>>> becomes simply:-
>>>>>>
>>>>>> TB1_ISR:
>>>>>> ADD&DACOUT,TABLE(R4)
>>>>>> ADD&N1INTERVAL,&CCRB1
>>>>>> BIC #CCIFG,&CCTLB1
>>>>>> INCD R4
>>>>>> ;ENTRIES ARE WORDS
>>>>>> AND #0X00FE,R4 ;ASSUMES
>>>>>> 256 ENTRY TABLE
>>>>>> RETI
>>>>>>
>>>>>> To overcome scaling issues and the need for a little maths you could
>>>>>> easily have tables for single tones, 2 note chords, up to 7 note
>> chords
>>>>>> Cheers
>>>>>>
>>>>>> Al
>>>>>>
>>>>>> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
>>>>>>> Onestone,
>>>>>>> your code is quite good (after some thinking I am now sure that it is
>>>>>>> working:-). One improvement: should be possible to do it with just
>> one
>>>>>>> CCR- channel.
>>>>>>>
>>>>>>> M.
>>>>>>>
>>>>>>> Onestone:
>>>>>>>
>>>>>>>> being a simple kind of guy I think my method is just too easy! 8-)
>>>>>>>>
>>>>>>>> Al
>>>>>>>>
>>>>>>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
>>>>>>>>> In case you are comfortable with 2 mixed sine waves just use both
>>>>>>>>> DAC's, feed them independly and add them analog at the output pin
>>>>>>>>> with 2 resistors.
>>>>>>>>>
>>>>>>>>> Another way: create a lookup table for your "chords".
>>>>>>>>> In your current code you always use 32 steps for each sine wave -
>> for
>>>>>>>>> one wave a step is e.g. 300us for the 2nd wave it is 310us. To mix
>>>>>>>>> them digitally you need finer steps.
>>>>>>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine
>> waves
>>>>>>>>> into that RAM-table according to the frequencies you want. Feed
>> this
>>>>>>>>> RAM-table with the fastest clock (987Hz is about 1ms) to the DAC.
>> For
>>>>>>>>> example in a 256 table the 987Hz wave fits 7.55 times, the 130Hz
>>>>>>>>> waves only 1 time. For the 130Hz tone you have to calculate 256
>>>>>>>>> values from you 32 values of the lookup table. This is called
>>>>>>>>> upsampling. You can use linear interpolation (lines) to calculate
>> the
>>>>>>>>> values between the 32 lookup values from your Flash table (or drop
>>>>>>>>> the lookup table and use sin() from the C compiler, no idea how
>> fast
>>>>>>>>> this is). The big deal here is, that in most cases the end of the
>> RAM
>>>>>>>>> table does not fit to the begin of the RAM table, the waves are not
>>>>>>>>> connected smoothly together. You have to calculate a new RAM table
>>>>>>>>> once the first one has been sent, so that the waves are smoothly
>>>>>>>>> connected. Use 2 RAM tables, one for output (DMA), one for
>>>>>>>>> precalculation (in the main loop).
>>>>>>>>>
>>>>>>>>> You can do the interpolation on the fly in the CCR-Interrupt
>> routine,
>>>>>>>>> no extra RAM table, no DMA needed (however, the sound will not be
>>>>>>>>> clear because of the jitter of the interrupt response time).
>>>>>>>>>
>>>>>>>>> M.
>>>>>>>>>
>>>>>>>>> Onestone:
>>>>>>>>>
>>>>>>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd use
>>>>>>>>>> 1 timer per tone, and track the last value for each tone. Then on
>>>>>>>>>> timer interrupt:-
>>>>>>>>>>
>>>>>>>>>> DACx = DACx - oldsinevalue + newsinevalue.
>>>>>>>>>>
>>>>>>>>>> Effectively remove the old value for the tone from the DAC and add
>>>>>>>>>> the new one at a variabe time interval. Also, given something with
>>>>>>>>>> as much memory as the 2619 i'd not limit myself to a 32 entry
>> table.
>>>>>>>>>> In theory, and assuming that you aren't using the other timers,
>> you
>>>>>>>>>> could get 7 tones using timer B. I'd also go for the highest clock
>>>>>>>>>> frequency possible, and in the ISR keep the code short and clean.
>>>>>>>>>> for minimal jitter. Rather than absolute values your table could
>>>>>>>>>> comprise differential values so that your calculation is simple
>> DACx
>>>>>>>>>> = DACx + sine(n).
>>>>>>>>>>
>>>>>>>>>> Hope this helps
>>>>>>>>>>
>>>>>>>>>> Al
>>>>>>>>>>
>>>>>>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
>>>>>>>>>>> Hi all,
>>>>>>>>>>> I am currently working on some code for an MSP430F2619. I am
>>>>>>>>>>> using a 32-value sine lookup table, and pushing the sequential
>>>>>>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
>>>>>>>>>>> note frequency) controlled by TimerB. So far,this is working
>>>>>>>>>>> well. I can produce any number of reasonable sounding pure
>>>>>>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
>>>>>>>>>>> and this is more than enough range for my needs, three full
>>>>>>>>>>> octaves.
>>>>>>>>>>>
>>>>>>>>>>> However, this only plays one tone at a time. I have been wracking
>>>>>>>>>>> my brains trying to figure out how to use this to generate a
>>>>>>>>>>> "chord," more than one note played at the same time. I know that
>>>>>>>>>>> musically this can be as simple as adding two sine waves
>> together,
>>>>>>>>>>> but since I don't have two simultaneously existing sine waves,
>> just
>>>>>>>>>>> one that I change the frequency of, I am at a loss.
>>>>>>>>>>>
>>>>>>>>>>> Does anyone have any suggestions on how to achieve this, or
>>>>>>>>>>> references that they think might push me in the right direction?
>>>>>>>>>>>
>>>>>>>>>>> Thank you,
>>>>>>>>>>> David
>>>>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
Reply by Onestone April 28, 20122012-04-28
The problem with this is that it cannot produce many common chords,
probably fine if the OP just wants a few simple fixed tunes, but not so
good where a wide range of common, current tunes need to be played, but
then if that were the case I'd go get a midi synth chip anyway, they're
cheap and extremely flexible. very little current music is written with
Just Intonation in mind. Most is still based around equal temperament.

It all depends on the OPs needs, and exactly what he has in mind, sinc
ehe's never stated whether this is an ad hoc musical program, or a few
simple fixed tunes it is up in the air.

Al

On 28/04/2012 9:27 AM, old_cow_yellow wrote:
> David,
>
> Try something simple first. Use Just Scale and generate multiple frequencies with simple ratios.
>
> (a) Find the smallest number that is divisible by all the frequencies.
> (b) Use a sampling rate that is an integer multiple of that number.
>
> For example, we can generate C3, E3 and G3 together.
> In Just Scale, we have: C3 = 128Hz, E3 = 160Hz and G3 = 192Hz.
> 1920 / 128 = 15; 1920 / 160 = 12; and 1920 / 192 = 10.
> We can use 3*1920 = 5760 samples/sec. (Or, instead of 3, some other integer.)
> Now we can use tables of 3*15 = 45 entries for C3. And 3*12 = 36 entries for E3. And 3*10 = 30 entries for G3.
>
> Be Just and Rational !
>
> --OCY
>
> --- In m..., "zylaxice" wrote:
>> Hi all,
>> I am currently working on some code for an MSP430F2619. I am using a 32-value sine lookup table, and pushing the sequential values out to the DAC12 via DMA, with the speed (and thus the note frequency) controlled by TimerB. So far,this is working well. I can produce any number of reasonable sounding pure tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5), and this is more than enough range for my needs, three full octaves.
>>
>> However, this only plays one tone at a time. I have been wracking my brains trying to figure out how to use this to generate a "chord," more than one note played at the same time. I know that musically this can be as simple as adding two sine waves together, but since I don't have two simultaneously existing sine waves, just one that I change the frequency of, I am at a loss.
>>
>> Does anyone have any suggestions on how to achieve this, or references that they think might push me in the right direction?
>>
>> Thank you,
>> David
>>
Reply by Dana Myers April 28, 20122012-04-28
Robert - that's *exactly* what I was suggesting, explained differently.
It's
really the way to do it.

Dana
On Fri, Apr 27, 2012 at 7:58 AM, Onestone wrote:

> **
> So many ways to skin that cat!
>
> Al
> On 28/04/2012 12:20 AM, Robert wrote:
> > How about you have a sine table, but instead of setting your interrupt
> time based on a single frequency divided by the # of samples, you instead
> pick a fixed interrupt time. For example, it seems your fastest interrupt
> rate currently would be at (1/987.7 Hz)/32 = 31.6 us. So use that as your
> interrupt time all the time.
> >
> > At each interrupt, you calculate for each sine wave where you'll be in
> that list of 32 samples, 0 - 31. If you're trying to create a sine wave at
> 400 Hz, your increment each interrupt would be (400 Hz/987.7 Hz). Calculate
> this using fixed-point #s, or course, such as 8p8. Since you have a limited
> number of tones, the increment can be precalculated for each one.
> >
> > Now, you when you get an interrupt, for each frequency, you add to a
> position value by the increment for each frequency and take the
> corresponding value from the sine wave table. Since you're in between two
> values, you'll probably want to extrapolate between the two values in the
> table. Do this for each frequency and add them together.
> >
> > Whether you can get this done in 31.6 us, I don't know, but it seems
> like a clean way of getting tones, and is scalable up until you run out of
> CPU cycles.
> >
> > --- In m..., Onestone wrote:
> >> Hi Matthias, I still think you're misunderstanding. First of all two
> >> tones would never require the same CCR, secondly chords don't contain
> >> duplicates of the same note (at least in my experience), so 7 unique
> >> tones can be played simultaneously with 7 CCr registers. And those tones
> >> can vary in real time, ie register CCRB1 doesn't have to be C, at each
> >> note, a fresh set of unique notes are available. My code sample
> >> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
> >> case. In the case of a 16MHz clock 7 tones would require 217 clock
> >> cycles maximum to process in the isrs, plus whatever overhead is needed
> >> in the foreground routine, so there would still be obvious limits to the
> >> maximum access rate. However since the OP wants a range from 130.8Hz to
> >> 987.7Hz a worst case event would mean an upper limit of 74 entries per
> >> table. however there is nothign to stop the user from having tables of
> >> different resolutions, or of varying the step size for different notes.
> >> ie a 256 entry table played at a fixed rate to give 100Hz would give a
> >> 200hz output if the step through the table was 2 instead of 1. this is,
> >> of course, another way of getting a wide frequency range using a single
> >> clock source. In this case longer tables sound better than short ones.
> >> In the case of a single table with variable step sizes to create notes
> >> of different frequencies it would be possible to use a single timer, and
> >> simply add all the different values for each step interval in a single
> >> ISR, however the range of frequencies is more limited. If I remember my
> >> note frequencies there are a limited number of base frequencies, and
> >> then the harmonics of these, which the above method results in, form the
> >> remaining available notes, so a combination of methods could well work.
> >>
> >> Of course, having said all of this, if the OP only needs to play a few
> >> different note combinations, or a few short tunes then, given the huge
> >> amount of available memory why note simply pre-calculate them and store
> >> them in flash?
> >>
> >> Al
> >>
> >>
> >> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
> >>> Onestone:
> >>>
> >>>> Hi Matthias. The idea is to use a single table, but probably a higher
> >>>> resolution table than 32 entries, and to still use the basic concept
> of
> >>>> timed access to generate different notes. It would be virtually
> >>>> impossible, I believe, to do this with a single timer, and limited
> >>>> jitter, how would you work out the next time interval for, say a 4
> note
> >>>> chord? where the frequencies are not some convenient binary multiple?
> >>> Hi Al,
> >>>
> >>> It seems I understand your algorithm quite different then you. Each
> note
> >>> use it's own counter (e.g. the 7 CCR registers) for the sample clock.
> >>>
> >>>> Then, where one note is a much higher frequency than another you have
> >>>> multiple instances of the higher note per instance of the lower note,
> so
> >>>> tracking order of tones with a single timer becomes cpu intensive.
> >>> That is true. You need to prepare the settings for the next tone in the
> >>> mainloop (CCR and position in the lookup table). One idea is a sorted
> table
> >>> in RAM, sorted by next CCR. A special case has to be handled if 2 (or
> more)
> >>> tones requires the same CCR. Even with your method the jitter is
> higher in
> >>> case 2 (or more) CCR-interrupts need to get served at the same
> CCR-value.
> >>> However my method is only suitable for very low frequencies.
> >>>
> >>> M.
> >>>
> >>>> Certainly it would be far easier to use a single timer per tone. Also
> >>>> you'd need to take scaling into account. By using a timer per note you
> >>>> reduce the calculations (using a differential sine table) to DACOUT > >>>> DACOUT + TABLE(Nx) where N is the table entry, x is the tone, and
> TABLE
> >>>> is a table of signed differential sine values. The simplest form of
> this
> >>>> would use 1 register per note, so N1 =R4, N2 = R5 etc. Then the ISR
> >>>> becomes simply:-
> >>>>
> >>>> TB1_ISR:
> >>>> ADD&DACOUT,TABLE(R4)
> >>>> ADD&N1INTERVAL,&CCRB1
> >>>> BIC #CCIFG,&CCTLB1
> >>>> INCD R4
> >>>> ;ENTRIES ARE WORDS
> >>>> AND #0X00FE,R4 ;ASSUMES
> >>>> 256 ENTRY TABLE
> >>>> RETI
> >>>>
> >>>> To overcome scaling issues and the need for a little maths you could
> >>>> easily have tables for single tones, 2 note chords, up to 7 note
> chords
> >>>>
> >>>> Cheers
> >>>>
> >>>> Al
> >>>>
> >>>> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
> >>>>> Onestone,
> >>>>> your code is quite good (after some thinking I am now sure that it is
> >>>>> working:-). One improvement: should be possible to do it with just
> one
> >>>>> CCR- channel.
> >>>>>
> >>>>> M.
> >>>>>
> >>>>> Onestone:
> >>>>>
> >>>>>> being a simple kind of guy I think my method is just too easy! 8-)
> >>>>>>
> >>>>>> Al
> >>>>>>
> >>>>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
> >>>>>>> In case you are comfortable with 2 mixed sine waves just use both
> >>>>>>> DAC's, feed them independly and add them analog at the output pin
> >>>>>>> with 2 resistors.
> >>>>>>>
> >>>>>>> Another way: create a lookup table for your "chords".
> >>>>>>> In your current code you always use 32 steps for each sine wave -
> for
> >>>>>>> one wave a step is e.g. 300us for the 2nd wave it is 310us. To mix
> >>>>>>> them digitally you need finer steps.
> >>>>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine
> waves
> >>>>>>> into that RAM-table according to the frequencies you want. Feed
> this
> >>>>>>> RAM-table with the fastest clock (987Hz is about 1ms) to the DAC.
> For
> >>>>>>> example in a 256 table the 987Hz wave fits 7.55 times, the 130Hz
> >>>>>>> waves only 1 time. For the 130Hz tone you have to calculate 256
> >>>>>>> values from you 32 values of the lookup table. This is called
> >>>>>>> upsampling. You can use linear interpolation (lines) to calculate
> the
> >>>>>>> values between the 32 lookup values from your Flash table (or drop
> >>>>>>> the lookup table and use sin() from the C compiler, no idea how
> fast
> >>>>>>> this is). The big deal here is, that in most cases the end of the
> RAM
> >>>>>>> table does not fit to the begin of the RAM table, the waves are not
> >>>>>>> connected smoothly together. You have to calculate a new RAM table
> >>>>>>> once the first one has been sent, so that the waves are smoothly
> >>>>>>> connected. Use 2 RAM tables, one for output (DMA), one for
> >>>>>>> precalculation (in the main loop).
> >>>>>>>
> >>>>>>> You can do the interpolation on the fly in the CCR-Interrupt
> routine,
> >>>>>>> no extra RAM table, no DMA needed (however, the sound will not be
> >>>>>>> clear because of the jitter of the interrupt response time).
> >>>>>>>
> >>>>>>> M.
> >>>>>>>
> >>>>>>> Onestone:
> >>>>>>>
> >>>>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd use
> >>>>>>>> 1 timer per tone, and track the last value for each tone. Then on
> >>>>>>>> timer interrupt:-
> >>>>>>>>
> >>>>>>>> DACx = DACx - oldsinevalue + newsinevalue.
> >>>>>>>>
> >>>>>>>> Effectively remove the old value for the tone from the DAC and add
> >>>>>>>> the new one at a variabe time interval. Also, given something with
> >>>>>>>> as much memory as the 2619 i'd not limit myself to a 32 entry
> table.
> >>>>>>>> In theory, and assuming that you aren't using the other timers,
> you
> >>>>>>>> could get 7 tones using timer B. I'd also go for the highest clock
> >>>>>>>> frequency possible, and in the ISR keep the code short and clean.
> >>>>>>>> for minimal jitter. Rather than absolute values your table could
> >>>>>>>> comprise differential values so that your calculation is simple
> DACx
> >>>>>>>> = DACx + sine(n).
> >>>>>>>>
> >>>>>>>> Hope this helps
> >>>>>>>>
> >>>>>>>> Al
> >>>>>>>>
> >>>>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
> >>>>>>>>> Hi all,
> >>>>>>>>> I am currently working on some code for an MSP430F2619. I am
> >>>>>>>>> using a 32-value sine lookup table, and pushing the sequential
> >>>>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
> >>>>>>>>> note frequency) controlled by TimerB. So far,this is working
> >>>>>>>>> well. I can produce any number of reasonable sounding pure
> >>>>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
> >>>>>>>>> and this is more than enough range for my needs, three full
> >>>>>>>>> octaves.
> >>>>>>>>>
> >>>>>>>>> However, this only plays one tone at a time. I have been wracking
> >>>>>>>>> my brains trying to figure out how to use this to generate a
> >>>>>>>>> "chord," more than one note played at the same time. I know that
> >>>>>>>>> musically this can be as simple as adding two sine waves
> together,
> >>>>>>>>> but since I don't have two simultaneously existing sine waves,
> just
> >>>>>>>>> one that I change the frequency of, I am at a loss.
> >>>>>>>>>
> >>>>>>>>> Does anyone have any suggestions on how to achieve this, or
> >>>>>>>>> references that they think might push me in the right direction?
> >>>>>>>>>
> >>>>>>>>> Thank you,
> >>>>>>>>> David
> >>>>>>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
Reply by old_cow_yellow April 28, 20122012-04-28
David,

Try something simple first. Use Just Scale and generate multiple frequencies with simple ratios.

(a) Find the smallest number that is divisible by all the frequencies.
(b) Use a sampling rate that is an integer multiple of that number.

For example, we can generate C3, E3 and G3 together.
In Just Scale, we have: C3 = 128Hz, E3 = 160Hz and G3 = 192Hz.
1920 / 128 = 15; 1920 / 160 = 12; and 1920 / 192 = 10.
We can use 3*1920 = 5760 samples/sec. (Or, instead of 3, some other integer.)
Now we can use tables of 3*15 = 45 entries for C3. And 3*12 = 36 entries for E3. And 3*10 = 30 entries for G3.

Be Just and Rational !

--OCY

--- In m..., "zylaxice" wrote:
>
> Hi all,
> I am currently working on some code for an MSP430F2619. I am using a 32-value sine lookup table, and pushing the sequential values out to the DAC12 via DMA, with the speed (and thus the note frequency) controlled by TimerB. So far,this is working well. I can produce any number of reasonable sounding pure tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5), and this is more than enough range for my needs, three full octaves.
>
> However, this only plays one tone at a time. I have been wracking my brains trying to figure out how to use this to generate a "chord," more than one note played at the same time. I know that musically this can be as simple as adding two sine waves together, but since I don't have two simultaneously existing sine waves, just one that I change the frequency of, I am at a loss.
>
> Does anyone have any suggestions on how to achieve this, or references that they think might push me in the right direction?
>
> Thank you,
> David
>

Reply by Onestone April 27, 20122012-04-27
So many ways to skin that cat!

Al

On 28/04/2012 12:20 AM, Robert wrote:
> How about you have a sine table, but instead of setting your interrupt time based on a single frequency divided by the # of samples, you instead pick a fixed interrupt time. For example, it seems your fastest interrupt rate currently would be at (1/987.7 Hz)/32 = 31.6 us. So use that as your interrupt time all the time.
>
> At each interrupt, you calculate for each sine wave where you'll be in that list of 32 samples, 0 - 31. If you're trying to create a sine wave at 400 Hz, your increment each interrupt would be (400 Hz/987.7 Hz). Calculate this using fixed-point #s, or course, such as 8p8. Since you have a limited number of tones, the increment can be precalculated for each one.
>
> Now, you when you get an interrupt, for each frequency, you add to a position value by the increment for each frequency and take the corresponding value from the sine wave table. Since you're in between two values, you'll probably want to extrapolate between the two values in the table. Do this for each frequency and add them together.
>
> Whether you can get this done in 31.6 us, I don't know, but it seems like a clean way of getting tones, and is scalable up until you run out of CPU cycles.
>
> --- In m..., Onestone wrote:
>> Hi Matthias, I still think you're misunderstanding. First of all two
>> tones would never require the same CCR, secondly chords don't contain
>> duplicates of the same note (at least in my experience), so 7 unique
>> tones can be played simultaneously with 7 CCr registers. And those tones
>> can vary in real time, ie register CCRB1 doesn't have to be C, at each
>> note, a fresh set of unique notes are available. My code sample
>> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
>> case. In the case of a 16MHz clock 7 tones would require 217 clock
>> cycles maximum to process in the isrs, plus whatever overhead is needed
>> in the foreground routine, so there would still be obvious limits to the
>> maximum access rate. However since the OP wants a range from 130.8Hz to
>> 987.7Hz a worst case event would mean an upper limit of 74 entries per
>> table. however there is nothign to stop the user from having tables of
>> different resolutions, or of varying the step size for different notes.
>> ie a 256 entry table played at a fixed rate to give 100Hz would give a
>> 200hz output if the step through the table was 2 instead of 1. this is,
>> of course, another way of getting a wide frequency range using a single
>> clock source. In this case longer tables sound better than short ones.
>> In the case of a single table with variable step sizes to create notes
>> of different frequencies it would be possible to use a single timer, and
>> simply add all the different values for each step interval in a single
>> ISR, however the range of frequencies is more limited. If I remember my
>> note frequencies there are a limited number of base frequencies, and
>> then the harmonics of these, which the above method results in, form the
>> remaining available notes, so a combination of methods could well work.
>>
>> Of course, having said all of this, if the OP only needs to play a few
>> different note combinations, or a few short tunes then, given the huge
>> amount of available memory why note simply pre-calculate them and store
>> them in flash?
>>
>> Al
>> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
>>> Onestone:
>>>
>>>> Hi Matthias. The idea is to use a single table, but probably a higher
>>>> resolution table than 32 entries, and to still use the basic concept of
>>>> timed access to generate different notes. It would be virtually
>>>> impossible, I believe, to do this with a single timer, and limited
>>>> jitter, how would you work out the next time interval for, say a 4 note
>>>> chord? where the frequencies are not some convenient binary multiple?
>>> Hi Al,
>>>
>>> It seems I understand your algorithm quite different then you. Each note
>>> use it's own counter (e.g. the 7 CCR registers) for the sample clock.
>>>
>>>> Then, where one note is a much higher frequency than another you have
>>>> multiple instances of the higher note per instance of the lower note, so
>>>> tracking order of tones with a single timer becomes cpu intensive.
>>> That is true. You need to prepare the settings for the next tone in the
>>> mainloop (CCR and position in the lookup table). One idea is a sorted table
>>> in RAM, sorted by next CCR. A special case has to be handled if 2 (or more)
>>> tones requires the same CCR. Even with your method the jitter is higher in
>>> case 2 (or more) CCR-interrupts need to get served at the same CCR-value.
>>> However my method is only suitable for very low frequencies.
>>>
>>> M.
>>>
>>>> Certainly it would be far easier to use a single timer per tone. Also
>>>> you'd need to take scaling into account. By using a timer per note you
>>>> reduce the calculations (using a differential sine table) to DACOUT >>>> DACOUT + TABLE(Nx) where N is the table entry, x is the tone, and TABLE
>>>> is a table of signed differential sine values. The simplest form of this
>>>> would use 1 register per note, so N1 =R4, N2 = R5 etc. Then the ISR
>>>> becomes simply:-
>>>>
>>>> TB1_ISR:
>>>> ADD&DACOUT,TABLE(R4)
>>>> ADD&N1INTERVAL,&CCRB1
>>>> BIC #CCIFG,&CCTLB1
>>>> INCD R4
>>>> ;ENTRIES ARE WORDS
>>>> AND #0X00FE,R4 ;ASSUMES
>>>> 256 ENTRY TABLE
>>>> RETI
>>>>
>>>> To overcome scaling issues and the need for a little maths you could
>>>> easily have tables for single tones, 2 note chords, up to 7 note chords
>>>>
>>>> Cheers
>>>>
>>>> Al
>>>>
>>>> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
>>>>> Onestone,
>>>>> your code is quite good (after some thinking I am now sure that it is
>>>>> working:-). One improvement: should be possible to do it with just one
>>>>> CCR- channel.
>>>>>
>>>>> M.
>>>>>
>>>>> Onestone:
>>>>>
>>>>>> being a simple kind of guy I think my method is just too easy! 8-)
>>>>>>
>>>>>> Al
>>>>>>
>>>>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
>>>>>>> In case you are comfortable with 2 mixed sine waves just use both
>>>>>>> DAC's, feed them independly and add them analog at the output pin
>>>>>>> with 2 resistors.
>>>>>>>
>>>>>>> Another way: create a lookup table for your "chords".
>>>>>>> In your current code you always use 32 steps for each sine wave - for
>>>>>>> one wave a step is e.g. 300us for the 2nd wave it is 310us. To mix
>>>>>>> them digitally you need finer steps.
>>>>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine waves
>>>>>>> into that RAM-table according to the frequencies you want. Feed this
>>>>>>> RAM-table with the fastest clock (987Hz is about 1ms) to the DAC. For
>>>>>>> example in a 256 table the 987Hz wave fits 7.55 times, the 130Hz
>>>>>>> waves only 1 time. For the 130Hz tone you have to calculate 256
>>>>>>> values from you 32 values of the lookup table. This is called
>>>>>>> upsampling. You can use linear interpolation (lines) to calculate the
>>>>>>> values between the 32 lookup values from your Flash table (or drop
>>>>>>> the lookup table and use sin() from the C compiler, no idea how fast
>>>>>>> this is). The big deal here is, that in most cases the end of the RAM
>>>>>>> table does not fit to the begin of the RAM table, the waves are not
>>>>>>> connected smoothly together. You have to calculate a new RAM table
>>>>>>> once the first one has been sent, so that the waves are smoothly
>>>>>>> connected. Use 2 RAM tables, one for output (DMA), one for
>>>>>>> precalculation (in the main loop).
>>>>>>>
>>>>>>> You can do the interpolation on the fly in the CCR-Interrupt routine,
>>>>>>> no extra RAM table, no DMA needed (however, the sound will not be
>>>>>>> clear because of the jitter of the interrupt response time).
>>>>>>>
>>>>>>> M.
>>>>>>>
>>>>>>> Onestone:
>>>>>>>
>>>>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd use
>>>>>>>> 1 timer per tone, and track the last value for each tone. Then on
>>>>>>>> timer interrupt:-
>>>>>>>>
>>>>>>>> DACx = DACx - oldsinevalue + newsinevalue.
>>>>>>>>
>>>>>>>> Effectively remove the old value for the tone from the DAC and add
>>>>>>>> the new one at a variabe time interval. Also, given something with
>>>>>>>> as much memory as the 2619 i'd not limit myself to a 32 entry table.
>>>>>>>> In theory, and assuming that you aren't using the other timers, you
>>>>>>>> could get 7 tones using timer B. I'd also go for the highest clock
>>>>>>>> frequency possible, and in the ISR keep the code short and clean.
>>>>>>>> for minimal jitter. Rather than absolute values your table could
>>>>>>>> comprise differential values so that your calculation is simple DACx
>>>>>>>> = DACx + sine(n).
>>>>>>>>
>>>>>>>> Hope this helps
>>>>>>>>
>>>>>>>> Al
>>>>>>>>
>>>>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
>>>>>>>>> Hi all,
>>>>>>>>> I am currently working on some code for an MSP430F2619. I am
>>>>>>>>> using a 32-value sine lookup table, and pushing the sequential
>>>>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
>>>>>>>>> note frequency) controlled by TimerB. So far,this is working
>>>>>>>>> well. I can produce any number of reasonable sounding pure
>>>>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
>>>>>>>>> and this is more than enough range for my needs, three full
>>>>>>>>> octaves.
>>>>>>>>>
>>>>>>>>> However, this only plays one tone at a time. I have been wracking
>>>>>>>>> my brains trying to figure out how to use this to generate a
>>>>>>>>> "chord," more than one note played at the same time. I know that
>>>>>>>>> musically this can be as simple as adding two sine waves together,
>>>>>>>>> but since I don't have two simultaneously existing sine waves, just
>>>>>>>>> one that I change the frequency of, I am at a loss.
>>>>>>>>>
>>>>>>>>> Does anyone have any suggestions on how to achieve this, or
>>>>>>>>> references that they think might push me in the right direction?
>>>>>>>>>
>>>>>>>>> Thank you,
>>>>>>>>> David
>>>>>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
Reply by Robert April 27, 20122012-04-27
How about you have a sine table, but instead of setting your interrupt time based on a single frequency divided by the # of samples, you instead pick a fixed interrupt time. For example, it seems your fastest interrupt rate currently would be at (1/987.7 Hz)/32 = 31.6 us. So use that as your interrupt time all the time.

At each interrupt, you calculate for each sine wave where you'll be in that list of 32 samples, 0 - 31. If you're trying to create a sine wave at 400 Hz, your increment each interrupt would be (400 Hz/987.7 Hz). Calculate this using fixed-point #s, or course, such as 8p8. Since you have a limited number of tones, the increment can be precalculated for each one.

Now, you when you get an interrupt, for each frequency, you add to a position value by the increment for each frequency and take the corresponding value from the sine wave table. Since you're in between two values, you'll probably want to extrapolate between the two values in the table. Do this for each frequency and add them together.

Whether you can get this done in 31.6 us, I don't know, but it seems like a clean way of getting tones, and is scalable up until you run out of CPU cycles.

--- In m..., Onestone wrote:
>
> Hi Matthias, I still think you're misunderstanding. First of all two
> tones would never require the same CCR, secondly chords don't contain
> duplicates of the same note (at least in my experience), so 7 unique
> tones can be played simultaneously with 7 CCr registers. And those tones
> can vary in real time, ie register CCRB1 doesn't have to be C, at each
> note, a fresh set of unique notes are available. My code sample
> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
> case. In the case of a 16MHz clock 7 tones would require 217 clock
> cycles maximum to process in the isrs, plus whatever overhead is needed
> in the foreground routine, so there would still be obvious limits to the
> maximum access rate. However since the OP wants a range from 130.8Hz to
> 987.7Hz a worst case event would mean an upper limit of 74 entries per
> table. however there is nothign to stop the user from having tables of
> different resolutions, or of varying the step size for different notes.
> ie a 256 entry table played at a fixed rate to give 100Hz would give a
> 200hz output if the step through the table was 2 instead of 1. this is,
> of course, another way of getting a wide frequency range using a single
> clock source. In this case longer tables sound better than short ones.
> In the case of a single table with variable step sizes to create notes
> of different frequencies it would be possible to use a single timer, and
> simply add all the different values for each step interval in a single
> ISR, however the range of frequencies is more limited. If I remember my
> note frequencies there are a limited number of base frequencies, and
> then the harmonics of these, which the above method results in, form the
> remaining available notes, so a combination of methods could well work.
>
> Of course, having said all of this, if the OP only needs to play a few
> different note combinations, or a few short tunes then, given the huge
> amount of available memory why note simply pre-calculate them and store
> them in flash?
>
> Al
> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
> > Onestone:
> >
> >> Hi Matthias. The idea is to use a single table, but probably a higher
> >> resolution table than 32 entries, and to still use the basic concept of
> >> timed access to generate different notes. It would be virtually
> >> impossible, I believe, to do this with a single timer, and limited
> >> jitter, how would you work out the next time interval for, say a 4 note
> >> chord? where the frequencies are not some convenient binary multiple?
> > Hi Al,
> >
> > It seems I understand your algorithm quite different then you. Each note
> > use it's own counter (e.g. the 7 CCR registers) for the sample clock.
> >
> >> Then, where one note is a much higher frequency than another you have
> >> multiple instances of the higher note per instance of the lower note, so
> >> tracking order of tones with a single timer becomes cpu intensive.
> > That is true. You need to prepare the settings for the next tone in the
> > mainloop (CCR and position in the lookup table). One idea is a sorted table
> > in RAM, sorted by next CCR. A special case has to be handled if 2 (or more)
> > tones requires the same CCR. Even with your method the jitter is higher in
> > case 2 (or more) CCR-interrupts need to get served at the same CCR-value.
> > However my method is only suitable for very low frequencies.
> >
> > M.
> >
> >> Certainly it would be far easier to use a single timer per tone. Also
> >> you'd need to take scaling into account. By using a timer per note you
> >> reduce the calculations (using a differential sine table) to DACOUT > >> DACOUT + TABLE(Nx) where N is the table entry, x is the tone, and TABLE
> >> is a table of signed differential sine values. The simplest form of this
> >> would use 1 register per note, so N1 =R4, N2 = R5 etc. Then the ISR
> >> becomes simply:-
> >>
> >> TB1_ISR:
> >> ADD&DACOUT,TABLE(R4)
> >> ADD&N1INTERVAL,&CCRB1
> >> BIC #CCIFG,&CCTLB1
> >> INCD R4
> >> ;ENTRIES ARE WORDS
> >> AND #0X00FE,R4 ;ASSUMES
> >> 256 ENTRY TABLE
> >> RETI
> >>
> >> To overcome scaling issues and the need for a little maths you could
> >> easily have tables for single tones, 2 note chords, up to 7 note chords
> >>
> >> Cheers
> >>
> >> Al
> >>
> >> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
> >>> Onestone,
> >>> your code is quite good (after some thinking I am now sure that it is
> >>> working:-). One improvement: should be possible to do it with just one
> >>> CCR- channel.
> >>>
> >>> M.
> >>>
> >>> Onestone:
> >>>
> >>>> being a simple kind of guy I think my method is just too easy! 8-)
> >>>>
> >>>> Al
> >>>>
> >>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
> >>>>> In case you are comfortable with 2 mixed sine waves just use both
> >>>>> DAC's, feed them independly and add them analog at the output pin
> >>>>> with 2 resistors.
> >>>>>
> >>>>> Another way: create a lookup table for your "chords".
> >>>>> In your current code you always use 32 steps for each sine wave - for
> >>>>> one wave a step is e.g. 300us for the 2nd wave it is 310us. To mix
> >>>>> them digitally you need finer steps.
> >>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine waves
> >>>>> into that RAM-table according to the frequencies you want. Feed this
> >>>>> RAM-table with the fastest clock (987Hz is about 1ms) to the DAC. For
> >>>>> example in a 256 table the 987Hz wave fits 7.55 times, the 130Hz
> >>>>> waves only 1 time. For the 130Hz tone you have to calculate 256
> >>>>> values from you 32 values of the lookup table. This is called
> >>>>> upsampling. You can use linear interpolation (lines) to calculate the
> >>>>> values between the 32 lookup values from your Flash table (or drop
> >>>>> the lookup table and use sin() from the C compiler, no idea how fast
> >>>>> this is). The big deal here is, that in most cases the end of the RAM
> >>>>> table does not fit to the begin of the RAM table, the waves are not
> >>>>> connected smoothly together. You have to calculate a new RAM table
> >>>>> once the first one has been sent, so that the waves are smoothly
> >>>>> connected. Use 2 RAM tables, one for output (DMA), one for
> >>>>> precalculation (in the main loop).
> >>>>>
> >>>>> You can do the interpolation on the fly in the CCR-Interrupt routine,
> >>>>> no extra RAM table, no DMA needed (however, the sound will not be
> >>>>> clear because of the jitter of the interrupt response time).
> >>>>>
> >>>>> M.
> >>>>>
> >>>>> Onestone:
> >>>>>
> >>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd use
> >>>>>> 1 timer per tone, and track the last value for each tone. Then on
> >>>>>> timer interrupt:-
> >>>>>>
> >>>>>> DACx = DACx - oldsinevalue + newsinevalue.
> >>>>>>
> >>>>>> Effectively remove the old value for the tone from the DAC and add
> >>>>>> the new one at a variabe time interval. Also, given something with
> >>>>>> as much memory as the 2619 i'd not limit myself to a 32 entry table.
> >>>>>> In theory, and assuming that you aren't using the other timers, you
> >>>>>> could get 7 tones using timer B. I'd also go for the highest clock
> >>>>>> frequency possible, and in the ISR keep the code short and clean.
> >>>>>> for minimal jitter. Rather than absolute values your table could
> >>>>>> comprise differential values so that your calculation is simple DACx
> >>>>>> = DACx + sine(n).
> >>>>>>
> >>>>>> Hope this helps
> >>>>>>
> >>>>>> Al
> >>>>>>
> >>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
> >>>>>>> Hi all,
> >>>>>>> I am currently working on some code for an MSP430F2619. I am
> >>>>>>> using a 32-value sine lookup table, and pushing the sequential
> >>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
> >>>>>>> note frequency) controlled by TimerB. So far,this is working
> >>>>>>> well. I can produce any number of reasonable sounding pure
> >>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
> >>>>>>> and this is more than enough range for my needs, three full
> >>>>>>> octaves.
> >>>>>>>
> >>>>>>> However, this only plays one tone at a time. I have been wracking
> >>>>>>> my brains trying to figure out how to use this to generate a
> >>>>>>> "chord," more than one note played at the same time. I know that
> >>>>>>> musically this can be as simple as adding two sine waves together,
> >>>>>>> but since I don't have two simultaneously existing sine waves, just
> >>>>>>> one that I change the frequency of, I am at a loss.
> >>>>>>>
> >>>>>>> Does anyone have any suggestions on how to achieve this, or
> >>>>>>> references that they think might push me in the right direction?
> >>>>>>>
> >>>>>>> Thank you,
> >>>>>>> David
> >>>>>>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
Reply by Dana Myers April 27, 20122012-04-27
To get finer frequency granularity with an NCO, you use more bits in the
phase accumulator; let's say 32-bits. Then you use the highest-order
bits of the accumulator as the cosine-table lookup value. This sets the
basic frequency granule as one "cycle" through the full phase accumulator.
If the clock rate - the sample rate - is 10KHz, one cycle will be
10KHz/2^32,
or 2.3283 microHertz, which means you can synthesize any audio frequency
better than your oscillator tolerance. I certainly generated DTMF to
better than
telco-standards this way 25 years ago.

You can scale this down to fit better; for example using a 256-entry
cosine table and a 24-bit accumulator clocked at 10KHz, you'd have a
frequency step of .59605 milliHz and the lookup would be:

outputsample = cosine_table[(phase_accum >> 16) & 0xff];
phase_accum += frequency_increment.

which probably compiles to something that avoids shifting.

But, hey, it's not my project :-)

Cheers -
Dana K6JQ

On Thu, Apr 26, 2012 at 11:46 PM, Matthias Weingart
wrote:

> **
> Dana,
>
> in case I understand Al's comment right :-) - he is doing it in a
> different
> way. The same lockup table is sent to the DAC with different sample rates.
> No value from the table is skipped, they are sent to the DAC with
> different
> speeds. e.g. for the first tone every 200 timer clocks, for the 2nd tone
> with every 201 timer clocks...
>
> M.
>
> Dana Myers :
> > More detail on DDS - you create a single sine-wave table (it's actually
> > a cosine)
> > and 'step' through it based on a constant sample rate. The frequency is
> > determined by the size of the step.
> >
> > For example, let's just assume we have a 1024-word table:
> >
> > int costab[1024] = { ... }; // initialize with pre-calculated single
> > wave of
> > // cos() * 32767 (-32767 .. 32767)
> >
> > If you use a sample rate of 10240 samples/sec, an increment of
> > 1 will produce a 10Hz sine wave, an increment of 10 will produce 100Hz,
> > etc.
> >
> > You maintain a "phase accumulator" for each desired output frequency.
> > The output is then a stream of samples at whatever precision your
> > cosine table is.
> >
> > You can use a large phase accumulator to provide better/finer
> > frequency granularity and intermediate bits of the accumulator
> > to effectively implement fractional increments between frequencies.
> >
> > You only need one periodic interrupt to drive the output ISR,
> >
> > Cheers,
> > Dana K6JQ
> >
> > On Thu, Apr 26, 2012 at 6:53 AM, Onestone
> > wrote:
> >
> >> **
>
> >>
> >>
> >> Hi Matthias, I still think you're misunderstanding. First of all two
> >> tones would never require the same CCR, secondly chords don't contain
> >> duplicates of the same note (at least in my experience), so 7 unique
> >> tones can be played simultaneously with 7 CCr registers. And those
> >> tones can vary in real time, ie register CCRB1 doesn't have to be C, at
> >> each note, a fresh set of unique notes are available. My code sample
> >> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
> >> case. In the case of a 16MHz clock 7 tones would require 217 clock
> >> cycles maximum to process in the isrs, plus whatever overhead is needed
> >> in the foreground routine, so there would still be obvious limits to
> >> the maximum access rate. However since the OP wants a range from
> >> 130.8Hz to 987.7Hz a worst case event would mean an upper limit of 74
> >> entries per table. however there is nothign to stop the user from
> >> having tables of different resolutions, or of varying the step size for
> >> different notes. ie a 256 entry table played at a fixed rate to give
> >> 100Hz would give a 200hz output if the step through the table was 2
> >> instead of 1. this is, of course, another way of getting a wide
> >> frequency range using a single clock source. In this case longer tables
> >> sound better than short ones. In the case of a single table with
> >> variable step sizes to create notes of different frequencies it would
> >> be possible to use a single timer, and simply add all the different
> >> values for each step interval in a single ISR, however the range of
> >> frequencies is more limited. If I remember my note frequencies there
> >> are a limited number of base frequencies, and then the harmonics of
> >> these, which the above method results in, form the remaining available
> >> notes, so a combination of methods could well work.
> >>
> >> Of course, having said all of this, if the OP only needs to play a few
> >> different note combinations, or a few short tunes then, given the huge
> >> amount of available memory why note simply pre-calculate them and store
> >> them in flash?
> >>
> >> Al
> >>
> >>
> >> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
> >> > Onestone:
> >> >
> >> >> Hi Matthias. The idea is to use a single table, but probably a
> >> >> higher resolution table than 32 entries, and to still use the basic
> >> >> concept of timed access to generate different notes. It would be
> >> >> virtually impossible, I believe, to do this with a single timer, and
> >> >> limited jitter, how would you work out the next time interval for,
> >> >> say a 4 note chord? where the frequencies are not some convenient
> >> >> binary multiple?
> >> > Hi Al,
> >> >
> >> > It seems I understand your algorithm quite different then you. Each
> >> > note use it's own counter (e.g. the 7 CCR registers) for the sample
> >> > clock.
> >> >
> >> >> Then, where one note is a much higher frequency than another you
> >> >> have multiple instances of the higher note per instance of the lower
> >> >> note, so tracking order of tones with a single timer becomes cpu
> >> >> intensive.
> >> > That is true. You need to prepare the settings for the next tone in
> >> > the mainloop (CCR and position in the lookup table). One idea is a
> >> > sorted
> >> table
> >> > in RAM, sorted by next CCR. A special case has to be handled if 2 (or
> >> more)
> >> > tones requires the same CCR. Even with your method the jitter is
> >> > higher
> >> in
> >> > case 2 (or more) CCR-interrupts need to get served at the same
> >> > CCR-value. However my method is only suitable for very low
> >> > frequencies.
> >> >
> >> > M.
> >> >
> >> >> Certainly it would be far easier to use a single timer per tone.
> >> >> Also you'd need to take scaling into account. By using a timer per
> >> >> note you reduce the calculations (using a differential sine table)
> >> >> to DACOUT = DACOUT + TABLE(Nx) where N is the table entry, x is the
> >> >> tone, and TABLE is a table of signed differential sine values. The
> >> >> simplest form of this would use 1 register per note, so N1 =R4, N2 > >> >> R5 etc. Then the ISR becomes simply:-
> >> >>
> >> >> TB1_ISR:
> >> >> ADD&DACOUT,TABLE(R4)
> >> >> ADD&N1INTERVAL,&CCRB1
> >> >> BIC #CCIFG,&CCTLB1
> >> >> INCD R4
> >> >> ;ENTRIES ARE WORDS
> >> >> AND #0X00FE,R4 ;ASSUMES
> >> >> 256 ENTRY TABLE
> >> >> RETI
> >> >>
> >> >> To overcome scaling issues and the need for a little maths you could
> >> >> easily have tables for single tones, 2 note chords, up to 7 note
> >> >> chords
> >> >>
> >> >> Cheers
> >> >>
> >> >> Al
> >> >>
> >> >> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
> >> >>> Onestone,
> >> >>> your code is quite good (after some thinking I am now sure that it
> >> >>> is working:-). One improvement: should be possible to do it with
> >> >>> just one CCR- channel.
> >> >>>
> >> >>> M.
> >> >>>
> >> >>> Onestone:
> >> >>>
> >> >>>> being a simple kind of guy I think my method is just too easy! 8-)
> >> >>>>
> >> >>>> Al
> >> >>>>
> >> >>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
> >> >>>>> In case you are comfortable with 2 mixed sine waves just use both
> >> >>>>> DAC's, feed them independly and add them analog at the output pin
> >> >>>>> with 2 resistors.
> >> >>>>>
> >> >>>>> Another way: create a lookup table for your "chords".
> >> >>>>> In your current code you always use 32 steps for each sine wave -
> >> >>>>> for one wave a step is e.g. 300us for the 2nd wave it is 310us.
> >> >>>>> To mix them digitally you need finer steps.
> >> >>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine
> >> >>>>> waves into that RAM-table according to the frequencies you want.
> >> >>>>> Feed this RAM-table with the fastest clock (987Hz is about 1ms)
> >> >>>>> to the DAC. For example in a 256 table the 987Hz wave fits 7.55
> >> >>>>> times, the 130Hz waves only 1 time. For the 130Hz tone you have
> >> >>>>> to calculate 256 values from you 32 values of the lookup table.
> >> >>>>> This is called upsampling. You can use linear interpolation
> >> >>>>> (lines) to calculate the values between the 32 lookup values from
> >> >>>>> your Flash table (or drop the lookup table and use sin() from the
> >> >>>>> C compiler, no idea how fast this is). The big deal here is, that
> >> >>>>> in most cases the end of the RAM table does not fit to the begin
> >> >>>>> of the RAM table, the waves are not connected smoothly together.
> >> >>>>> You have to calculate a new RAM table once the first one has been
> >> >>>>> sent, so that the waves are smoothly connected. Use 2 RAM tables,
> >> >>>>> one for output (DMA), one for precalculation (in the main loop).
> >> >>>>>
> >> >>>>> You can do the interpolation on the fly in the CCR-Interrupt
> >> >>>>> routine, no extra RAM table, no DMA needed (however, the sound
> >> >>>>> will not be clear because of the jitter of the interrupt response
> >> >>>>> time).
> >> >>>>>
> >> >>>>> M.
> >> >>>>>
> >> >>>>> Onestone:
> >> >>>>>
> >> >>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd
> >> >>>>>> use 1 timer per tone, and track the last value for each tone.
> >> >>>>>> Then on timer interrupt:-
> >> >>>>>>
> >> >>>>>> DACx = DACx - oldsinevalue + newsinevalue.
> >> >>>>>>
> >> >>>>>> Effectively remove the old value for the tone from the DAC and
> >> >>>>>> add the new one at a variabe time interval. Also, given
> >> >>>>>> something with as much memory as the 2619 i'd not limit myself
> >> >>>>>> to a 32 entry table. In theory, and assuming that you aren't
> >> >>>>>> using the other timers, you could get 7 tones using timer B. I'd
> >> >>>>>> also go for the highest clock frequency possible, and in the ISR
> >> >>>>>> keep the code short and clean. for minimal jitter. Rather than
> >> >>>>>> absolute values your table could comprise differential values so
> >> >>>>>> that your calculation is simple DACx = DACx + sine(n).
> >> >>>>>>
> >> >>>>>> Hope this helps
> >> >>>>>>
> >> >>>>>> Al
> >> >>>>>>
> >> >>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
> >> >>>>>>> Hi all,
> >> >>>>>>> I am currently working on some code for an MSP430F2619. I am
> >> >>>>>>> using a 32-value sine lookup table, and pushing the sequential
> >> >>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
> >> >>>>>>> note frequency) controlled by TimerB. So far,this is working
> >> >>>>>>> well. I can produce any number of reasonable sounding pure
> >> >>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
> >> >>>>>>> and this is more than enough range for my needs, three full
> >> >>>>>>> octaves.
> >> >>>>>>>
> >> >>>>>>> However, this only plays one tone at a time. I have been
> >> >>>>>>> wracking my brains trying to figure out how to use this to
> >> >>>>>>> generate a "chord," more than one note played at the same time.
> >> >>>>>>> I know that musically this can be as simple as adding two sine
> >> >>>>>>> waves together, but since I don't have two simultaneously
> >> >>>>>>> existing sine waves, just one that I change the frequency of, I
> >> >>>>>>> am at a loss.
> >> >>>>>>>
> >> >>>>>>> Does anyone have any suggestions on how to achieve this, or
> >> >>>>>>> references that they think might push me in the right
> >> >>>>>>> direction?
> >> >>>>>>>
> >> >>>>>>> Thank you,
> >> >>>>>>> David
> >> >>>>>>>
> >> >>>
>


Reply by Onestone April 27, 20122012-04-27
That's correct. With a high speed clock it offers better granularity
than integer stepping through the table. It is still DDS, although it's
something I've been doing for at least 30 years, although I've never had
to generate chords before, and I've only recently heard it called DDS.
I'm sure somebody somewhere (probably some young sprog) sits and invents
all these TLA's just to confuse us old farts.

Al

On 27/04/2012 4:16 PM, Matthias Weingart wrote:
> Dana,
>
> in case I understand Al's comment right :-) - he is doing it in a different
> way. The same lockup table is sent to the DAC with different sample rates.
> No value from the table is skipped, they are sent to the DAC with different
> speeds. e.g. for the first tone every 200 timer clocks, for the 2nd tone
> with every 201 timer clocks...
>
> M.
>
> Dana Myers:
>
>> More detail on DDS - you create a single sine-wave table (it's actually
>> a cosine)
>> and 'step' through it based on a constant sample rate. The frequency is
>> determined by the size of the step.
>>
>> For example, let's just assume we have a 1024-word table:
>>
>> int costab[1024] = { ... }; // initialize with pre-calculated single
>> wave of
>> // cos() * 32767 (-32767 .. 32767)
>>
>> If you use a sample rate of 10240 samples/sec, an increment of
>> 1 will produce a 10Hz sine wave, an increment of 10 will produce 100Hz,
>> etc.
>>
>> You maintain a "phase accumulator" for each desired output frequency.
>> The output is then a stream of samples at whatever precision your
>> cosine table is.
>>
>> You can use a large phase accumulator to provide better/finer
>> frequency granularity and intermediate bits of the accumulator
>> to effectively implement fractional increments between frequencies.
>>
>> You only need one periodic interrupt to drive the output ISR,
>>
>> Cheers,
>> Dana K6JQ
>>
>> On Thu, Apr 26, 2012 at 6:53 AM, Onestone
>> wrote:
>>
>>> **
>>>
>>>
>>> Hi Matthias, I still think you're misunderstanding. First of all two
>>> tones would never require the same CCR, secondly chords don't contain
>>> duplicates of the same note (at least in my experience), so 7 unique
>>> tones can be played simultaneously with 7 CCr registers. And those
>>> tones can vary in real time, ie register CCRB1 doesn't have to be C, at
>>> each note, a fresh set of unique notes are available. My code sample
>>> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
>>> case. In the case of a 16MHz clock 7 tones would require 217 clock
>>> cycles maximum to process in the isrs, plus whatever overhead is needed
>>> in the foreground routine, so there would still be obvious limits to
>>> the maximum access rate. However since the OP wants a range from
>>> 130.8Hz to 987.7Hz a worst case event would mean an upper limit of 74
>>> entries per table. however there is nothign to stop the user from
>>> having tables of different resolutions, or of varying the step size for
>>> different notes. ie a 256 entry table played at a fixed rate to give
>>> 100Hz would give a 200hz output if the step through the table was 2
>>> instead of 1. this is, of course, another way of getting a wide
>>> frequency range using a single clock source. In this case longer tables
>>> sound better than short ones. In the case of a single table with
>>> variable step sizes to create notes of different frequencies it would
>>> be possible to use a single timer, and simply add all the different
>>> values for each step interval in a single ISR, however the range of
>>> frequencies is more limited. If I remember my note frequencies there
>>> are a limited number of base frequencies, and then the harmonics of
>>> these, which the above method results in, form the remaining available
>>> notes, so a combination of methods could well work.
>>>
>>> Of course, having said all of this, if the OP only needs to play a few
>>> different note combinations, or a few short tunes then, given the huge
>>> amount of available memory why note simply pre-calculate them and store
>>> them in flash?
>>>
>>> Al
>>>
>>>
>>> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
>>>> Onestone:
>>>>
>>>>> Hi Matthias. The idea is to use a single table, but probably a
>>>>> higher resolution table than 32 entries, and to still use the basic
>>>>> concept of timed access to generate different notes. It would be
>>>>> virtually impossible, I believe, to do this with a single timer, and
>>>>> limited jitter, how would you work out the next time interval for,
>>>>> say a 4 note chord? where the frequencies are not some convenient
>>>>> binary multiple?
>>>> Hi Al,
>>>>
>>>> It seems I understand your algorithm quite different then you. Each
>>>> note use it's own counter (e.g. the 7 CCR registers) for the sample
>>>> clock.
>>>>
>>>>> Then, where one note is a much higher frequency than another you
>>>>> have multiple instances of the higher note per instance of the lower
>>>>> note, so tracking order of tones with a single timer becomes cpu
>>>>> intensive.
>>>> That is true. You need to prepare the settings for the next tone in
>>>> the mainloop (CCR and position in the lookup table). One idea is a
>>>> sorted
>>> table
>>>> in RAM, sorted by next CCR. A special case has to be handled if 2 (or
>>> more)
>>>> tones requires the same CCR. Even with your method the jitter is
>>>> higher
>>> in
>>>> case 2 (or more) CCR-interrupts need to get served at the same
>>>> CCR-value. However my method is only suitable for very low
>>>> frequencies.
>>>>
>>>> M.
>>>>
>>>>> Certainly it would be far easier to use a single timer per tone.
>>>>> Also you'd need to take scaling into account. By using a timer per
>>>>> note you reduce the calculations (using a differential sine table)
>>>>> to DACOUT = DACOUT + TABLE(Nx) where N is the table entry, x is the
>>>>> tone, and TABLE is a table of signed differential sine values. The
>>>>> simplest form of this would use 1 register per note, so N1 =R4, N2 >>>>> R5 etc. Then the ISR becomes simply:-
>>>>>
>>>>> TB1_ISR:
>>>>> ADD&DACOUT,TABLE(R4)
>>>>> ADD&N1INTERVAL,&CCRB1
>>>>> BIC #CCIFG,&CCTLB1
>>>>> INCD R4
>>>>> ;ENTRIES ARE WORDS
>>>>> AND #0X00FE,R4 ;ASSUMES
>>>>> 256 ENTRY TABLE
>>>>> RETI
>>>>>
>>>>> To overcome scaling issues and the need for a little maths you could
>>>>> easily have tables for single tones, 2 note chords, up to 7 note
>>>>> chords
>>>>>
>>>>> Cheers
>>>>>
>>>>> Al
>>>>>
>>>>> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
>>>>>> Onestone,
>>>>>> your code is quite good (after some thinking I am now sure that it
>>>>>> is working:-). One improvement: should be possible to do it with
>>>>>> just one CCR- channel.
>>>>>>
>>>>>> M.
>>>>>>
>>>>>> Onestone:
>>>>>>
>>>>>>> being a simple kind of guy I think my method is just too easy! 8-)
>>>>>>>
>>>>>>> Al
>>>>>>>
>>>>>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
>>>>>>>> In case you are comfortable with 2 mixed sine waves just use both
>>>>>>>> DAC's, feed them independly and add them analog at the output pin
>>>>>>>> with 2 resistors.
>>>>>>>>
>>>>>>>> Another way: create a lookup table for your "chords".
>>>>>>>> In your current code you always use 32 steps for each sine wave -
>>>>>>>> for one wave a step is e.g. 300us for the 2nd wave it is 310us.
>>>>>>>> To mix them digitally you need finer steps.
>>>>>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine
>>>>>>>> waves into that RAM-table according to the frequencies you want.
>>>>>>>> Feed this RAM-table with the fastest clock (987Hz is about 1ms)
>>>>>>>> to the DAC. For example in a 256 table the 987Hz wave fits 7.55
>>>>>>>> times, the 130Hz waves only 1 time. For the 130Hz tone you have
>>>>>>>> to calculate 256 values from you 32 values of the lookup table.
>>>>>>>> This is called upsampling. You can use linear interpolation
>>>>>>>> (lines) to calculate the values between the 32 lookup values from
>>>>>>>> your Flash table (or drop the lookup table and use sin() from the
>>>>>>>> C compiler, no idea how fast this is). The big deal here is, that
>>>>>>>> in most cases the end of the RAM table does not fit to the begin
>>>>>>>> of the RAM table, the waves are not connected smoothly together.
>>>>>>>> You have to calculate a new RAM table once the first one has been
>>>>>>>> sent, so that the waves are smoothly connected. Use 2 RAM tables,
>>>>>>>> one for output (DMA), one for precalculation (in the main loop).
>>>>>>>>
>>>>>>>> You can do the interpolation on the fly in the CCR-Interrupt
>>>>>>>> routine, no extra RAM table, no DMA needed (however, the sound
>>>>>>>> will not be clear because of the jitter of the interrupt response
>>>>>>>> time).
>>>>>>>>
>>>>>>>> M.
>>>>>>>>
>>>>>>>> Onestone:
>>>>>>>>
>>>>>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd
>>>>>>>>> use 1 timer per tone, and track the last value for each tone.
>>>>>>>>> Then on timer interrupt:-
>>>>>>>>>
>>>>>>>>> DACx = DACx - oldsinevalue + newsinevalue.
>>>>>>>>>
>>>>>>>>> Effectively remove the old value for the tone from the DAC and
>>>>>>>>> add the new one at a variabe time interval. Also, given
>>>>>>>>> something with as much memory as the 2619 i'd not limit myself
>>>>>>>>> to a 32 entry table. In theory, and assuming that you aren't
>>>>>>>>> using the other timers, you could get 7 tones using timer B. I'd
>>>>>>>>> also go for the highest clock frequency possible, and in the ISR
>>>>>>>>> keep the code short and clean. for minimal jitter. Rather than
>>>>>>>>> absolute values your table could comprise differential values so
>>>>>>>>> that your calculation is simple DACx = DACx + sine(n).
>>>>>>>>>
>>>>>>>>> Hope this helps
>>>>>>>>>
>>>>>>>>> Al
>>>>>>>>>
>>>>>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
>>>>>>>>>> Hi all,
>>>>>>>>>> I am currently working on some code for an MSP430F2619. I am
>>>>>>>>>> using a 32-value sine lookup table, and pushing the sequential
>>>>>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
>>>>>>>>>> note frequency) controlled by TimerB. So far,this is working
>>>>>>>>>> well. I can produce any number of reasonable sounding pure
>>>>>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
>>>>>>>>>> and this is more than enough range for my needs, three full
>>>>>>>>>> octaves.
>>>>>>>>>>
>>>>>>>>>> However, this only plays one tone at a time. I have been
>>>>>>>>>> wracking my brains trying to figure out how to use this to
>>>>>>>>>> generate a "chord," more than one note played at the same time.
>>>>>>>>>> I know that musically this can be as simple as adding two sine
>>>>>>>>>> waves together, but since I don't have two simultaneously
>>>>>>>>>> existing sine waves, just one that I change the frequency of, I
>>>>>>>>>> am at a loss.
>>>>>>>>>>
>>>>>>>>>> Does anyone have any suggestions on how to achieve this, or
>>>>>>>>>> references that they think might push me in the right
>>>>>>>>>> direction?
>>>>>>>>>>
>>>>>>>>>> Thank you,
>>>>>>>>>> David
>>>>>>>>>>
>
Reply by Matthias Weingart April 27, 20122012-04-27
Dana,

in case I understand Al's comment right :-) - he is doing it in a different
way. The same lockup table is sent to the DAC with different sample rates.
No value from the table is skipped, they are sent to the DAC with different
speeds. e.g. for the first tone every 200 timer clocks, for the 2nd tone
with every 201 timer clocks...

M.

Dana Myers :

> More detail on DDS - you create a single sine-wave table (it's actually
> a cosine)
> and 'step' through it based on a constant sample rate. The frequency is
> determined by the size of the step.
>
> For example, let's just assume we have a 1024-word table:
>
> int costab[1024] = { ... }; // initialize with pre-calculated single
> wave of
> // cos() * 32767 (-32767 .. 32767)
>
> If you use a sample rate of 10240 samples/sec, an increment of
> 1 will produce a 10Hz sine wave, an increment of 10 will produce 100Hz,
> etc.
>
> You maintain a "phase accumulator" for each desired output frequency.
> The output is then a stream of samples at whatever precision your
> cosine table is.
>
> You can use a large phase accumulator to provide better/finer
> frequency granularity and intermediate bits of the accumulator
> to effectively implement fractional increments between frequencies.
>
> You only need one periodic interrupt to drive the output ISR,
>
> Cheers,
> Dana K6JQ
>
> On Thu, Apr 26, 2012 at 6:53 AM, Onestone
> wrote:
>
>> **
>> Hi Matthias, I still think you're misunderstanding. First of all two
>> tones would never require the same CCR, secondly chords don't contain
>> duplicates of the same note (at least in my experience), so 7 unique
>> tones can be played simultaneously with 7 CCr registers. And those
>> tones can vary in real time, ie register CCRB1 doesn't have to be C, at
>> each note, a fresh set of unique notes are available. My code sample
>> executes in 25 cycles plus interrupt latency of 1-6 cycles, so 31 worst
>> case. In the case of a 16MHz clock 7 tones would require 217 clock
>> cycles maximum to process in the isrs, plus whatever overhead is needed
>> in the foreground routine, so there would still be obvious limits to
>> the maximum access rate. However since the OP wants a range from
>> 130.8Hz to 987.7Hz a worst case event would mean an upper limit of 74
>> entries per table. however there is nothign to stop the user from
>> having tables of different resolutions, or of varying the step size for
>> different notes. ie a 256 entry table played at a fixed rate to give
>> 100Hz would give a 200hz output if the step through the table was 2
>> instead of 1. this is, of course, another way of getting a wide
>> frequency range using a single clock source. In this case longer tables
>> sound better than short ones. In the case of a single table with
>> variable step sizes to create notes of different frequencies it would
>> be possible to use a single timer, and simply add all the different
>> values for each step interval in a single ISR, however the range of
>> frequencies is more limited. If I remember my note frequencies there
>> are a limited number of base frequencies, and then the harmonics of
>> these, which the above method results in, form the remaining available
>> notes, so a combination of methods could well work.
>>
>> Of course, having said all of this, if the OP only needs to play a few
>> different note combinations, or a few short tunes then, given the huge
>> amount of available memory why note simply pre-calculate them and store
>> them in flash?
>>
>> Al
>> On 26/04/2012 6:32 PM, Matthias Weingart wrote:
>> > Onestone:
>> >
>> >> Hi Matthias. The idea is to use a single table, but probably a
>> >> higher resolution table than 32 entries, and to still use the basic
>> >> concept of timed access to generate different notes. It would be
>> >> virtually impossible, I believe, to do this with a single timer, and
>> >> limited jitter, how would you work out the next time interval for,
>> >> say a 4 note chord? where the frequencies are not some convenient
>> >> binary multiple?
>> > Hi Al,
>> >
>> > It seems I understand your algorithm quite different then you. Each
>> > note use it's own counter (e.g. the 7 CCR registers) for the sample
>> > clock.
>> >
>> >> Then, where one note is a much higher frequency than another you
>> >> have multiple instances of the higher note per instance of the lower
>> >> note, so tracking order of tones with a single timer becomes cpu
>> >> intensive.
>> > That is true. You need to prepare the settings for the next tone in
>> > the mainloop (CCR and position in the lookup table). One idea is a
>> > sorted
>> table
>> > in RAM, sorted by next CCR. A special case has to be handled if 2 (or
>> more)
>> > tones requires the same CCR. Even with your method the jitter is
>> > higher
>> in
>> > case 2 (or more) CCR-interrupts need to get served at the same
>> > CCR-value. However my method is only suitable for very low
>> > frequencies.
>> >
>> > M.
>> >
>> >> Certainly it would be far easier to use a single timer per tone.
>> >> Also you'd need to take scaling into account. By using a timer per
>> >> note you reduce the calculations (using a differential sine table)
>> >> to DACOUT = DACOUT + TABLE(Nx) where N is the table entry, x is the
>> >> tone, and TABLE is a table of signed differential sine values. The
>> >> simplest form of this would use 1 register per note, so N1 =R4, N2 >> >> R5 etc. Then the ISR becomes simply:-
>> >>
>> >> TB1_ISR:
>> >> ADD&DACOUT,TABLE(R4)
>> >> ADD&N1INTERVAL,&CCRB1
>> >> BIC #CCIFG,&CCTLB1
>> >> INCD R4
>> >> ;ENTRIES ARE WORDS
>> >> AND #0X00FE,R4 ;ASSUMES
>> >> 256 ENTRY TABLE
>> >> RETI
>> >>
>> >> To overcome scaling issues and the need for a little maths you could
>> >> easily have tables for single tones, 2 note chords, up to 7 note
>> >> chords
>> >>
>> >> Cheers
>> >>
>> >> Al
>> >>
>> >> On 26/04/2012 4:14 PM, Matthias Weingart wrote:
>> >>> Onestone,
>> >>> your code is quite good (after some thinking I am now sure that it
>> >>> is working:-). One improvement: should be possible to do it with
>> >>> just one CCR- channel.
>> >>>
>> >>> M.
>> >>>
>> >>> Onestone:
>> >>>
>> >>>> being a simple kind of guy I think my method is just too easy! 8-)
>> >>>>
>> >>>> Al
>> >>>>
>> >>>> On 25/04/2012 6:11 PM, Matthias Weingart wrote:
>> >>>>> In case you are comfortable with 2 mixed sine waves just use both
>> >>>>> DAC's, feed them independly and add them analog at the output pin
>> >>>>> with 2 resistors.
>> >>>>>
>> >>>>> Another way: create a lookup table for your "chords".
>> >>>>> In your current code you always use 32 steps for each sine wave -
>> >>>>> for one wave a step is e.g. 300us for the 2nd wave it is 310us.
>> >>>>> To mix them digitally you need finer steps.
>> >>>>> Create a table in RAM, and upsample (stretch) your 32 step-sine
>> >>>>> waves into that RAM-table according to the frequencies you want.
>> >>>>> Feed this RAM-table with the fastest clock (987Hz is about 1ms)
>> >>>>> to the DAC. For example in a 256 table the 987Hz wave fits 7.55
>> >>>>> times, the 130Hz waves only 1 time. For the 130Hz tone you have
>> >>>>> to calculate 256 values from you 32 values of the lookup table.
>> >>>>> This is called upsampling. You can use linear interpolation
>> >>>>> (lines) to calculate the values between the 32 lookup values from
>> >>>>> your Flash table (or drop the lookup table and use sin() from the
>> >>>>> C compiler, no idea how fast this is). The big deal here is, that
>> >>>>> in most cases the end of the RAM table does not fit to the begin
>> >>>>> of the RAM table, the waves are not connected smoothly together.
>> >>>>> You have to calculate a new RAM table once the first one has been
>> >>>>> sent, so that the waves are smoothly connected. Use 2 RAM tables,
>> >>>>> one for output (DMA), one for precalculation (in the main loop).
>> >>>>>
>> >>>>> You can do the interpolation on the fly in the CCR-Interrupt
>> >>>>> routine, no extra RAM table, no DMA needed (however, the sound
>> >>>>> will not be clear because of the jitter of the interrupt response
>> >>>>> time).
>> >>>>>
>> >>>>> M.
>> >>>>>
>> >>>>> Onestone:
>> >>>>>
>> >>>>>> i DON'T SEE HOW YOU COULD DO THIS WITH DMA. As a first try I'd
>> >>>>>> use 1 timer per tone, and track the last value for each tone.
>> >>>>>> Then on timer interrupt:-
>> >>>>>>
>> >>>>>> DACx = DACx - oldsinevalue + newsinevalue.
>> >>>>>>
>> >>>>>> Effectively remove the old value for the tone from the DAC and
>> >>>>>> add the new one at a variabe time interval. Also, given
>> >>>>>> something with as much memory as the 2619 i'd not limit myself
>> >>>>>> to a 32 entry table. In theory, and assuming that you aren't
>> >>>>>> using the other timers, you could get 7 tones using timer B. I'd
>> >>>>>> also go for the highest clock frequency possible, and in the ISR
>> >>>>>> keep the code short and clean. for minimal jitter. Rather than
>> >>>>>> absolute values your table could comprise differential values so
>> >>>>>> that your calculation is simple DACx = DACx + sine(n).
>> >>>>>>
>> >>>>>> Hope this helps
>> >>>>>>
>> >>>>>> Al
>> >>>>>>
>> >>>>>> On 25/04/2012 7:05 AM, zylaxice wrote:
>> >>>>>>> Hi all,
>> >>>>>>> I am currently working on some code for an MSP430F2619. I am
>> >>>>>>> using a 32-value sine lookup table, and pushing the sequential
>> >>>>>>> values out to the DAC12 via DMA, with the speed (and thus the
>> >>>>>>> note frequency) controlled by TimerB. So far,this is working
>> >>>>>>> well. I can produce any number of reasonable sounding pure
>> >>>>>>> tones/notes at frequencies from 130.8Hz (C3) to 987.7Hz (B5),
>> >>>>>>> and this is more than enough range for my needs, three full
>> >>>>>>> octaves.
>> >>>>>>>
>> >>>>>>> However, this only plays one tone at a time. I have been
>> >>>>>>> wracking my brains trying to figure out how to use this to
>> >>>>>>> generate a "chord," more than one note played at the same time.
>> >>>>>>> I know that musically this can be as simple as adding two sine
>> >>>>>>> waves together, but since I don't have two simultaneously
>> >>>>>>> existing sine waves, just one that I change the frequency of, I
>> >>>>>>> am at a loss.
>> >>>>>>>
>> >>>>>>> Does anyone have any suggestions on how to achieve this, or
>> >>>>>>> references that they think might push me in the right
>> >>>>>>> direction?
>> >>>>>>>
>> >>>>>>> Thank you,
>> >>>>>>> David
>> >>>>>>>
>> >>>