Playing multiple sound files simultaneously.

I hope I’m asking this question in the right place, but here goes.

I’m working on a program that simulates an accordion. Yes, you heard right, a 21-button accordion. I have created music files by sampling the sounds produced on my accordion. They are short, 2-sec files, that I have created and uploaded to Dropbox for use in my program. The idea is that by pressing a button the music file that corresponds with that button will play. @Ignatz described a method of playing a music or sound file while pressing a button, and going silent once released. That advice greatly helped.

On an accordion I can play multiple notes simultaneously. My question is: Can I select multiple sound files and play them simultaneously if I press multiple buttons? My goal is to produce a blended sound similar to pressing multiple buttons on an accordion. I’m guessing it’s not possible but by asking the exports I can save myself some frustration.

I have searched this site but cannot find an answer. Any help is greatly appreciated.

@Scotty The quickest way would be to set up 2 buttons and listen if it plays your 2 sound files and if it sounds correct.

You can play multiple versions of the same sound simultaneously

-- Use this function to perform your initial setup
function setup()
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
end

function touched(t)
    
    if t.state==MOVING then
        sound("Game Sounds One:Female Cheer 1")
    end
end

@Scotty As @West shows, you can play multiple sound files, but will playing multiple sound files together blend correctly to give you the final sound you want. You’ll have to take the sound files you have and play some together to see if the resulting sound is what you want.

Thanks. Can’t wait to give this a shot.
I really appreciate this.

@West, @dave1707:
We’re getting close. I’ve modified the proposed solution to include what is to happen once touch has ended.

The first example works with multiple sound files but can’t be looped while pressing. Also I’m unable to stop sounds upon release.

The blended sounds play well together (at leased as well as an accordion sounds LOL!)

The second example works but with only one music file at a time. Plus music plays as long as I am touching screen and stops once touch has ENDED. That solution was described by @Ignatz to another member’s question.

--[[
-- Plays both sounds listed opon touch (desired).
-- Also desired, the ability to loop as long as I am touching the screen.
-- But once touch has ENDED I want the both sounds to stop.
function touched(t)
    if t.state==BEGAN then  -- plays both files
        -- two of my sampled 2-sec sounds
        sound("Dropbox:BC1PushC2")
        sound("Dropbox:TC1PullD5")
    elseif t.state==ENDED then  -- stop playing
        --music.stop() -- has no effect
        --sound.stop() -- or generates an error
    end
end
--]]

--[[
-- This works for only one file.
function touched(t)
    if t.state==BEGAN then 
        music("Dropbox:TC1PullD5",true) -- my sampled 2-sec music file.
    elseif t.state==ENDED then
        music.stop()
    end
end
--]]

I really hopes this helps. And, again, I appreciate the help.

@Scotty Here’s something I set up with just 2 keys. Pressing each one plays a sound, and releasing each one stops the sound. You’ll have to try these with your sound files. You can set up as many keys as you want.

function setup()
    keys={}
    table.insert(keys,key(100,100,"Game Sounds One:Wind 2"))
    table.insert(keys,key(200,100,"Game Sounds One:Crowd Boo"))
end

function draw()
    background(40, 40, 50)
    for a,b in pairs(keys) do
        b:draw()
    end
end

function touched(t)
    for a,b in pairs(keys) do
        b:touched(t)
    end
end

key=class()

function key:init(x,y,s)
    self.x=x
    self.y=y
    self.w=50
    self.h=100
    self.k=nil 
    self.s=s  
    self.id=nil 
end

function key:draw()
    fill(255)
    rect(self.x,self.y,50,100)
end

function key:touched(t)
    if t.x>self.x and t.x<self.x+self.w and t.y>self.y and t.y<self.y+self.h then
        self.id=t.id
        if t.state==BEGAN then
            self.k=sound(self.s,1,1,1,true)
        end
        if t.state==ENDED then
            self.k:stop()
        end
    elseif t.state==ENDED and t.id==self.id then
        self.k:stop()
    end
end

Thank you very much @dave1707. Your example works great as is. It works great with my sampled sounds substituted in and it, most importantly, works great in my project. Any multiple key presses on my accordion that sound well together sounds nice in my program.

There are two more issues I need to chase down but I before I ask those questions of you I want to try and tackle them myself. One is related to the the above problem while the other relates to the fact that I am dealing with thirty buttons in this program. Each button can produce two tones. One for expanding or pulling the other for compressing or pushing on the accordion. That’s a lot of variable definitions to keep track of. I’m glad I didn’t buy a piano-style accordion.

