Shop OBEX P1 Docs P2 Docs Learn Events
Prop sound quality question — Parallax Forums

Prop sound quality question

danielstrittdanielstritt Posts: 43
edited 2013-10-01 11:36 in Propeller 1
I decided to write my own wave playing program on the prop, to learn how to use sound with it. After 12 straight hours, I got it up and running. Problem is, the sound is muddy, like a very low bitrate mp3. But before I put time into fixing it, I need to know if the prop is capable of cd quality sound, or is that the best I can do?

Comments

  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2013-05-29 02:37
    The prop can easily do 16bit, 44.1khz WAV files. I am using the KISS WAV player object to do that now.
  • JonnyMacJonnyMac Posts: 8,926
    edited 2013-05-29 07:52
    Andrew is correct -- I have a board that runs 100MHz and does 48kHz audio with no trouble. One thing you can run into problem with is using the counters as DACs. The nature of propagation delays across the silicon to the IO pins can add clicks and pops and scratchy noise to the audio. I tore my hair out for a week with this before calling Chip Gracey who immediately identified the problem. His solution (for the Propeller 1) is to add high frequency white noise to the audio which will get filtered out by the RC circuit connected to to the pin. It's seems odd, but it works.

    This will be a non-issue for the Propeller 2 as it has built-in DACs.
  • pik33pik33 Posts: 2,350
    edited 2013-05-29 08:17
    The Propeller can do a noise free HQ sound using NCO counters and noise shaping filter instead of duty dac.

    Here is my player: http://forums.parallax.com/showthread.php/140767-A-new-topic-for-vga-%28not-only%29-sid-player

    Compile with BST with unused method removal or it doesn't fit in 32k.

    You can find a sound driver in it, which output noise free sound using ~300 KHz/8 bit sampling with noise shaping filter.

    And one more thing: Propeller Demo Board has bad low pass filters (~1.6 kHz @3dB) - I had to modify this on my demo board. This filter makes the sound dull. No high freqs.
  • JonnyMacJonnyMac Posts: 8,926
    edited 2013-05-29 09:05
    Perhaps you can elaborate because I'm finding this in the you code:
    arg1 := $18000000 | left
      arg2 := $18000000 | right
    


    ...which clearly shows the counters are being setup in DUTY cycle mode (single-ended). This is what I do in my player code, too. That said, when playing in low-frequency, 16-bit WAV file (especially pure tones), unexpected noise will show up without using Chip's stereo_duty cog. The best solution, which I used once, is a high-speed SPI DAC -- but they're expensive.
  • pik33pik33 Posts: 2,350
    edited 2013-05-29 10:15
    I used standard duty dac until last (0.16) version of the player. Then I switched to nco version. Here it is (extracted from Propplay 0.16) Mode==0 is for sidcog (~32 kHz main sample rate +> more oversampling possible)

    To compile Propplay with std prop tools, it may be sufficient to remove a "demo" method from the VGA driver.
    This is ncowav version for using with a propplay. Get a full version of this from its topic on the propeller forum
    }}
    
    
      _clkmode = xtal1+pll16x
      _clkfreq = 80_000_000
    
      _SD_DO = 0
      _SD_CLK = 1
      _SD_DI = 2
      _SD_CS = 3
      _SD_WP = -1 ' -1 ifnot installed.
      _SD_CD = -1 ' -1 ifnot installed.
    
    VAR
    
    '  long bufnum
      long cog
      long buf[512]
      long bufnum
    
    
    pub getbuf
    return @buf
    
    pub getbufnum
    return @bufnum
    
    
    PUB start(left, right, mode, addr)
    
    smode:=mode
    longfill(@buf,0,512)
    if mode==1
      bufptr:=@buf
      overval:=7
      delay:=259
    if mode==0
      bufptr:=addr
      overval:=9
      delay:=288
    stop
    
    leftcounter := ((left & $1F) + constant(100000 << 23))
    rightcounter := ((right & $1F) + constant(100000 << 23))
    outputmask := |<left | |<right
    
    'coginit (7,@init,@bufnum)
    cog:=1+cognew(@init, @bufnum)
    return cog
      
    
    PUB stop
    
    if cog>0
      cogstop(cog-1)
    cog := 0
      
    
    DAT
                            org     0                         'initialization
    
    init                    mov     ctra,leftcounter         ' nco mode
                            mov     ctrb,rightcounter
                            mov     frqa,#1                  ' frq=1 for pwm mode
                            mov     frqb,#1
                            mov     dira,outputmask          ' enable output on selected pins
                            mov     bufptr2,par
                            mov     time,cnt
                            add     time,delay
    
    loop                    cmp     smode,#0                 wz
                   if_z     jmp     #p3
                            mov     ptr,bufptr               ' compute pointer to sample
                            add     ptr,bufcnt
                            rdword  lsample,ptr              ' get left
                            shl     lsample,#16
                            add     ptr, #2
                            rdword  rsample,ptr              ' get right
                            sar     lsample,#16
                            shl     rsample,#16              ' extend sign to 32 bits
                            sar     rsample,#16
                            add     bufcnt,#4
                            and     bufcnt,bufmask
    p4                      mov     over,overval
                            wrlong  bufcnt,bufptr2           ' write actual sample number for main program
                            jmp     #p2
    
    p3                      mov     ptr,bufptr
                            rdlong  lsample,ptr
                            sar     lsample,#16
                            mov     rsample, lsample
                            shl     rsample,#1
                            add     lsample, rsample
                            shl     rsample,#1
                            add     lsample, rsample
                            sar     lsample,#3
    
                            mov     rsample,lsample
                            jmp     #p4
    
    
    p2                      add     i1l,lsample              ' noise shape left
                            add     i2l,i1l
                            mov     topl,i2l
                            sar     topl,#8
                            mov     fbl,topl
                            shl     fbl,#8
                            sub     i1l,fbl
                            sub     i2l,fbl
    
                            add     i1r,rsample              ' noise shape right
                            add     i2r,i1r
                            mov     topr,i2r
                            sar     topr,#8
                            mov     fbr,topr
                            shl     fbr,#8
                            sub     i1r,fbr
                            sub     i2r,fbr
    
    
                            maxs    topr, maxval           ' clip max to avoid clicks
                            mins    topr, minval
                            add     topr, #$80             ' convert to 8 bit unsigned
                            and     topr, #$FF
                            maxs    topl, maxval
                            mins    topl, minval
                            add     topl, #$80
                            and     topl, #$FF
    
                            waitcnt time, delay
                            neg     phsa, topr            ' Output.
                            neg     phsb, topl            ' Output.
    
                            djnz    over,#p2
                            jmp    #loop
    
    leftcounter             long    0
    rightcounter            long    0
    outputmask              long    0
    delay                   long    259
    bufmask                 long    00_0000_0000_0000_0000_0111_1111_1111
    overval                 long    7
    maxval                  long    127
    minval                  long   -127
    bufptr                  long    0
    bufptr2                 long    0
    bufcnt                  long    0
    smode                   long    0
    
    over                    res 1
    lsample                 res 1
    rsample                 res 1
    time                    res 1
    topl                    res 1
    topr                    res 1
    fbl                     res 1
    fbr                     res 1
    i1r                     res 1
    i1l                     res 1
    i2l                     res 1
    i2r                     res 1
    ptr                     res 1
    
    
    
                            fit     496
    
    {{
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                  TERMS OF USE: MIT License
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    // Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
    
  • KyeKye Posts: 2,200
    edited 2013-05-29 12:36
    How does the NCO mode work?

    Are you doing a PWM pulse train?

    If so... then (80 MHz / 44.1 KHz) = 1,814 so the bit resolution is about 11 bits then right? I suppose that is enough for good audio. 8-bits is too low.
  • pedwardpedward Posts: 1,642
    edited 2013-05-29 12:46
    JonnyMac wrote: »
    Andrew is correct -- I have a board that runs 100MHz and does 48kHz audio with no trouble. One thing you can run into problem with is using the counters as DACs. The nature of propagation delays across the silicon to the IO pins can add clicks and pops and scratchy noise to the audio. I tore my hair out for a week with this before calling Chip Gracey who immediately identified the problem. His solution (for the Propeller 1) is to add high frequency white noise to the audio which will get filtered out by the RC circuit connected to to the pin. It's seems odd, but it works.

    This will be a non-issue for the Propeller 2 as it has built-in DACs.

    He also said to use pin 0 of COG 0 because the electrical path was the shortest.
  • Mark_TMark_T Posts: 1,981
    edited 2013-05-29 16:58
    Kye wrote: »
    How does the NCO mode work?

    Are you doing a PWM pulse train?

    If so... then (80 MHz / 44.1 KHz) = 1,814 so the bit resolution is about 11 bits then right? I suppose that is enough for good audio. 8-bits is too low.

    Not with sigma-delta conversion and noise-shaping, no. You can get 24 bit audio happily out using 11 bit PWM, and PWM is orders of magnitude less sensitive
    to jitter than NCO mode. Without understanding sigma-delta and noise-shaping it all looks like magic.
  • Tracy AllenTracy Allen Posts: 6,656
    edited 2013-05-29 20:22
    I'd bookmarked threads where Piotr developed his ideas for alternative audio pin drivers including the NCO-PWM method with noise shaping. The 8-bit PWM is delivered to the pin in the standard manner, by retarding the phase of ctra and ctrb by the N/256 fraction dictated by the current sample after noise shaping.

    A-new-topic-for-vga-not-only -sid-player?
    12-bit-audio-using-video-generator-first-working-concept
    Return-to-duty-dac-oversampling-noise-shaped-player
    A-simple-dithered-wav-player-now-dithers-every-1-microsecond
    Post #11 in that last one also has Mark_T's very interesting class D sigma-delta driver. That drives the class D by the phase difference between two counters.
  • pik33pik33 Posts: 2,350
    edited 2013-05-29 21:51
    I used Mark_T idea and his code (slightly modified to fit in ncowav) in my driver. It is 8 bit but still delivers high quality audio because of oversampling and noise shaping used. The noise shaping causes near all quantization noise go to Fs/2, and in this case this is about 150 KHz, in ultrasonic range. As far as I know, we gain about 12 (maybe more) dB of SNR in audible range, when 2x oversampling/noise shaping, so this driver should have SNR in accoustic range better than 88 dB.

    In "real life" only audible noise from a demoboard when using ncowav is its amplifier noise.

    Also, I changed demoboard RC filter, shifting 3dB freq from 1.6 to 21 kHz.
  • KyeKye Posts: 2,200
    edited 2013-05-30 06:31
    I tried reading the code, I have no clue what you are doing :).
  • pik33pik33 Posts: 2,350
    edited 2013-05-30 07:34
    I am doing noise shaping. I think Mark_T can describe it better, but it works like this:

    We have a 16-bit sample, for example $1280. When output as 8 bit, it will be constant $12. When output after noise shaping filter it will be something like 12-13-12-13-12-13

    Average is 12.5 (=>1280) and you have unhearable noise (square wave) @ 150 kHz.

    Near all quantization noise goes to the ultrasonic range, and you have noise free sound, The noise is still there, but you can't hear it.

    This is a noise shaper, all magic is here:
                            add     i1l,lsample              ' noise shape left
                             add     i2l,i1l
                             mov     topl,i2l
                             sar     topl,#8
                             mov     fbl,topl
                             shl     fbl,#8
                             sub     i1l,fbl
                             sub     i2l,fbl
    
    

    We have two integrators, i1l and i2l (for the left channel). Top 8 bits from second integrator goes to the output, and then are subtracted from both integrators. So, what is really integrated, is the quantization noise, and when there is more than 8 bit integrated, it is added to the output.
  • KyeKye Posts: 2,200
    edited 2013-10-01 11:36
Sign In or Register to comment.