EmbeddedRelated.com
Forums

Multiple Sine Waves/Chords from a DAC

Started by zylaxice April 24, 2012
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
>

Beginning Microcontrollers with the MSP430

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
> >>>>>>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
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
>>
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
>>>>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
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