Once I solve that problem I may be able to get my setup() function to be less that 850 lines long. I’m using tables to hold my button objects once creaded so I think I need to use tables to hold the variables used to create them. Similar to your example above.

Thanks again for your help. I really appreciate it.

@Scotty Glad to hear its a good start for what you need. Also glad that you are trying to figure things out for yourself rather than just asking for an answer. The more you try to figure out youself, the more you’ll learn and won’t rely on others for help. But if you do run into problems, don’t hesitate to ask. That’s the whole purpose of this forum.

Thank you, @dave1707.

@dave1707, this is how things stand right now.

I’ve modified the example you have generously provided by adding extra keys. I’ve also added the ability to simulate what would happen when the iPad is tilted. So now there are four keys in one direction and four keys in the other direction.

When the right side of the iPad is tilted up the red set of keys are available. When the left side is tilted up the green set are available. Gravity.x +/- is used to govern which keys are displayed. I use color to keep track of what’s going on.

You can press and release or press and hold any combination all you want and the blended sound is pleasing. The problem I’m dealing with is when I press AND hold a key WHILE tilting from left to right or from right to left the sound gets locked in and will not stop. Like pushing and pulling on an accordion’s bellows while holding a button changes the sound produced, I want to be able to accomplish this through tilting the iPad.

My goal is that when I press AND hold a red key, for instance, while in one iPad orientation the corresponding green key should replace that sound as the iPad is tilted into the new orientation. When the key is released the sound stops.

I’ve added a text statement to label each key’s touch.id and it seems clear that I’m loosing the original touch.id as I am tilting the iPad. Somehow I need to keep track of the original id so I can release the original sound when Gravity.x’s sense changes.

I hope this make sense and you can provide additional guidance.
(Side note: Is it correct to enclose the code that follows with ~~~ before and after to preserve formatting?)
Thank you very much.


supportedOrientations(PORTRAIT)
displayMode(FULLSCREEN)

function setup()
    -- key locs
    X1 = (WIDTH/5)
    X2 = (WIDTH/5)*2
    X3 = (WIDTH/5)*3
    X4 = (WIDTH/5)*4   
    Y = 200

    -- added extra keys (all sounds are 2sec in length)
    keysPush={}
    table.insert(keysPush,key(X1,Y,"Dropbox:TC1PushG3"))
    table.insert(keysPush,key(X2,Y,"Dropbox:TC1PushC4")) 
    table.insert(keysPush,key(X3,Y,"Dropbox:TC1PushE4"))
    table.insert(keysPush,key(X4,Y,"Dropbox:TC1PushG4")) 

    keysPull={}
    table.insert(keysPull,key(X1,Y,"Dropbox:TC1PullB3"))
    table.insert(keysPull,key(X2,Y,"Dropbox:TC1PullD4"))      
    table.insert(keysPull,key(X3,Y,"Dropbox:TC1PullF4"))
    table.insert(keysPull,key(X4,Y,"Dropbox:TC1PullA4"))      

end


function draw()
    background(40, 40, 50)
    fill(255, 255, 255, 255)
    fontSize(25)
    textMode(CENTER)

    fontSize(50)
    -- display keys based on iPad orientation
    if Gravity.x > 0 then
        text(string.format("Gravity.x = %.f: Push",Gravity.x),
            WIDTH/2,HEIGHT/2-25)
        for a,b in pairs(keysPush) do 
            fill(0, 255, 0, 255)        
            b:draw() 
        end
    elseif Gravity.x < -0 then
        text(string.format("Gravity.x = %.f: Pull",Gravity.x),
            WIDTH/2,HEIGHT/2-25)
        for a,b in pairs(keysPull) do
            fill(255, 0, 0, 255)      
            b:draw() 
        end
    end
end


function touched(t)    
    if Gravity.x > 0 then
        for a,b in pairs(keysPush) do
            b:touched(t)
        end
    elseif Gravity.x < 0 then
        for a,b in pairs(keysPull) do            
            b:touched(t)
        end
    end
end



key=class()

function key:init(x,y,s)
    self.x=x
    self.y=y
    self.rad= 35
    self.k=nil   -- this will hold address of sound()?
    self.s=s     -- sound to be played
    self.id=0
end


function key:draw()
    ellipseMode(RADIUS)
    strokeWidth(5)    
    ellipse(self.x,self.y,self.rad)
    stroke(255, 255, 255, 255)
    textMode(CENTER)
    fontSize(15)
    fill(255, 255, 255, 255)
    -- sound and touch id
    text(self.s,self.x,self.y-self.rad-25)
    text(self.id,self.x,self.y-self.rad-50)
