Shop OBEX P1 Docs P2 Docs Learn Events
Piano Delayed Mute Problem — Parallax Forums

Piano Delayed Mute Problem

SciNemoSciNemo Posts: 91
edited 2010-01-17 22:39 in Propeller 1
I am working on a synthesizer project that uses a PS2 keyboard and the comboKeyboard object. I am having trouble coming up with a method so that when you press a key the note is played, but it dies out after a while. I could do it so that the propeller just loops for a delay and then turns off the note, but that does not allow another note to cut off the first note.

My attempt uses a timer that is set when a key is pressed and then decremented until it is at zero, at which point the sound is turned off. For some reason instead of the sound turning off after a delay it just remains on, although it is not stuck in an infinite loop, as I can hit other keys and it switches to that note.

Here is my code:

  timer := 0
  
  repeat    
    keyval := key.getkey
    key.clearkeys 

    repeat i from 0 to 32
      if keyOrder[i]==keyval
        note := (i+1)*3+1
        timer := 500
     
    if timer>0
      noteOn(1, note)
      timer--
    else
      noteOff(1)
      timer := 0    

DAT

keyOrder byte "z","a","q","x","s","w","c","d","e","v","f","r","b","g","t","n","h","y","m","j","u",",","k","i",".","l","o","/",";","p","'","[noparse][[/noparse]","]"

[/i]

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Not the fish.
sites.google.com/site/bitwinproject/

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-17 20:41
    If key.getkey blocks until a key is pressed, you will see the behavior you report. To avoid this, you will need to check first that a key was pressed, then call getkey.

    BTW, you can avoid the problem with [noparse][[/noparse]i] disappearing and changing everything after it to italics by using my code formatter at www.phipi.com/format.

    -Phil
  • SciNemoSciNemo Posts: 91
    edited 2010-01-17 21:16
    My code is now:

      timer := 0 
      
      [b]repeat[/b]
        [b]if[/b] key.key>0   
          keyval := key.getkey
          key.clearkeys 
    
        [b]repeat[/b] i [b]from[/b] 0 to 32
          [b]if[/b] keyOrder[noparse][[/noparse]­i]==keyval
            note := (i+1)*3+1
            timer := 50
         
        [b]if[/b] timer>0                                  
          noteOn(2, note)
          timer--       
        [b]else[/b]
          noteOff(2)                    
          timer := 0
    
    
    



    (thanks for the link to that nifty code formatter)
    It still does not work. If I am right then this code now checks for a keypress before calling getkey like you recommend, but the note still hangs indefinitely. Am I right in saying that the timer variable is not decrementing? How can that be so when I know that the code under "if timer>0" is being called (because I can still change the note by pressing another key)?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Not the fish.
    sites.google.com/site/bitwinproject/
  • KyeKye Posts: 2,200
    edited 2010-01-17 21:36
    Use a second cog that basically plays every note for you and manages a counter for each note.

    The cog would just go through an array decrementing a bunch of variables and map the volume of the variable to the value currently its decrementing.

    When the value its decrementing equals zero it turns the note off.

    Then the cog that is getting the notes can just put change the value of the next note played back to 1000 or something and then get the next note.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-17 21:49
    You're still getting hung up with getkey. The reason is that key extracts the key value from the buffer, and when getkey is called, there's nothing there, so it hangs, waiting for another keypress. Try this:

      if (keyval := key.getkey)
        repeat from 0 to 32
          ...
      if (timer)
        ...
    
    
    


    -Phil
  • SciNemoSciNemo Posts: 91
    edited 2010-01-17 21:57
    I've changed my code to this, which (I'm pretty sure) is what you meant for me to try. I think I know what you are saying now, but for some reason the darn thing is still hanging. Somehow "timer--" is getting executed once and not being run again at all. I'm assuming it gets executed once because noteOn() gets called and I hear the note played.

      timer := 0 
      
      [b]repeat[/b] 
        [b]if[/b] (keyval := key.getkey)
          [b]repeat[/b] i [b]from[/b] 0 to 32
            [b]if[/b] keyOrder[noparse][[/noparse]*i]==keyval
              note := (i+1)*3+1
              timer := 50
         
        [b]if[/b] timer>0                                  
          noteOn(2, note)
          timer--       
        [b]else[/b]
          noteOff(2)                    
          timer := 0
    
    
    



    ..And kye, thanks for that method. I'll attempt it if I can't get this Spin code sorted out, but my PASM skills are very weak and I don't know the exact way I would go about accomplishing that.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Not the fish.
    sites.google.com/site/bitwinproject/
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-17 22:03
    Sorry, I screwed up. It was supposed to be:

        if (keyval := key.key)
          ...
    
    
    


    -Phil
  • kwinnkwinn Posts: 8,697
    edited 2010-01-17 22:12
    Shouldn't the "if timer>0 " block be indented to be in the "repeat i from 0 to 32" loop?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-17 22:16
    kwinn,

    No. Then it would only get executed when a new key is pressed.

    -Phil
  • SciNemoSciNemo Posts: 91
    edited 2010-01-17 22:18
    EDIT EDIT:Phil is right (Kwin is wrong)

    All the "repeat i from 0 to 32" loop does is set note to a value that corresponds to the position of the key that has been pressed in the order that I have established in the keyOrder data section (shown in the code segment in my initial post). If the "if timer>0" block were in the "repeat i from 0 to 32" loop the noteOn() function would be called 33 times and only when a new key was pressed, which I don't want.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Not the fish.
    sites.google.com/site/bitwinproject/

    Post Edited (SciNemo) : 1/17/2010 10:57:49 PM GMT
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-17 22:26
    Just a note (so to speak): I don't know how noteOn is supposed to work, but I'm guessing you don't have to keep refreshing it. If that's the case, you can call it once when a new key is pressed, and your timer loop gets a lot simpler:

        if (--timer == 0)                                  
           noteOff(2)                    
    
    
    


    Also, at some point you will probably want to learn to use cnt for more accurate timing without having to rely on the Spin code overhead.

    Another optimization that will help is to use lookdown instead of your loop to find the value for i.

    -Phil

    Post Edited (Phil Pilgrim (PhiPi)) : 1/17/2010 10:31:31 PM GMT
  • kwinnkwinn Posts: 8,697
    edited 2010-01-17 22:39
    OK, (scratching head), that looks like it should work. Can you add Full Duplex Serial to the program and output to PST to see if NoteOn/NoteOff sections are executed?
Sign In or Register to comment.