rserota / wad

Web Audio DAW. Use the Web Audio API for dynamic sound synthesis. It's like jQuery for your ears.
MIT License
1.9k stars 159 forks source link

Created a SoundIterator Object #112

Closed frastlin closed 5 years ago

frastlin commented 5 years ago

I added one file: src/sound_iterator.js

I also added the tests to the bottom of the html file. I updated webpack because it wouldn't run on my machine with the old version, but I'm not exactly sure how to remove that from the PR.

rserota commented 5 years ago

Hey, thanks for submitting this PR. I haven't had much time to test it yet, but it looks good so far. My only thought at the moment, is that it seems like another way to group multiple wads together, but polywads already sort of do that. Do you think it would be feasible to adapt the polywad interface to do what you need to do? If the similarities between polywads and sound iterators are only superficial, then it might just make things more complicated to combine them, but in general I like Wad to have few, flexible functions, rather than a tool for every occasion.

frastlin commented 5 years ago

PolyWads are meant to have wads playing together. This is meant to have wads playing one after another. This could be used if you wanted to group polywads together in an arpeggio that was either random or always in the same order. The tests demonstrate the full functionality pretty well:

var iterator = new Wad.SoundIterator({files: [
    new Wad({source: 'sawtooth', volume: 0.5, env:{hold:1}}),
    new Wad({source: 'square', volume: 0.5, env:{hold:1}}),
    new Wad({source: 'sine', volume: 0.5, env:{hold:1}}),
]})

// repeated calls to play will repeat the sounds over and over again in the same order they were added
document.getElementById('play-next-nonrandom-sound').addEventListener('click', function(){
    iterator.random = false
    iterator.play()
})

document.getElementById('play-next-random-sound').addEventListener('click', function(){
    iterator.random = true
    iterator.randomPlaysBeforeRepeat = 0
    iterator.play()
})

document.getElementById('play-next-sound-with-1-randomPlaysBeforeRepeat').addEventListener('click', function(){
    iterator.random = true
    iterator.randomPlaysBeforeRepeat = 1
    iterator.play()
})

var newSound = new Wad({source:'triangle', volume: 0.5, env:{hold:1}})

document.getElementById('add-sound').addEventListener('click', function(){
    iterator.add(newSound)
})

document.getElementById('remove-sound').addEventListener('click', function(){
    iterator.remove(newSound)
})
frastlin commented 5 years ago

This is very much a utility class, and the times I've thought when it would be useful are:

With a little more code, it could run a song comprised of Wad objects, but currently the timing functionality is not there, just the ordering.

It's really just an iterator that removes the boilerplate from the above functions. I use it in most of my projects.

rserota commented 5 years ago

This looks great, thanks for contributing!

You briefly mentioned some timing functionality that could be useful? How are you imagining that would work? I've actually been thinking about adding timing features to Wad.

frastlin commented 5 years ago

How I would do it is: Create a set of notes using an oscillator with an env:hold duration for the duration of the notes. Then create a silence oscillator with an env: hold duration for rests. Then you can just attach sounds and silent oscillators to make a set of notes, then there could be a function to play the sounds in order until they are done.

This would require:

Then there could be syntactic sugar for adding notes, like having an oscillator Wad object, and pass it into a createSequence method on the SoundIterator object that has the arguments: oscillator, text music notation. The text music notation could be a string of either ABC notation, LilyPond notation, or a custom notation system, or all of the above. The parser will just add notes and rests to the SoundIterator that are based off the passed oscillator or polyWad.