end


function key:touched(t)
    if t.state==BEGAN then
        if vec2(t.x,t.y):dist(vec2(self.x,self.y)) <= self.rad then
            self.id=t.id
            self.k=sound(self.s,1,1,1,true)
        end
    elseif  t.state==ENDED and t.id==self.id then
        self.k:stop()
    end
end




@Scotty Since you like to solve you’re own problems, I’ll give you a suggestion. When you tilt the iPad, don’t lock out the keys totally. If a red key is held down when you tilt the iPad, set the corresponding green key value to play. You can prevent the pressing of the red keys, but still allow the checking for ending the touch of a red key. Instead of checking Gravity in the touched function, try checking it in the key:touched function for BEGAN. That way you can still check for ENDED.

Thanks, @dave1707. I’ll work on this and see what I come up with. I appreciate it.

@dave1707 , I’m still struggling with this problem but I feel I’m getting closer to my goal.

The way it stands now is that when I press and hold a key in one orientation the correct sound plays. As I tilt the iPad to the new orientation the original sound continues to play BUT at least it stops playing when I release the key. So the sound is not getting locked in as before. This is a step closer.

The sound that plays in one orientation needs to be replaced by a new sound as the iPad’s orientation changes (i.e. at the point when gravity.x changes from positive to negative or vise versa). This all has to happen while the key is pressed and held. If that can happen AND cease to play once key is released I think WE would have it solved.

When you write: “If a red key is held down when you tilt the iPad, set the corresponding green key value to play.” I’m not clear how to accomplish this AND not have it play at the wrong time.

One change I’ve made was to combine my two tables into one. That way, when I moved the testing of gravity.x from touched to key:touched (your suggestion), I could get away with accessing only a single table in the touched for loop and not have both sounds play. That was very beneficial.

I hope this is clear and once again, thank you for your continued guidance.

supportedOrientations(PORTRAIT)
displayMode(FULLSCREEN)

function setup()    
    
    -- key locs
    X1 = (WIDTH/5)
    X2 = (WIDTH/5)*2
    X3 = (WIDTH/5)*3
    X4 = (WIDTH/5)*4  
    Y = 200

--[[
Added extra keys
"keysPush" and "keysPull" table have been combined into one table.
--]]
    keysPushPull={}
    table.insert(keysPushPull,key(X1,Y,
        "Dropbox:TC1PushE4","Dropbox:TC1PullF4"))
    table.insert(keysPushPull,key(X2,Y,
        "Dropbox:TC1PushG4","Dropbox:TC1PullA4")) 
    table.insert(keysPushPull,key(X3,Y,
        "Dropbox:TC1PushC5","Dropbox:TC1PullB4"))                                            
    table.insert(keysPushPull,key(X4,Y,
        "Dropbox:TC1PushE5","Dropbox:TC1PullD5")) 

end



function draw()
    background(89, 89, 89, 255)
    fill(255, 255, 255, 255)
    fontSize(25)
    textMode(CENTER)   
    fontSize(40)
    
-- display keys based on iPad orientation.
    if Gravity.x > 0 then
        text(string.format("Gravity.x = %.f: Push",Gravity.x),
            WIDTH/2,HEIGHT/2-25)
        for a,b in pairs(keysPushPull) do 
            fill(0, 255, 0, 255)        
            b:draw() 
        end
    elseif Gravity.x < 0 then
        text(string.format("Gravity.x = %.f: Pull",Gravity.x),
            WIDTH/2,HEIGHT/2-25)
        for a,b in pairs(keysPushPull) do
            fill(255, 0, 0, 255)      
            b:draw() 
        end
    end              
end


function touched(t)
    for a,b in pairs(keysPushPull) do
        b:touched(t)
    end
end



key=class()

function key:init(x,y,sPush,sPull)
    self.x      = x
    self.y      = y
    self.sPush  = sPush
    self.sPull  = sPull

    self.id     =  0 
    self.rad    = 35    
    self.k      =  0   -- sound 
end


function key:draw()
    ellipseMode(RADIUS)
    strokeWidth(5)    
    ellipse(self.x,self.y,self.rad)
    stroke(255, 255, 255, 255)
    textMode(CENTER)
    fontSize(15)
    fill(255, 255, 255, 255)
    -- label each key with sound name and touch id 
    if Gravity.x > 0 then
        text(self.sPush, self.x,self.y-self.rad-25)
        text(self.id,    self.x,self.y-self.rad-50) 
    elseif Gravity.x < 0 then
        text(self.sPull, self.x,self.y-self.rad-25)
        text(self.id,    self.x,self.y-self.rad-50)
    end        
