Shop OBEX P1 Docs P2 Docs Learn Events
Simple (Sound/Freq) Synthesizer — Parallax Forums

Simple (Sound/Freq) Synthesizer

John A. ZoidbergJohn A. Zoidberg Posts: 514
edited 2011-01-16 14:58 in Propeller 1
Hello there,

Sorry for the long absence, these new weeks of 2011 had kept me busy and I'm down with the flu as well! What a rough start!

Anyway, it's not about the New Year, it's about the DDS-Freq Synthesizer.

I've read some amazing threads about SID-cog and how the others did for the music modules. That had inspired me to make my own one.

Well, I could use a dsPIC on that, but since I have a couple of Propellers, why not I use them instead?

So, I've read up a bit of DDS (Digital Direct Synthesis), and then 'feed' it to the envelope generator.

However, one tiny issue here - no single-cycle hardware multiplier, so I can't really predict the frequency generated after the envelope by just using any High Level Language like Spin.

Or, I should dedicate one cog for the DDS, one cog for the Env. Generator?

On top of that, anything about Karplus-Strong synthesis done on a Prop? :)

Thanks for the opinions.:cool:

Comments

  • Heater.Heater. Posts: 21,230
    edited 2011-01-15 04:25
    John,

    You don't need DSP to do DDS. Just a table of sines (built it to the Props ROM) a phase counter (32 bits is fine I'm sure) and a tight loop fetching the values from the table and incrementing the phase counter. I've done this on the humble AVR.

    For the envelope a 16 by 16 bit multiply in PASM is quite fast enough. Perhaps in a separate COG.

    Never heard of Karplus-Strong before but it looks quite straight forward for the Prop http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis
  • John A. ZoidbergJohn A. Zoidberg Posts: 514
    edited 2011-01-15 08:03
    Thanks for the opinions. However, I'm still in the struggle of learning the phase counters in Spin/PASM. I will check out the fast multiply algorithm in the system.

    I've planned to start by using a sine and the square wave first, with the PWM output. Do you think the 8kHz sampling rate will help in this one? :)
  • Heater.Heater. Posts: 21,230
    edited 2011-01-15 08:39
    John,

    When I mentioned phase counters and DDS I was not thinking of the Props hardware counters but a software technique.

    Basically you have a table full of values of the sine function. Say 256 samples.
    Then you have a 32 bit "phase" counter that is incremented by some amount "delta" for each sample period.
    The phase counter is used as an index into the sine table. Use the top 8 bits of the phase counter, the table lookups wrap around the table.
    Changing the value of delta changes your frequency.
    Of course the table could also hold samples of any other waveform you like.

    Example:
    VAR
        long phaseCounter
        long delta
    
    PUB dds
        repeat
           sample := sin[phaseCounter >> 24]
           'Output sample here some how.
           phaseConter += delta
    
    
    DAT
    sin 'A table of 256 sine values.
    
    Fun to do in assembler for speed. Then you can have multiple phaseCounters and deltas creating multiple tones simultaneously.
  • Heater.Heater. Posts: 21,230
    edited 2011-01-15 09:20
    John,

    You got me thinking.

    We can do Fourier transforms on the Prop at a rate of more than twenty 1024 point transforms per second. That's good for real time transforms at 10KHz sample rate.

    So what about using the FFT backwards for synthesis? Have a buffer full of amplitude values of the frequencies you want to generate. Use the FFT to turn that into the required signal waveform.
  • AribaAriba Posts: 2,690
    edited 2011-01-15 10:41
    With Spin you can do a DDS with wavetable at about 16kHz.
    Here is a test I have done some years ago:
    {{ DDS Test }}
    CON  _clkmode      = xtal1 + pll16x                                    
         _xinfreq      = 5_000_000
    
         DAC_PIN   = 15
         MIDDLE    = 1<<31
    
         FREQUENCY = 440        'Hz
         VOL       = 70 <<24    '0..255 <<24
         
    PUB Main   | phs, phsm, frq, smp, time
      dira[DAC_PIN] := 1                 'Set up DAC
      ctra := %00110 << 26 + DAC_PIN     'counter A in DUTY mode
      
      frq := MIDDLE / 8_000 * FREQUENCY  'calc frq steps for 16kHz fs
      
      time := cnt
      repeat                             '1 kHz loop
        phs += frq                       'DDS oscillator
        smp := sintab[phs>>24] << 24     'table waveform (sine)
        frqa := smp ** VOL + MIDDLE      'smp * volume to DAC
    
        waitcnt(time += 5000)            '16kHz loop freq (80MHz clk)
    
    DAT
    sintab  byte 127,127,127,127,127,127,126,126,125,124,124,123,122,121,120,119
            byte 118,117,115,114,112,111,109,108,106,104,102,100,98,96,94,92
            byte 90,88,85,83,81,78,76,73,71,68,65,63,60,57,54,51
            byte 48,46,43,40,37,34,31,28,24,21,18,15,12,9,6,3
            byte 0,-4,-7,-10,-13,-16,-19,-22,-25,-29,-32,-35,-38,-41,-44,-47
            byte -49,-52,-55,-58,-61,-64,-66,-69,-72,-74,-77,-79,-82,-84,-86,-89
            byte -91,-93,-95,-97,-99,-101,-103,-105,-107,-109,-110,-112,-113,-115,-116,-118
            byte -119,-120,-121,-122,-123,-124,-125,-125,-126,-127,-127,-128,-128,-128,-128,-128
            byte -128,-128,-128,-128,-128,-128,-127,-127,-126,-125,-125,-124,-123,-122,-121,-120
            byte -119,-118,-116,-115,-113,-112,-110,-109,-107,-105,-103,-101,-99,-97,-95,-93
            byte -91,-89,-86,-84,-82,-79,-77,-74,-72,-69,-66,-64,-61,-58,-55,-52
            byte -49,-47,-44,-41,-38,-35,-32,-29,-25,-22,-19,-16,-13,-10,-7,-4
            byte 0,3,6,9,12,15,18,21,24,28,31,34,37,40,43,46
            byte 48,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88
            byte 90,92,94,96,98,100,102,104,106,108,109,111,112,114,115,117
            byte 118,119,120,121,122,123,124,124,125,126,126,127,127,127,127,127
    

    Andy
  • HumanoidoHumanoido Posts: 5,770
    edited 2011-01-15 11:43
    Andy, what board does this code run on and what extra hardware is needed? Thanks!
  • Heater.Heater. Posts: 21,230
    edited 2011-01-15 11:48
    Sorry, I described DDS wrongly, one wants to use the top 8 bits of the phase counter not the lower. Ariba's code is more like it.
  • AribaAriba Posts: 2,690
    edited 2011-01-15 15:13
    Humanoido wrote: »
    Andy, what board does this code run on and what extra hardware is needed? Thanks!

    You can use every Propeller Board with a free pin to test. The 16 kHz loop is calculated for 80MHz clock frequency, but another clock will work also, just results not in the right frequency.
    The output pin can be defined in the CON section (DAC_PIN). On a DemoBoard you will use 10 or 11. I normally use just a current limiting resistor with 220 Ohm and go directly to a Earphone or activ Loudspeaker box. For example a Video out circuit with the 3 or 4 resistors is also OK id you set the DAC_PIN to video basepin + 2.

    Andy
  • John A. ZoidbergJohn A. Zoidberg Posts: 514
    edited 2011-01-15 19:33
    Heater. wrote: »
    John,

    You got me thinking.

    We can do Fourier transforms on the Prop at a rate of more than twenty 1024 point transforms per second. That's good for real time transforms at 10KHz sample rate.

    So what about using the FFT backwards for synthesis? Have a buffer full of amplitude values of the frequencies you want to generate. Use the FFT to turn that into the required signal waveform.

    Yeah that's a very good idea too. However, I'm still struggling with the FFT algorithm, so I need some more time to digest it. :)

    I could cook up the DDS algorithm easier, but the Envelope Generator has left me wondering.

    If I start with a normal exponential Env.Generator, example, exp(-t), then I multiply it by the output, I would risk running past the lookup Envelope table if it exceeds the duration. (What I meant is an effective, and realistic chime tone instead of just plain beeeeeeep).

    My pseudocode will be like:

    1.) phase += Frequency
    2.) increment time counter (for a duration of a musical note or a tone)
    3.) The volume of the musical tone decays approximately 15 msec, so draw out each envelope value every 15 msec and dump it into a variable
    4.) multiply the output with the volume of the tone, then shift it back to 8-bits
    5.) Repeat, from 1 to 4 until time counter reaches the desired value.

    The 1, 2 and 4, I do not have a problem.

    But I'm stumbled at the 3. Should I have a spare counter to keep track of the envelope table, or should I use the main time counter and then do a divide operation?

    Opinions are greatly appreciated. :)
  • siljamickesiljamicke Posts: 66
    edited 2011-01-16 01:55
    I am working on a synth engine using these techniques myself, and i will post a thread as i progress a bit.
    However i got really excited by what Heater wrote on FFT. I've been trying to understand the concept of Fourier, FFT, Laplace,Z, and what not, for ages now, but since i lack any knowledge in math, i'm at a dead end it seems.
    But i refuse to think that a concept only can be explained with a formula. For instance is the explanation of DDS here in this thread far better than any in a textbook i've ever read!
    Could you, Heater, perhaps give a more intuitive, verbal and down to earth explanation on FFT?
    Not an exhaustive explanation on the matter, just some hints.
    I understand the input (any complex waveform) and the output (the sinusodial components and their respective amplitudes), but the black box in the middle, gaah! ;)
  • Heater.Heater. Posts: 21,230
    edited 2011-01-16 02:54
    siljamicke,
    But i refuse to think that a concept only can be explained with a formula.
    I agree. I pretty much don't feel that I understand any maths unless I can form a picture of what is going on in my mind. The formula is just a short hand for expressing the idea, the idea is in the pictures to me.

    Often what you want to know/understand about a topic is buried in a mountain of math detail and diversions that just serve to confuse. I found that to be the case with FFT for a long time.

    Re: FFT, there is a great thread going on here, "Fourier for Dummies" http://forums.parallax.com/showthread.php?127306-Fourier-for-dummies-under-construction. Bean has contributed a document about Fourier that you will find there and is a good intro to the Fourier Transform.

    A few things to get started:

    1) The input to the Fourier transform is a list of sampled signal values.

    2) The output is a list of amplitudes of the frequencies that make up that signal.

    3) Once you have a sampled signal there is only certain frequencies that it can contain. Say you have one 1024 samples in a second. The frequencies in the out put are from zero (D.C.) to 511Hz.

    4) But the output list is 1024 entries! That's OK the second half of the list contains the negative frequencies.

    5) What negative frequencies? How can something happen a negative number of times per second?!!
    No problem, imagine a wheel going around. Some point on the wheel goes up and down as it rotates. You can plot it's vertical position as a sinusoidal wave form with some frequency. BUT now turn the wheel in the opposite direction at the same speed. The sinusoid that you plot will be the same. So "negative frequency" is just that rotation in the reverse direction.

    6) If you multiply two sine waves, A and B together and take the average of the result you will get zero for all cases except when the frequency of A and B and phase are the same. Magic ha?. Try drawing out some sines and see what happens.

    7) So if you want to know if frequency F is in your input samples just multiply all the values of the input samples by corresponding values of a sine at frequency F. Then take the average. Only if the frequency F is present in the input will you get a non-zero result. The value of which is the amplitude of that frequency component.

    8) The above fails if the component frequency F is out of phase with the "test" sine wave you are multiplying it against. The more out of phase it is the less it is detected until at 90 degrees out of phase it is not detected at all.

    That's OK if you also multiply against a cosine at frequency F that will tell you how much of the signal at F is in phase with sine and how much is in phase with cos. These can be combined to give the actual magnitude no matter what the incoming phase is.

    9) If you do the multiplying and averaging against "test" sine and cos waveforms as in 7) and
    8) for all possible values of frequency F. (0 to 512 in our example) then you have detected all possible frequencies in the input. Easy hey?

    And that is the Fourier Transform:)
  • siljamickesiljamicke Posts: 66
    edited 2011-01-16 11:02
    Wow! It should be mathematically proven that math makes life unnecesarilly awkward!
    I think this was as clear as anything has to be. Future textbooks on the matter fourier analysis will be a single page with the URL to this thread!
    You may now proceed to enlighten me on FFT! ;-)

    Big big thanks!
  • AribaAriba Posts: 2,690
    edited 2011-01-16 13:51
    John

    The simplest form of a decay envelope is to multiply the vol value with a factor < 1.0. So the vol value decreases exponential. The factor defines the decay time.

    Another methode is to see the envelope as a waveform. So you can do another DDS with much slower frequency and a Envelope waveform.

    Here is my testcode extended with the first methode:
    {{ DDS Test with Decay }}
    CON  _clkmode      = xtal1 + pll16x                                    
         _xinfreq      = 5_000_000
    
         DAC_PIN   = 15
         MIDDLE    = 1<<31
    
         FREQUENCY = 500        'Hz
         VOLUME    = 90 <<24    '0..255 <<24
         DECAY     = $FFD0      '$FF00..$FFFF
         
    PUB Main   | phs, vol, frq, smp, time
      dira[DAC_PIN] := 1                 'Set up DAC
      ctra := %00110 << 26 + DAC_PIN     'counter A in DUTY mode
      
      frq := MIDDLE / 5_000 * FREQUENCY  'calc frq steps for 10kHz fs
    
      repeat
        vol := VOLUME                    'start value of Env
        time := cnt
        repeat                           '10 kHz loop
          phs += frq                     'DDS oscillator
          smp := sintab[phs>>24] << 24   'table waveform (sine)
          frqa := smp ** vol + MIDDLE    'smp * volume to DAC
           
          vol := vol>>16 * DECAY         'calc Env decay
          waitcnt(time += 8000)          '10kHz loop freq (80MHz clk)
        until vol < $1000
        waitcnt(clkfreq + cnt)
                                          
    DAT
    sintab  byte 127,127,127,127,127,127,126,126,125,124,124,123,122,121,120,119
            byte 118,117,115,114,112,111,109,108,106,104,102,100,98,96,94,92
            byte 90,88,85,83,81,78,76,73,71,68,65,63,60,57,54,51
            byte 48,46,43,40,37,34,31,28,24,21,18,15,12,9,6,3
            byte 0,-4,-7,-10,-13,-16,-19,-22,-25,-29,-32,-35,-38,-41,-44,-47
            byte -49,-52,-55,-58,-61,-64,-66,-69,-72,-74,-77,-79,-82,-84,-86,-89
            byte -91,-93,-95,-97,-99,-101,-103,-105,-107,-109,-110,-112,-113,-115,-116,-118
            byte -119,-120,-121,-122,-123,-124,-125,-125,-126,-127,-127,-128,-128,-128,-128,-128
            byte -128,-128,-128,-128,-128,-128,-127,-127,-126,-125,-125,-124,-123,-122,-121,-120
            byte -119,-118,-116,-115,-113,-112,-110,-109,-107,-105,-103,-101,-99,-97,-95,-93
            byte -91,-89,-86,-84,-82,-79,-77,-74,-72,-69,-66,-64,-61,-58,-55,-52
            byte -49,-47,-44,-41,-38,-35,-32,-29,-25,-22,-19,-16,-13,-10,-7,-4
            byte 0,3,6,9,12,15,18,21,24,28,31,34,37,40,43,46
            byte 48,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88
            byte 90,92,94,96,98,100,102,104,106,108,109,111,112,114,115,117
            byte 118,119,120,121,122,123,124,124,125,126,126,127,127,127,127,127
    

    Andy
  • Heater.Heater. Posts: 21,230
    edited 2011-01-16 14:48
    siljamicke,
    It should be mathematically proven that math makes life unnecesarilly awkward!

    Ha, ha!, Now I could show you the proof of that but it would make your life even more unnecessarily awkward:)
    You may now proceed to enlighten me on FFT

    Ah...Now I have at least two people here presenting me with that challenge.

    Not so fast. It has taken many years for the secrets of the FFT to drop into place in my mind. My problem now is that I can't get you from Fourier Transform as described above to FFT in code without going through some yuky maths.

    The good news, perhaps, is that I can strip the maths down to the minimum required essentials. I've been pondering how to present this for a while now. I'd like to be able to tell it as a chatty story of discovery rather than a dusty math text book.
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-16 14:58
    Hi Heater

    You have more that 2. I'm one more. This thread are nice place to show solutions what FFT can be used to.
    And thanks for descriptive approach Of FFT's function.

    Heater. wrote: »
    siljamicke,



    Ha, ha!, Now I could show you the proof of that but it would make your life even more unnecessarily awkward:)



    Ah...Now I have at least two people here presenting me with that challenge.

    Not so fast. It has taken many years for the secrets of the FFT to drop into place in my mind. My problem now is that I can't get you from Fourier Transform as described above to FFT in code without going through some yuky maths.

    The good news, perhaps, is that I can strip the maths down to the minimum required essentials. I've been pondering how to present this for a while now. I'd like to be able to tell it as a chatty story of discovery rather than a dusty math text book.
Sign In or Register to comment.