Shop OBEX P1 Docs P2 Docs Learn Events
Newbie Spin Question — Parallax Forums

Newbie Spin Question

NWCCTVNWCCTV Posts: 3,629
edited 2013-04-20 18:54 in Propeller 1
Being new to Spin I am not even sure if this is possible so go easy on me. If it is not possible suggestions are welcome. I have modified the Pressure Sensor Bar Graph Demo program to start and stop various servos depending on the rawReading received. Now I need tp play some .wav files pretty much at the same time. If I include one of the .wav/sd card reading programs from the OBEX in my Objects section, is there a way to call the "read SD card and Play .wav file functions from that program?
«1

Comments

  • marzec309marzec309 Posts: 146
    edited 2013-04-06 11:30
    yes, create a nick name for sd program, in your project use the OBJ field and make a entery similar to this:

    obj
    music : "name_of_object_here"

    then in your program you can call any of its public methods like this:

    music.name_of_method
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-06 11:45
    OK, But how do I then call the "read SD card" and "play wav file" methods that are within the added object?

    Edit: Here is the .wav/sd card code:
    ' ASM WAV Player Ver. 2g (Plays 16-bit PCM WAV files from SD card)
    ' Copyright 2007-2013 Raymond Allen
    ' MIT License: See end of file for terms of use. 
    ' Settings for Demo Board Audio Output: Right Pin# = 10, Left Pin# = 11
    ' Rev.2G: Added support for variable size header before "data"
    ' Rev.2C: Made code easier to use and understand and added mono support 
    
    CON 'Crystal settings
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000 '80 MHz
    
    CON 'SD card pin settings
    'Set the pins used for SD card here
    'Propeller Platform Express settings:
    SD_MISO=22
    SD_CLK=23
    SD_MOSI=24
    SD_CS=25
    
    'Quick Media Player Settings
    {
    SD_MISO=27
    SD_CLK=26
    SD_MOSI=25
    SD_CS=24
    }
    CON 'Audio Pins and buffer size
    'Here you can select the audio output pins
    'Demo Board Settings:
    Pin_Right=26
    Pin_Left=27
    'Quick Media Player Settings
    {
    Pin_Right=23
    Pin_Left=22
    } 
    'Slow SD cards may require a larger buffer, adjust with value below
    buffLongs=100
    buffWords = buffLongs*2+1 
    'Volume control
    volume = 45535 'range is 0 to 65535 with 65535 being the loudest 
    
    VAR long parameter1 'to pass @buff1 to ASM
    long parameter2 'to pass @buff2 to ASM
    long parameter3 'to pass sample rate to ASM
    long parameter4 'to pass #samples to ASM
    long parameter5 'to pass #channels to ASM
    long parameter6 'to pass #samples in each buffer
    long parameter7 'to pass volume to ASM
    word buff1[buffWords]
    word buff2[buffWords]
    byte Header[44]
    
    OBJ
    SD : "FSRW"
    ser : "fullduplexserial" 'for monitoring
    PUB Main
    'Play a WAV File
    'Start serial connection
    ser.start(31,30,0,9600)
    waitcnt(cnt+clkfreq*2) 'Wait 2 seconds (but don't need to)
    ser.str(string(13,13,"Playing wav file...",13)) 
    PlayWav(string("heart1.wav")) ' <--------- Change .wav filename to play here !!!!!!!!!!!!!!
    ser.str(STRING("Play wav complete.",13)) 
    repeat 'all done
    
    PUB PlayWav(pFileName)|n,i,j, SampleRate,Samples,nChannels,ChunkSize,SamplePeriod,PlayTime
    
    'open the WAV file (NOTE: Only plays stereo, 16-bit PCM WAV Files !!!!!!!!!!!!!)
    
    'Mounting SD card now
    ser.str(string("Attempting to mount SD card",13))
    repeat 'try forever to mount the SD card
    i:=\sd.Mount_Explicit(SD_MISO,SD_CLK,SD_MOSI,SD_CS) 
    if i==0
    quit 'mounted, so exit
    waitcnt(cnt+clkfreq/4)
    ser.tx(".")
    ser.str(string("SD card mounted.",13)) 
    
    'open file
    ser.str(string("Attempting to open wav file: "))
    ser.str(pFileName)
    ser.tx(13)
    
    i:=\sd.popen(pFileName,"r") 
    if (i<>0)
    ser.str(string("Cannot open wav file.",13)) 
    return
    'Plays only 16-bit PCM WAV Files !!!!!!!!!!!!!!!!
    'See here for header format: [URL]https://ccrma.stanford.edu/courses/422/projects/WaveFormat/[/URL] 
    i:=sd.pread(@Header, 44-8) 'read data words to input stereo buffer
    'Get bits per sample (must be 16)
    if (Header[35]<<8+Header[34])<>16
    ser.str(string(13,"Error: Not 16 bits per sample!",13))
    return 
    'Get audio format, must be PCM
    if (Header[21]<<8+Header[20])<>1
    ser.str(string(13,"Error: Not uncompressed PCM data",13))
    return 
    'Get sample rate from header
    SampleRate:=Header[27]<<24+Header[26]<<16+Header[25]<<8+Header[24]
    ser.str(string("Sample Rate: ")) 
    ser.dec(SampleRate)
    ser.tx(13)
    'Get # channels from header
    nChannels:=Header[23]<<8+Header[22]
    ser.str(string("#Channels: "))
    ser.dec(nChannels)
    ser.tx(13)
    'Find data
    repeat
    sd.pread(@Header[36], 4)
    if Header[36]<<24+Header[37]<<16+Header[38]<<8+Header[39] == $64617461
    quit 'found data
    sd.pread(@Header[40],4) 'read subchunk size
    
    'get # samples from header
    ChunkSize:=Header[43]<<24+Header[42]<<16+Header[41]<<8+Header[40]
    Samples:=(ChunkSize>>1)/nChannels
    ser.str(string("#Samples: ")) 
    ser.dec(Samples)
    ser.tx(13)
    'Calculate play time
    SamplePeriod:=CLKFREQ/SampleRate '#clocks between samples'1814'for 44100ksps, 5000 'for 16ksps 
    ser.str(string("Playtime (s) = ")) 
    ser.dec(Samples*SamplePeriod/ClkFreq)
    ser.tx(13)
    
    
    'Start ASM player in a new cog
    ser.str(STRING("Running ASM Player",13)) 
    parameter1:=@buff1 'address of first buffer
    parameter2:=@buff2 'address of second buffer
    parameter3:=SamplePeriod 'time between samples
    parameter4:=Samples 'total # samples
    parameter5:=nChannels '#channels
    parameter6:=(BuffWords-1)/nChannels '#samples in each buffer
    parameter7:=volume&$FFFFF 'volume control (0..65535)
    COGNEW(@ASMWAV,@parameter1)
    'Keep filling buffers until end of file
    ' note: using alternating buffers to keep data always at the ready...
    n:=buffWords-1
    buff1[n]:=1 'set empty flags at end of buffers
    buff2[n]:=1
    i:=n*2 'number of bytes to read
    'Keep buffers filled until got all samples
    j:=samples*nChannels*2
    PlayTime :=cnt
    repeat
    repeat until buff1[n]==1 'wait until buffer empty
    if sd.pread(@buff1, i)<>i 'read data words to input stereo buffer 
    quit 
    buff1[n]:=0 'clear empty flag
    j-=i
    if j=<0
    quit
    
    repeat until buff2[n]==1 'wait until buffer empty
    if sd.pread(@buff2, i)<>i
    quit 'read data words to input stereo buffer 
    buff2[n]:=0 'clear empty flag
    j-=i
    if j=<0
    quit
    ser.str(string("Played time (s) = ")) 
    ser.dec((cnt-PlayTime)/clkfreq)
    ser.tx(13) 
    
    'must have reached the end of the file, so close it
    \sd.pclose
    
    return
    
    DAT
    ORG 0
    ASMWAV
    'load input parameters from hub to cog given address in par
    movd :par,#pData1 
    mov x,par
    mov y,#7 'input 7 parameters
    :par rdlong 0,x
    add :par,dlsb
    add x,#4
    djnz y,#:par
    setup
    'setup output pins
    MOV DMaskR,#1
    ROL DMaskR,OPinR
    OR DIRA, DMaskR
    MOV DMaskL,#1
    ROL DMaskL,OPinL
    OR DIRA, DMaskL
    'setup counters
    OR CountModeR,OPinR
    MOV CTRA,CountModeR
    OR CountModeL,OPinL
    MOV CTRB,CountModeL
    'Wait for SPIN to fill table
    MOV WaitCount, CNT
    ADD WaitCount,BigWait
    WAITCNT WaitCount,#0
    'setup loop table
    MOV LoopCount,SizeBuff
    MOV pData,pData1
    MOV nTable,#1
    'setup loop counter
    MOV WaitCount, CNT
    ADD WaitCount,dRate
    
    MainLoop
    CMP nSamples,#0 wz,wc 'see if out of samples
    IF_e JMP #Done
    SUB nSamples,#1
    waitcnt WaitCount,dRate
    cmp nChannel,#2 wz,wc
    if_e jmp #Stereo 'otherwise, assume mono
    Mono
    call #ReadWithVolume
    mov right,y
    mov left,right
    jmp #Output
    
    Stereo
    call #ReadWithVolume
    mov right,y
    add pData,#2
    call #ReadWithVolume
    mov left,y 
    Output
    ADD pData,#2 
    MOV FRQA,Right 
    MOV FRQB,Left
    
    'loop
    DJNZ LoopCount,#MainLoop
    WRword one,pData 'set empty flag 
    
    MOV LoopCount,SizeBuff 
    'switch table ?
    CMP nTable,#1 wz
    IF_Z JMP #SwitchToTable2
    SwitchToTable1
    MOV nTable,#1
    MOV pData,pData1
    JMP #MainLoop
    SwitchToTable2
    MOV nTable,#2
    MOV pData,pData2
    JMP #MainLoop
    
    
    Done
    
    'now stop
    COGID thisCog
    COGSTOP thisCog 
    'Multiply routine adapted from manual
    '' Multiply x[15..0] by y[15..0] (y[31..16] must be 0)
    ' on exit, product in y[31..0]
    ReadWithVolume
    mov x,dVolume
    rdword y,pData
    add y,twos
    and y,ffff
    shl x,#16 'get multiplicand into x[31..16]
    mov t,#16 'ready for 8 multiplier bits
    shr y,#1 wc 'get initial multiplier bit into c
    :loop
    if_c add y,x wc 'if c set, add multiplicand to product
    rcr y,#1 wc 'put next multiplier in c, shift prod.
    djnz t,#:loop 'loop until done
    ReadWithVolume_ret
    ret 'return with product in y[31..0]
    
    'Working variables
    thisCog long 0
    x long 0
    y long 0
    t long 0
    dlsb long 1 << 9
    BigWait long 100000
    twos long $8000_8000
    ffff long $ffff
    
    'Loop parameters
    nTable long 0
    WaitCount long 0
    pData long 0
    LoopCount long 0
    Left long 0
    Right long 0
    Zero long 0
    one long 1 
    'setup parameters
    DMaskR long 0 'right output mask
    OPinR long Pin_Right 'right channel output pin # 
    DMaskL long 0 'left output mask 
    OPinL long Pin_Left 'left channel output pin # 
    CountModeR long
    
  • marzec309marzec309 Posts: 146
    edited 2013-04-06 12:09
    ok say you nicknamed it music and the file name is song. your code would contain:
    obj
       music : "     "       'in the quotes type the name of the object exactly as it is saved. 
                                 'Also make sure its in the same folder as this code.
    
    pub
       music.PlayWav(string("song"))   'replace song with the file on the sd card you would like played. leave the quotes!
    
    
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-06 13:16
    I tried this but I am getting an "Expected Subroutine Name" error. Here is the full code.
    {{
    Pressure Sensor and BarGraph DEMO.spin
    Program Date: 1/4/2013
    Version:      1.1 Modified version to add the ability to turn a servo on and off at specified pressure.
    Description:
    This program reads voltage values from the Propeller BOE's ADC and prints the raw value to
    the Parallax Serial Terminal program running on your PC.  The program also uses a cog to
    show a linear representation of the pressure sensed on a 10-segment LED bar graph.
     
                               Propeller BOE Wiring Diagram
    
    === Pressure Sensor Pin Connections ===   
                                                       
                             +5v                       
                              &#61463;                        
                              &#9474;                        
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488; &#9474;                        
              &#9474;             &#9474; &#9474;                        
              &#9474;   MPX5010   &#9474; &#9474;                         
              &#9474;             &#9474; &#9474;                         
              &#9492;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9496; &#9474;                         
          Pin 1 &#9474; &#9474; &#9474; x x x   &#9474;                        
        AD0 &#61615;&#9472;&#9472;&#9472;&#9496; &#9474; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;                        
                  &#61464;                                    
                 GND
     
    === LED Bar Graph Pin Connections ===
                                         
         P0 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9488;                 
         P1 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P2 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P3 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P4 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P5 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P6 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P7 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                             
         P8 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                                                                    
         P9 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
              220&#937;     &#9474;                 
                       &#9474;                 
                       &#61464;  GND             
     
    }}
    CON
      'let the compiler know which crystal and PLL settings to use
      _xinfreq = 5_000_000
      _clkmode = xtal1 + pll16x
      _leftServoPin = 14
      _rightServoPin = 9
      _timeStepInMilliseconds = 20
      _updateFrequencyInHertz = 50
      INPUT         = false         'bit pattern is all 0s
      OUTPUT        = true          'bit pattern is all 1s
      PC_BAUD       = 115_200       'PC serial terminal's baud rate
      
      ADC_CH0       = 1 << 0
      ADC_CH1       = 1 << 1
      ADC_CH2       = 1 << 2
      ADC_CH3       = 1 << 3
      ADC_ALL       = ADC_CH0 + ADC_CH1 + ADC_CH2 + ADC_CH3
      'LED Bar graph pin definitions
      BAR_GRAPH_0   = 0
      BAR_GRAPH_1   = 1
      BAR_GRAPH_2   = 2
      BAR_GRAPH_3   = 3
      BAR_GRAPH_4   = 4
      BAR_GRAPH_5   = 5
      BAR_GRAPH_6   = 6
      BAR_GRAPH_7   = 7
      BAR_GRAPH_8   = 8
      BAR_GRAPH_9   = 9
      Servo_Run     = 14
    OBJ
      adc    :     "PropBOE ADC"                           'Requires 1 cog
      pc     :     "Parallax Serial Terminal"              'Requires 1 cog
      system :     "Propeller Board of Education"          'PropBOE configuration tools
      time   :     "Timing"                                'Timekeeping and delay object
      servo  :     "PropBOE Servos"                        'Servo control object
      music  :     "WavPlayer2g"                          ' SD Card/Wave Plaer
    VAR
      'Globally accessible variables, shared by all cogs
      long pressure
      long cogStack[20]
      word cogStack2[20]       
                            
    
    PUB Go | rawReading
    
      'Start other objects
      pc.Start(PC_BAUD)
      adc.Start(ADC_CH0)
      
      'Launch additional cogs
      
      cognew(RunBarGraph, @cogStack)
      
      repeat
        rawReading := adc.In(0)                             'Get the reading from channel 0 on the ADC.
        pressure := rawReading / 25                         'Scale the raw reading to be displayed on the LED bar graph.
                                                            'Note that this scaled reading does not correspond with a particular
                                                            'unit of pressure such as mmH2O, mmHg, kPa, or PSI.  Check the sensor's
                                                            'datasheet (MPX5010DP) for the mV/mmH2O conversion value if you want an
                                                            'absolute reading in a particular unit of pressure.
                                                                                                       '
                                                            'The global variable "pressure" is shared between this cog and the cog
                                                            'that is controlling the LED bar graph.  
        '===== Print to the PC serial terminal =====
        pc.Home
        pc.Str(string("=== Pressure Sensor Test ==="))
        pc.NewLine
        pc.NewLine
        pc.Str(string("Raw ADC Value: "))
        pc.dec(rawReading)
        pc.Chars(" ", 5)
        pc.NewLine
        
          if rawReading >= 150                              ' Set rawReading accordingly to turn servo on 
           servo.Set(14, 200)
           servo.Set(15, -200)
            dira[11] := 1 
            outa[11] := 1                                ' Servo on pin 14 counterclockwise
          elseif rawReading <149                             ' Set rawReading accordingly to stop servo
           servo.stop                                        ' Stop servo
            dira[11] := 0 
            outa[11] := 0
           
           
               waitcnt(cnt + clkfreq/20)                     'wait for ~1/20th seconds so as not to flood the computer's serial port with data.
    
    PUB RunBarGraph | i
       
      dira[BAR_GRAPH_9..BAR_GRAPH_0] := OUTPUT              'set range of pins to output
                                                            '(this works in this case because the pins are consecutive)
                                        
      
      repeat
        outa[BAR_GRAPH_9..BAR_GRAPH_0] := 1<<pressure - 1   'Continually set the value of the scaled pressure to the LED bar graph pins.
                                                            'Do a little bitwise manipulation to make the LEDs look nice.
        
    PUB   
       music.PlayWav(string("chimes"))   'replace song with the file on the sd card you would like played. leave the quotes!
    DAT
     
    {{
    
  • ElectrodudeElectrodude Posts: 1,658
    edited 2013-04-06 14:09
    You said:
    PUB       
      music.PlayWav(string("chimes"))   'replace song with the file on the sd card you would like played. leave the quotes! 
    

    You have to name the PUB function!
    PUB Chimes
      music.PlayWav(string("chimes"))   'replace song with the file on the sd card you would like played. leave the quotes! 
    

    electrodude
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-06 14:36
    OK. I tried that but no sound is coming out. I know the file works because I played it in the actual wav file program. I even removed all the other code except what is needed for the wav file.
  • skylightskylight Posts: 1,915
    edited 2013-04-06 17:56
    Probably a silly question but did you make a call to the method "Chimes" from somewhere in your main program?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-06 18:38
    No, how do I do this?
  • skylightskylight Posts: 1,915
    edited 2013-04-08 01:46
    Sorry for taking so long to reply, I was busy working.
    NWCCTV wrote: »
    No, how do I do this?

    If your code looks like this now:

    PUB Chimes 
     music.PlayWav(string("chimes"))   'replace song with the file on the sd card you would like played. leave the quotes!
    

    Then in the part of your program you want the wav to play you just put a call to Chimes, ie just place the word "Chimes" without quotes there

    The PUB and PRI methods sit there waiting to do their code in your program and only execute their code when called by your program.
  • skylightskylight Posts: 1,915
    edited 2013-04-08 17:40
    Did you have any luck playing the wav file?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-08 17:56
    I can play the wav file from the original wav program but I can not get it to play when adding that program as an Object. The call to chimes is here
    PUB Chimes 
     music.PlayWav(string("chimes.wav"))
    
  • skylightskylight Posts: 1,915
    edited 2013-04-09 04:11
    NWCCTV wrote: »
    I can play the wav file from the original wav program but I can not get it to play when adding that program as an Object. The call to chimes is here
    PUB Chimes 
     music.PlayWav(string("chimes.wav"))
    

    What you are showing is the method to play the wav file, which directs to Rayman's Wav Player method but you have to call this first by putting the word chimes somewhere else in the program.

    The method PUB Chimes will not do anything until called.

    Can you show the whole code and the part of your program where you wish the wav to play and I can then show you how to call the Chimes method.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-18 16:05
    Here is the code I have. The chimes.wav for now is just prior to the runbargraph portion. However, I really need it to run along with the Servos in the If statement
    {{
    Pressure Sensor and BarGraph DEMO.spin
    Program Date: 1/4/2013
    Version:      1.1 Modified version to add the ability to turn a servo on and off at specified pressure.
    Description:
    This program reads voltage values from the Propeller BOE's ADC and prints the raw value to
    the Parallax Serial Terminal program running on your PC.  The program also uses a cog to
    show a linear representation of the pressure sensed on a 10-segment LED bar graph.
     
                               Propeller BOE Wiring Diagram
    
    === Pressure Sensor Pin Connections ===   
                                                       
                             +5v                       
                              &#61463;                        
                              &#9474;                        
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488; &#9474;                        
              &#9474;             &#9474; &#9474;                        
              &#9474;   MPX5010   &#9474; &#9474;                         
              &#9474;             &#9474; &#9474;                         
              &#9492;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9516;&#9472;&#9496; &#9474;                         
          Pin 1 &#9474; &#9474; &#9474; x x x   &#9474;                        
        AD0 &#61615;&#9472;&#9472;&#9472;&#9496; &#9474; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;                        
                  &#61464;                                    
                 GND
     
    === LED Bar Graph Pin Connections ===
                                         
         P0 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9488;                 
         P1 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P2 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P3 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P4 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P5 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P6 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
         P7 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                             
         P8 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                                                                    
         P9 &#61615;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#61606;&#61608;&#9472;&#9472;&#9515;                 
              220&#937;     &#9474;                 
                       &#9474;                 
                       &#61464;  GND             
     
    }}
    CON
      'let the compiler know which crystal and PLL settings to use
      _xinfreq = 5_000_000
      _clkmode = xtal1 + pll16x
      _leftServoPin = 14
      _rightServoPin = 9
      _timeStepInMilliseconds = 20
      _updateFrequencyInHertz = 50
      INPUT         = false         'bit pattern is all 0s
      OUTPUT        = true          'bit pattern is all 1s
      PC_BAUD       = 115_200       'PC serial terminal's baud rate
      
      ADC_CH0       = 1 << 0
      ADC_CH1       = 1 << 1
      ADC_CH2       = 1 << 2
      ADC_CH3       = 1 << 3
      ADC_ALL       = ADC_CH0 + ADC_CH1 + ADC_CH2 + ADC_CH3
      'LED Bar graph pin definitions
      BAR_GRAPH_0   = 0
      BAR_GRAPH_1   = 1
      BAR_GRAPH_2   = 2
      BAR_GRAPH_3   = 3
      BAR_GRAPH_4   = 4
      BAR_GRAPH_5   = 5
      BAR_GRAPH_6   = 6
      BAR_GRAPH_7   = 7
      BAR_GRAPH_8   = 8
      BAR_GRAPH_9   = 9
      Servo_Run     = 14
    OBJ
      adc    :     "PropBOE ADC"                           'Requires 1 cog
      pc     :     "Parallax Serial Terminal"              'Requires 1 cog
      system :     "Propeller Board of Education"          'PropBOE configuration tools
      time   :     "Timing"                                'Timekeeping and delay object
      servo  :     "PropBOE Servos"                        'Servo control object 
      music  :     "WavPlayer2g"                          ' SD Card/Wave Plaer
    VAR
      'Globally accessible variables, shared by all cogs
      long pressure
      long cogStack[20]
            
                            
    
    PUB Go | rawReading
      'Start other objects
      pc.Start(PC_BAUD)
      adc.Start(ADC_CH0)
      
      'Launch additional cogs
      
      cognew(RunBarGraph, @cogStack)
      
      repeat
        rawReading := adc.In(0)                             'Get the reading from channel 0 on the ADC.
        pressure := rawReading / 25                         'Scale the raw reading to be displayed on the LED bar graph.
                                                            'Note that this scaled reading does not correspond with a particular
                                                            'unit of pressure such as mmH2O, mmHg, kPa, or PSI.  Check the sensor's
                                                            'datasheet (MPX5010DP) for the mV/mmH2O conversion value if you want an
                                                            'absolute reading in a particular unit of pressure.
                                                                                                       '
                                                            'The global variable "pressure" is shared between this cog and the cog
                                                            'that is controlling the LED bar graph.  
        '===== Print to the PC serial terminal =====
        pc.Home
        pc.Str(string("=== Pressure Sensor Test ==="))
        pc.NewLine
        pc.NewLine
        pc.Str(string("Raw ADC Value: "))
        pc.dec(rawReading)
        pc.Chars(" ", 5)
        pc.NewLine
        
          if rawReading >= 150                              ' Set rawReading accordingly to turn servo on 
           servo.Set(14, 200)                                ' Servo on pin 14 counterclockwise
           servo.Set(15, -200)
           dira[11] :=1
           outa[11] :=1
          elseif rawReading <149                             ' Set rawReading accordingly to stop servo
           servo.stop
           servo.stop
           dira[11] :=0
           outa[11] :=0                                        ' Stop servo
           
           
          waitcnt(cnt + clkfreq/20)                     'wait for ~1/20th seconds so as not to flood the computer's serial port with data.
    PUB Chimes | Chimes
     music.PlayWav(string("Chimes.wav"))
               
    PUB RunBarGraph | i
       
      dira[BAR_GRAPH_9..BAR_GRAPH_0] := OUTPUT              'set range of pins to output
                                                            '(this works in this case because the pins are consecutive)
                                        
      
      repeat
        outa[BAR_GRAPH_9..BAR_GRAPH_0] := 1<<pressure - 1   'Continually set the value of the scaled pressure to the LED bar graph pins.
                                                            'Do a little bitwise manipulation to make the LEDs look nice.
        
    
    DAT
     
    {{
    
  • cavelambcavelamb Posts: 720
    edited 2013-04-18 23:00
    CON
    '
    ' first PUB encountered is considered to be the main program?                     
    '
    PUB Go | rawReading
      'Start other objects
      pc.Start(PC_BAUD)
      adc.Start(ADC_CH0)
      'Launch additional cogs
      cognew(RunBarGraph, @cogStack)
    '
    ' repeat forever - main loop of your program
    '
      repeat
        rawReading := adc.In(0)                             'Get the reading from channel 0 on the ADC.
        pressure := rawReading / 25                         'Scale the raw reading to be displayed on the LED bar graph.
        
          if rawReading >= 150                              ' Set rawReading accordingly to turn servo on 
           servo.Set(14, 200)                                ' Servo on pin 14 counterclockwise
           servo.Set(15, -200)
           dira[11] :=1
           outa[11] :=1
          elseif rawReading <149                             ' Set rawReading accordingly to stop servo
           servo.stop
           servo.stop
           dira[11] :=0
           outa[11] :=0                                        ' Stop servo
           
           
          waitcnt(cnt + clkfreq/20)                     'wait for ~1/20th seconds so as not to flood the computer's serial port with data.
    '      
    '         Execution stops right here.... loops back to the repeat
    '         It doesn't fall through to a Pub or PRI method.
    '         Chimes is never called.
    '     
          
    PUB Chimes | Chimes
     music.PlayWav(string("Chimes.wav"))
    
  • skylightskylight Posts: 1,915
    edited 2013-04-19 01:08
    NWCCTV wrote: »
    Here is the code I have. The chimes.wav for now is just prior to the runbargraph portion. However, I really need it to run along with the Servos in the If statement
        
          if rawReading >= 150                              ' Set rawReading accordingly to turn servo on 
           servo.Set(14, 200)                                ' Servo on pin 14 counterclockwise
           servo.Set(15, -200)
           dira[11] :=1
           outa[11] :=1
    
           Chimes   ' like this put the call here, although I don't have a way of testing this to see if the call affects the servos running 
    
          elseif rawReading <149                             ' Set rawReading accordingly to stop servo
           servo.stop
           servo.stop
           dira[11] :=0
           outa[11] :=0                                        ' Stop servo
           
           
          waitcnt(cnt + clkfreq/20)                     'wait for ~1/20th seconds so as not to flood the computer's serial port with data.
    PUB Chimes | Chimes
     music.PlayWav(string("Chimes.wav"))
               
    
    
    As Cavelamb says you have no call to Chimes, try the modification as listed above.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 13:56
    When compiling I get an error "Expected a unique subroutine name" for the Chimes after PUB
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 14:15
    You have "chimes" listed twice as a PUB name and it's local variable. Get rid of the " | chimes" in the Pub Chimes | Chimes statement.
  • skylightskylight Posts: 1,915
    edited 2013-04-19 14:17
    I was just about to post the same, was trying to find the strikethrough in the editor, can't see it in either the simple or advanced editor.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 14:33
    I tried that and it still does not work. In fact, although my servos turn as expected, they do not shut off when pressure is no longer applied and the chimes.wav file does not play.
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 14:41
    NW I don't know were you put the call to chimes and I do not know if the call for music.playwav returns right away or after the song completes? Show us your latest code.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 15:03
    OK, I got it to work. I had to modify the original wav program so as not to use the "fullduplexserial" file as my program uses the "Parallax Serial Terminal" file from the OBEX. Once I modified that code it worked. Thanks for the help all.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 15:23
    
    So on to my next issue!!!! I actually found a very much slimmed down wav player in the OBEX that is more suited to my needs. However, I am not sure how to get it to work. The program name is !WAV-Player Program. I placed that in the OBJ section of my program. The program calls another object and is named dac which is the command for playing the wav file from within that object. How do I go about calling the file that actually plays the wav file from the second OBJ that is being called from WAV-Player_DACEngine?
    
    WAV-Player Program
    //
    // Author: Kwabena W. Agyeman
    // Updated: 7/20/2011
    // Designed For: P8X32A
    // Version: 1.2
    //
    // Copyright (c) 2011 Kwabena W. Agyeman
    // See end of file for terms of use.
    //
    // Update History:
    //
    // v1.0 - Original release - 7/6/2011.
    // v1.1 - Tested with updated driver - 7/18/2011.
    // v1.2 - Added support for dither mode - 7/20/2011.
    //
    // Plays a WAV file over and over again at different sample rates. The WAV file is specified by its file path name string that
    // can be found in the code below. The WAV-Player program can play any standard WAV file. E.g. 16/8-Bit 16000/22050/44100-Hz.
    //
    // Nyamekye,
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    CON
      _clkmode = xtal1 + pll16x ' The clkfreq is 80MHz.
      _xinfreq = 5_000_000 ' Demo board compatible.
      _dopin = 22
      _clkpin = 23
      _dipin = 24
      _cspin = 25
      _cdpin = 4 ' -1 if unused.
      _wppin = 5 ' -1 if unused.
      _rtcres1 = -1 ' -1 always.
      _rtcres2 = -1 ' -1 always.
      _rtcres3 = -1 ' -1 always.
      _lpin = 26 ' -1 if unused.
      _rpin = 27 ' -1 if unused.
      _volume = 50 ' Default volume.
      _ditherEnable = true ' "true" or "false" please.
      _ditherLevel = 4 ' 0 = Most Dither ... 31 = Least Dither.
      
    OBJ dac: "WAV-Player_DACEngine"
    VAR long spinPlayerStack[100]
    PUB demo
      dac.FATEngineStart(_dopin, _clkpin, _dipin, _cspin, _wppin, _cdpin, _rtcres1, _rtcres2, _rtcres3)
      dac.DACEngineStart(constant(_lpin | (not(not(_ditherEnable)))), constant(_rpin | (not(not(_ditherEnable)))), _volume)
      ' Above Never fail - no need to check return value.    
      
      if(_ditherEnable)
        dac.DACDitherEngineStart(_lpin, _rpin, _ditherLevel) ' Never fails - no need to check return value.
      
      cognew(spinPlayer, @spinPlayerStack) ' Startup separate process.
      repeat ' Repeat forever.
        repeat until(dac.wavePlayerState) ' Wait until start.
        
        repeat until(dac.fileSamplePosition > (dac.fileSampleNumber / 3)) ' Wait until 1/3rds in.
        dac.fileSampleRateSetup((dac.fileSampleRate * 4) / 3) ' Sample rate set to 4/3rds the original.
        repeat until(dac.fileSamplePosition > ((dac.fileSampleNumber / 3) * 2)) ' Wait until 2/3rds in.
        dac.fileSampleRateSetup((dac.fileSampleRate * 3) / 4) ' Sample rate set to 3/4ths the original.
        repeat while(dac.wavePlayerState) ' Wait until stop. 
    PUB spinPlayer ' Plays a WAV file over and over again.
      'repeat ' Forever
        dac.playWAVFile(string("chimes.wav")) ' Supports WAV files up to ~2GB.
    {{
    
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 15:36
    I've never used Kye's object but I see you have inserted "chimes.wav". Can you post the "WAV-Player_DACEngine" file?

    EDIT: if that is Kye's demo file posted above it shows how to start it. Make sure the chimes.wav is in the folder his engine wants to see it in - probably the folder the engine is in.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 16:03
    Here it is. I will try placing it in the same folder to see what happens. However, I can play the file without doing this when I run it from the original wav program.CODE][/code]WAV-Player Digital to Analog Converter Engine
    //
    // Author: Kwabena W. Agyeman
    // Updated: 7/20/2011
    // Designed For: P8X32A
    // Version: 1.3
    //
    // Copyright (c) 2011 Kwabena W. Agyeman
    // See end of file for terms of use.
    //
    // Update History:
    //
    // v1.0 - Original release - 7/27/2010.
    // v1.1 - Merged object with player - 7/6/2011.
    // v1.2 - Fixed playback issue - 7/18/2011.
    // v1.3 - Added dither cog - 7/20/2011.
    //
    // For each included copy of this object only one spin interpreter should access it at a time.
    //
    // Nyamekye,
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Audio Circuit:
    //
    // 100OHM 1UF
    // Left Pin Number --R
    C-- Left Out (Use better audio circuit filtering for noise issues).
    // |
    // C 10NF
    // |
    // GND
    //
    // 100OHM 1UF
    // Right Pin Number --R
    C-- Right Out (Use better audio circuit filtering for noise issues).
    // |
    // C 10NF
    // |
    // GND
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    OBJ fat: "SD-MMC_FATEngine.spin"
    VAR
    long leftValue, rightValue, samplesPerSecond, clocksPerSample, numberOfSamples, samplePosition, ditherLeft, ditherRight
    word dataBlock[512], callerPointer, callePointer, leftVolume, rightVolume, numberOfChannels, bitsPerSample
    byte stopedOrStarted, beginOrEnd, cogIdentification, ditherCogIdentification
    PUB leftChannelOutput '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the current sample going out to the left audio channel. The value returned is a 16 bit signed extended number.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return leftValue
    PUB rightChannelOutput '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the current sample going out to the right audio channel. The value returned is a 16 bit signed extended number.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return rightValue
    PUB fileSampleRateSetup(sampleRate) '' 4 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Setups the sample rate of the audio file. The samples are played at the sample rate.
    '' //
    '' // SampleRate - The new sample rate to playback sample at. Between 1 - 66,150 samples per second.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    clocksPerSample := (clkfreq / ((sampleRate <# 66_150) #> 1))
    PUB fileSampleRate '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the sample rate of the audio file. The samples are played at the sample rate.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return samplesPerSecond
    PUB fileSampleNumber '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the number of samples in the audio file. The samples are played at the sample rate.
    '' //
    '' // Valid while method "wavePlayerState" returns true.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return numberOfSamples
    PUB fileSamplePosition '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the playback sample position in the audio file. The samples are played at the sample rate.
    '' //
    '' // Valid while method "wavePlayerState" returns true.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return (numberOfSamples - samplePosition)
    PUB leftChannelVolume(newVolume) '' 4 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Changes the volume of the left channel. (0 to 100).
    '' //
    '' // NewVolume - New volume to output at. Zero mutes the channel.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    leftVolume := (((newVolume <# 100) #> 0) * constant($1_00_00 / 100))
    PUB rightChannelVolume(newVolume) '' 4 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Changes the volume of the right channel. (0 to 100).
    '' //
    '' // NewVolume - New volume to output at. Zero mutes the channel.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    rightVolume := (((newVolume <# 100) #> 0) * constant($1_00_00 / 100))
    PUB pauseWavePlayer(state) '' 4 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Pause or unpause the wave player. The method "wavePlayerState" has nothing to do with the wave player being paused.
    '' //
    '' // State - New wave player state. True for paused and false for unpaused.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    stopedOrStarted := (not(not(state)))
    PUB wavePlayerState '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the wave player's state. True while playing a WAV file and false while not playing a WAV file.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    result or= beginOrEnd
    PUB playWAVFile(filePathName) '' 56 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Plays a WAV file on the SD/MMC card - supports WAV files up to ~2GB and over ~1 second of audio.
    '' //
    '' // The WAV player supports 8-Bit 1/2 channel WAV files sampled between 1 Hz to 44,100 Hz.
    '' //
    '' // The WAV player supports 16-Bit 1/2 channel WAV files sampled between 1 Hz to 44,100 Hz.
    '' //
    '' // If an error occurs while reading the WAV file a string describing that error will be returned. Null otherwise.
    '' //
    '' // If an error occurs while reading the FAT file system a string describing that error will be returned. Null otherwise.
    '' //
    '' // FilePathName - A file system path string specifying the path of the WAV file to play.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    result := \playWAV(filePathName)
    \fat.unmountPartition
    PRI playWAV(filePathName) | chunkSkip, blockAlign, byteRate, searchChunkSize ' 52 Stack Longs
    ifnot(fat.partitionMounted)
    fat.mountPartition(0)
    fat.openFile(filePathName, "R")
    if(fat.readLong <> $46_46_49_52)
    abort string("Not A RIFF File")
    if((fat.readLong + 8) <> fat.fileSize)
    abort string("RIFF Chunk Size Invalid")
    if(fat.readLong <> $45_56_41_57)
    abort string("Not A WAVE File")
    repeat while(fat.readLong <> $20_74_6D_66)
    searchChunkSize := fat.readLong
    if((searchChunkSize < 1) or (fat.fileSize == fat.fileTell))
    abort string("FMT Chunk Missing")
    fat.fileSeek(searchChunkSize + fat.fileTell)
    chunkSkip := (fat.readLong - 16)
    if(chunkSkip < 0)
    abort string("FMT Chunk Size Invalid")
    if(fat.readShort <> 1)
    abort string("Not A LPCM file")
    numberOfChannels := fat.readShort
    if((numberOfChannels < 1) or (2 < numberOfChannels))
    abort string("Unsupported Number Of Channels")
    samplesPerSecond := fat.readLong
    if((samplesPerSecond < 1) or (44_100 < samplesPerSecond))
    abort string("Unsupported Samples Per Second")
    clocksPerSample := (clkfreq / samplesPerSecond)
    byteRate := fat.readLong
    blockAlign := fat.readShort
    if((blockAlign <> 1) and (blockAlign <> 2) and (blockAlign <> 4))
    abort string("Unsupported Block Align")
    if(byteRate <> (samplesPerSecond * blockAlign))
    abort string("Invalid Byte Rate")
    bitsPerSample := fat.readShort
    if((bitsPerSample <> 8) and (bitsPerSample <> 16))
    abort string("Unsupported Bits Per Sample")
    fat.fileSeek(chunkSkip + fat.fileTell)
    repeat while(fat.readLong <> $61_74_61_64)
    searchChunkSize := fat.readLong
    if((searchChunkSize < 1) or (fat.fileSize == fat.fileTell))
    abort string("DATA Chunk Missing")
    fat.fileSeek(searchChunkSize + fat.fileTell)
    numberOfSamples := (fat.readLong / blockAlign)
    callerPointer := callePointer
    repeat while(callerPointer == callePointer)
    fat.readData(@dataBlock[256 & callerPointer], 512)
    samplePosition := numberOfSamples
    repeat (((((numberOfSamples * blockAlign) + 511) / 512) - 1) #> 0)
    not callerPointer
    repeat while(callerPointer == callePointer)
    fat.readData(@dataBlock[256 & callerPointer], 512)
    PUB DACEngineStart(leftPinNumber, rightPinNumber, initialVolume) '' 9 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Starts up the DAC driver running on a cog.
    '' //
    '' // Returns true on success or false.
    '' //
    '' // LeftPinNumber - Pin to use to play the left channel audio. -1 to disable.
    '' // RightPinNumber - Pin to use to play the right channel audio. -1 to disable.
    '' // InitialVolume - Initial volume for the left and right audio channels. Between 0 and 100. 0 mutes.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    DACEngineStop
    if(chipver == 1)
    clocksPerSample := clkfreq
    rightVolume := leftVolume := (((initialVolume <# 100) #> 0) * constant($1_00_00 / 100))
    leftCounterSetup := ((leftPinNumber & $1F) + constant(110 << 26))
    rightCounterSetup := ((rightPinNumber & $1F) + constant(110 << 26))
    outputMask := (((leftPinNumber <> -1) & (|<leftPinNumber)) | ((rightPinNumber <> -1) & (|<rightPinNumber)))
    leftValueAddress := @leftValue
    rightValueAddress := @rightValue
    samplePositionAddress := @samplePosition
    dataBlockAddress := @dataBlock
    callePointerAddress := @callePointer
    numberOfChannelsAddress := @numberOfChannels
    bitsPerSampleAddress := @bitsPerSample
    leftVolumeAddress := @leftVolume
    rightVolumeAddress := @rightVolume
    stopedOrStartedAddress := @stopedOrStarted
    beginOrEndAddress := @beginOrEnd
    ditherOutLeftAddress := @ditherLeft
    ditherOutRightAddress := @ditherRight

    cogIdentification := cognew(@initialization, @clocksPerSample)
    result or= ++cogIdentification
    PUB DACEngineStop '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Shuts down the DAC driver running on a cog.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    if(cogIdentification)
    cogstop(-1 + cogIdentification~)
    PUB DACDitherEngineStart(leftPinNumber, rightPinNumber, ditherLevel) '' 9 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Starts up the DAC dither driver running on a cog.
    '' //
    '' // The "DACEngineStart" method starts the regular non-dithering audio driver. If the audio quality is acceptable using it
    '' // then the special dithering audio driver is not needed. If the audio quality is not acceptable then use the dither engine
    '' // to eliminate both quantization noise from delta-modulation and pico-second jitter noise from on-chip crosstalk between
    '' // nearby pins. Normally, these two noise sources generate distracting buzzes, whines, and hash, but dithering removes them
    '' // in exchange for lower-level white noise which does not draw attention. The dither level can be adjusted - the further
    '' // you get from COG0, the more dither you need. The special dither audio driver will use another cog in addition to the
    '' // cog used by the regular non-dithering audio driver. Both audio drivers can output to different audio pins to produce
    '' // a dithered audio source and non-dithered audio source. To produce only a dithered audio source disable the left and
    '' // right audio channel pins in the regular non-dithering audio driver by passing -1 as the left and right pin numbers. If
    '' // only a non-dithered audio source is required do not call the "DACDitherEngineStart" method - this saves a cog.
    '' //
    '' // Returns true on success or false.
    '' //
    '' // LeftPinNumber - Pin to use to play the left channel audio. -1 to disable.
    '' // RightPinNumber - Pin to use to play the right channel audio. -1 to disable.
    '' // DitherLevel - Dither level for the left and right audio channels. 0 = Most Dither ... 31 = Least Dither.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    DACDitherEngineStop
    if(chipver == 1)
    ditherLeftCounterSetup := ((leftPinNumber & $1F) + constant(110 << 26))
    ditherRightCounterSetup := ((rightPinNumber & $1F) + constant(110 << 26))
    ditherOutputMask := (((leftPinNumber <> -1) & (|<leftPinNumber)) | ((rightPinNumber <> -1) & (|<rightPinNumber)))
    leftDitherShift := rightDitherShift := (ditherLevel & $1F)

    ditherLeftAddress := @ditherLeft
    ditherRightAddress := @ditherRight
    ditherCogIdentification := cognew(@ditherInitialization, 0)
    result or= ++ditherCogIdentification

    PUB DACDitherEngineStop '' 3 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Shuts down the DAC dither driver running on a cog.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    if(ditherCogIdentification)
    cogstop(-1 + ditherCogIdentification~)

    PUB FATEngineStart(DOPin, CLKPin, DIPin, CSPin, WPPin, CDPin, RTCReserved1, RTCReserved2, RTCReserved3) '' 18 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Starts up the SDC driver running on a cog and checks out a lock for the driver.
    '' //
    '' // This method should only be called once for any number of included versions of this object.
    '' //
    '' // This method causes all included versions of this object to need re-mounting when called.
    '' //
    '' // Returns true on success or false.
    '' //
    '' // DOPin - The SPI data out pin from the SD card. Between 0 and 31.
    '' // CLKPin - The SPI clock pin from the SD card. Between 0 and 31.
    '' // DIPin - The SPI data in pin from the SD card. Between 0 and 31.
    '' // CSPin - The SPI chip select pin from the SD card. Between 0 and 31.
    '' // WPPin - The SPI write protect pin from the SD card holder. Between 0 and 31. -1 if not installed.
    '' // CDPin - The SPI write protect pin from the SD card holder. Between 0 and 31. -1 if not installed.
    '' // RTCReserved1 - Reserved parameter 1 for RTC compatible driver versions. Pass -1.
    '' // RTCReserved2 - Reserved parameter 2 for RTC compatible driver versions. Pass -1.
    '' // RTCReserved3 - Reserved parameter 3 for RTC compatible driver versions. Pass -1.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    return fat.FATEngineStart(DOPin, CLKPin, DIPin, CSPin, WPPin, CDPin, RTCReserved1, RTCReserved2, RTCReserved3)
    PUB FATEngineStop '' 6 Stack Longs
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Shuts down the SDC driver running on a cog and returns the lock used by the driver.
    '' //
    '' // This method should only be called once for any number of included versions of this object.
    '' //
    '' // This method causes all included versions of this object to need re-mounting when called.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    fat.FATEngineStop
    DAT
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' DAC Driver
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    org 0
    ' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
    initialization mov ctra, leftCounterSetup ' Setup counter modes to duty cycle mode.
    mov ctrb, rightCounterSetup '
    mov frqa, longAdjust '
    mov frqb, longAdjust '
    mov dira, outputMask '
    mov playerPointer, dataBlockAddress '
    rdlong timeCounter, par ' Setup timing.
    add timeCounter, cnt '
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' Player
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    outerLoop rdlong buffer, samplePositionAddress wz ' Enable playback playback given samples.
    muxnz playerMode, #4 '

    rdword buffer, numberOfChannelsAddress ' Setup number of channels.
    cmp buffer, #1 wz '
    muxz playerMode, #1 '
    rdword buffer, bitsPerSampleAddress ' Setup bits per channel.
    cmp buffer, #8 wz '
    muxz playerMode, #2 '
    mov counter, #128 ' Setup loop counter.
    test playerMode, #1 wc '
    if_c shl counter, #1 '
    test playerMode, #2 wc '
    if_c shl counter, #1 '
    ' //////////////////////Inner Loop/////////////////////////////////////////////////////////////////////////////////////////////
    innerLoop rdlong buffer, par ' Wait until next sample output period.
    waitcnt timeCounter, buffer '
    rdbyte buffer, stopedOrStartedAddress wz ' If stopped loop continously.
    if_nz mov frqa, longAdjust '
    if_nz mov frqb, longAdjust '
    if_nz jmp #innerLoop '
    movs signedLongOutput, #leftValueAddress ' Get and output value.
    movs multiplicand, #leftVolumeAddress '
    movs unsignedLongOutput, #ditherOutLeftAddress '
    call #decode '
    mov frqa, sampleBuffer '
    test playerMode, #1 wc ' Check number of channels.
    test playerMode, #2 wz '
    if_c_and_nz sub playerPointer, #1 '
    if_c_and_z sub playerPointer, #2 '
    movs signedLongOutput, #rightValueAddress ' Get and output value.
    movs multiplicand, #rightVolumeAddress '
    movs unsignedLongOutput, #ditherOutRightAddress '
    call #decode '
    mov frqb, sampleBuffer '
    rdlong buffer, samplePositionAddress ' Decrement position.
    cmpsub buffer, #1 wc, wz '
    if_c wrlong buffer, samplePositionAddress '
    if_z andn playerMode, #4 ' Disable playback given samples.
    test playerMode, #4 wc ' Playback begun.
    if_c mov buffer, #$FF '
    if_c_and_nz wrbyte buffer, beginOrEndAddress '
    if_z wrbyte buffer, beginOrEndAddress ' Playback be done.

    djnz counter, #innerLoop ' Loop.
    ' //////////////////////Outer Loop/////////////////////////////////////////////////////////////////////////////////////////////
    rdword buffer, callePointerAddress wz ' Switch data block pointer.
    sumz buffer, #1 '
    wrword buffer, callePointerAddress '
    if_nz mov playerPointer, dataBlockAddress '
    jmp #outerLoop ' Loop.
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' Decode Value
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    decode test playerMode, #2 wc ' Read data depending on size.
    if_c rdbyte multiplyBuffer, playerPointer ' Read a byte or a word.
    if_c add playerPointer, #1 '
    if_nc rdword multiplyBuffer, playerPointer '
    if_nc add playerPointer, #2 '
    if_c sub multiplyBuffer, #128 ' Sign extend.
    if_c shl multiplyBuffer, #24 '
    if_nc shl multiplyBuffer, #16 '
    sar multiplyBuffer, #16 '
    test playerMode, #4 wz ' Zero playback given samples.
    if_z mov multiplyBuffer, #0 '

    signedLongOutput wrlong multiplyBuffer, 0 ' Update main memory.
    multiplicand rdword multiplyCounter, 0 ' Setup inputs.
    mov sampleBuffer, #0 '
    abs multiplyBuffer, multiplyBuffer wc ' Backup sign.
    rcr sampleBuffer, #1 wz, nr '
    multiplyLoop shr multiplyCounter, #1 wc ' Preform multiplication.
    if_c add sampleBuffer, multiplyBuffer '
    shl multiplyBuffer, #1 '
    tjnz multiplyCounter, #multiplyLoop '
    negnz sampleBuffer, sampleBuffer ' Restore sign and center value.
    unsignedLongOutput wrlong sampleBuffer, 0 '
    add sampleBuffer, longAdjust '
    decode_ret ret ' Return.
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    longAdjust long $80_00_00_00 ' Centers output.
    ' //////////////////////Configuration Settings/////////////////////////////////////////////////////////////////////////////////
    leftCounterSetup long 0
    rightCounterSetup long 0
    outputMask long 0
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    leftValueAddress long 0
    rightValueAddress long 0
    samplePositionAddress long 0
    dataBlockAddress long 0
    callePointerAddress long 0
    numberOfChannelsAddress long 0
    bitsPerSampleAddress long 0
    leftVolumeAddress long 0
    rightVolumeAddress long 0
    stopedOrStartedAddress long 0
    beginOrEndAddress long 0
    ditherOutLeftAddress long 0
    ditherOutRightAddress long 0
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    buffer res 1
    counter res 1
    playerPointer res 1
    playerMode res 1
    sampleBuffer res 1
    timeCounter res 1
    multiplyBuffer res 1
    multiplyCounter res 1
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    fit 496
    DAT
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' DAC Dither Driver
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    org 0
    ' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
    ditherInitialization mov ctra, ditherLeftCounterSetup ' Setup counter modes to duty cycle mode.
    mov ctrb, ditherRightCounterSetup '
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' Dither
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ditherLoop test leftLFSR, leftTaps wc ' Iterate left dither source
    rcl leftLFSR, #1 '
    test rightLFSR, rightTaps wc ' Iterate right dither source
    rcl rightLFSR, #1 '
    rdlong ditherLBuffer, ditherLeftAddress ' Read left source and shift dither.
    mov ditherLCounter, leftLFSR '
    sar ditherLCounter, leftDitherShift '
    rdlong ditherRBuffer, ditherRightAddress ' Read right source and shift dither.
    mov ditherRCounter, rightLFSR '
    sar ditherRCounter, rightDitherShift '
    add ditherLBuffer, ditherLCounter ' Apply dither.
    add ditherLBuffer, ditherAdjust '

    mov frqa, ditherLBuffer ' Output.

    add ditherRBuffer, ditherRCounter ' Apply dither.
    add ditherRBuffer, ditherAdjust '

    mov frqb, ditherRBuffer ' Output.
    mov dira, ditherOutputMask ' Repeat.
    jmp #ditherLoop '

    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ditherAdjust long $80_00_00_00 ' Prevents poping.
    leftTaps long $A4_00_00_80 ' Left LFSR taps.
    rightTaps long $80_A0_10_00 ' Right LFSR taps.
    leftLFSR long 1 ' Initial value.
    rightLFSR long 1 ' Initial value.
    ' //////////////////////Configuration Settings/////////////////////////////////////////////////////////////////////////////////
    ditherLeftCounterSetup long 0
    ditherRightCounterSetup long 0
    ditherOutputMask long 0
    leftDitherShift long 0
    rightDitherShift long 0
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    ditherLeftAddress long 0
    ditherRightAddress long 0
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    ditherLBuffer res 1
    ditherLCounter res 1
    ditherRBuffer res 1
    ditherRCounter res 1
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    fit 496
    {{
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 16:05
    Can you attach it as a file?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 16:09
    I will do that. However, When I placed the chimes.wav in the same directory it did not make a difference. I am getting the error "Expected a subroutine name" at this entry: playWAVFile
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 16:42
    Can you also attach your chimes.wav file? I will play with this later tonight and see if I can play your wav file with Kye's engine.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 16:48
    Yes, The chimes.wav file does play in Kye's engine. It is the chimes.wav file that is on any Windows system. I am using it just as a test until I get everything to work the way I need it to.
  • ratronicratronic Posts: 1,451
    edited 2013-04-19 17:03
    Try this line with the proper numbers for your pins for lpin and rpin, near the beginning of your code -
    dac.DACEngineStart(_lpin, _rpin, 100)
    

    and place this were ever you decided to play chimes -
    dac.playWAVFile(string("chimes.wav"))
    
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-04-19 17:13
    lpin and rpin are for the speakers, correct? so dac.DACEngineStart(_25, _26, 100) or do I leave the underscore out also?
Sign In or Register to comment.