end


function key:touched(t)
    if t.state==BEGAN then
        if vec2(t.x,t.y):dist(vec2(self.x,self.y)) <= self.rad then 
            if Gravity.x > 0 then
                self.id=t.id
                self.k=sound(self.sPush,1,1,1,true)
            elseif Gravity.x < 0 then
                self.id=t.id                
                self.k=sound(self.sPull,1,1,1,true)
            end            
        end           
    elseif  t.state==ENDED and t.id==self.id then
        self.k:stop()
    end    
end

@Scotty When you’re pressing a key and you get a sound, and then you change orientation, is the same sound supposed to switch to the other key or is the other key supposed to play a different sound.

@Scotty

Your logic and code is fine for the above, but the issue is that the touched function when the screen is touched for the first time (or released). Tilting the screen does not visit the touched function.

To explore - try changing

if t.state==BEGAN then

to

if t.state==BEGAN or t.state==MOVING then

This will give you what you are after, but only if you are moving your finger on the button (the touch movement will trigger the touched function).

What you probably want to explore is using the touched function to create a table of currently active touches and cycle through them on on the main draw cycle. I’ll let you have a go at this (unless Dave or others can suggest a better approach) but let me know if you want further pointers - I’ve done similar with a touch tracker and the code should somewhere on this forum

@Scotty Here’s what I was thinking. The red key can be pushed when Gravity is negative and the green key pushed when Gravity is positive. The sound for any key stops when that key is released no matter what the value of Gravity. I don’t have access to your sound files, so I’m using the same Codea sound for both keys. I don’t know if you want both key sounds to play at the same time or not.

function setup()
    rectMode(CENTER)
    k1=key(100,100,-1,color(255,0,0),"Game Sounds One:Wind 2")
    k2=key(WIDTH-100,100,1,color(0,255,0),"Game Sounds One:Wind 2")
end

function draw()
    background(40, 40, 50)
    k1:draw()
    k2:draw()
end

function touched(t)
    k1:touched(t)
    k2:touched(t)
end

key=class()

function key:init(x,y,g,col,s)
    self.x=x
    self.y=y
    self.w=50
    self.h=50
    self.g=g    -- -1=key valid for gravity negative  1=key valid for gravity positive
    self.id=0   -- touch id
    self.c=col  -- key color
    self.s=s    -- sound to play for this key
    self.k=nil  -- sound thats playing
end

function key:draw()
    fill(self.c)
    rect(self.x,self.y,self.w,self.h)
end

function key:touched(t)
    if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
            t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
        if t.state==BEGAN then
            if Gravity.x<0 and self.g==-1 then    -- gravity negative and key negative
                self.id=t.id
                self.k=sound(self.s,1,1,1,true)
            elseif Gravity.x>0 and self.g==1 then    -- gravity positive and key positive
                self.id=t.id
                self.k=sound(self.s,1,1,1,true)
            end
        end
    end
    if t.state==ENDED and t.id==self.id then
        self.id=nil
        self.k:stop()        
    end
end

@dave1707, forgive me but I have yet to figure out how to share Dropbox sound files. I’m willing to share – just not smart enough to share. LOL!

In your example it appears you have TWO buttons, a red and a green. Make that be ONE button that can produce two different sounds, a high/low sound, and two different colors, red/green, depending on the iPad orientation. So, to keep this example as simple as possible: one button, two sounds and two colors.

In my example, I have four buttons. If a one-button can work I should be able to get multiple buttons to work. My goal is 29 buttons, like an accordion.

Thanks again for your help.

@West thanks for your suggestion. I’ve tried adding MOVING to the if condition but that just keep adding more sounds but not stopping them once the button is released.

As for your other suggestion, keeping track of active touches that is worth exploring.

Also I’m trying to figure out how to share Dropbox sound files, once I do that it should make my example make more sense.

Thank you very much.

@Scotty I guess I don’t know how an accordion actually works. So the buttons on the different sides of the accordion play different notes and depending on pulling or pushing the accordion, each button will play one of two notes assigned to it. If that’s the case, then as long as a button is pressed, it will switch between the two notes as the iPad is tilted until the button is released. If that’s the case, then I can modify my above code to handle that.