I am trying to build a sequencer using Tone.js. Right now, it is a simple sequence that is being played after the user clicks the play button. I can get it to play fine after first pressing it, but after the button is pressed again to pause, then pressed again to play, notes will randomly click or not be played in time or played at a lower volume.
My initial problem was creating multiple synths at once which caused this synths to all play the same notes at once. I was able to fix that problem, but now I can't get the sequence to play consistently. Can someone please take a look at my repo? https://github.com/cjacqo/sequencer
NOTES:
The problem is the Controls.js file (sequencer > src > components > controls > Controls.js)
The play button is both the 'play' and 'pause' button at the moment
const Controls = () => {
const [started, setIsStarted] = useState(false)
const [isPlaying, setIsPlaying] = useState(false)
const [tempo, setTempo] = useTempoHook('100')
const [subDivision, setSubDivision] = useSubDivisionHook('1/4')
const [sequence, setSequence] = useState(false)
useEffect(() => {
console.log('Is Playing: ', isPlaying)
console.log('Tempo: ', tempo)
console.log('SubDivision: ', subDivision)
})
Tone.Transport.bpm.value = tempo
const createSequence = () => {
const synth = new Tone.Synth().toDestination()
const sequence = new Tone.Sequence((time, note) => {
// console.log(time)
synth.triggerAttackRelease(note, 0.1, time)
}, ['C3', 'D3', 'E3', 'F3'], '4n')
sequence.start(0)
return sequence
}
const startTone = async () => {
await Tone.start()
setIsStarted(true)
}
const stopSequence = () => {
Tone.Transport.stop()
sequence.stop()
sequence.dispose()
setIsPlaying(false)
}
const startSequence = () => {
Tone.Transport.start()
setSequence(createSequence())
setIsPlaying(true)
}
const start = () => {
if (Tone.Transport.state === 'started') {
stopSequence()
} else {
startSequence()
}
console.log(Tone.Transport.state)
}
const stop = () => {
// setIsPlaying(false)
}
return (
<div>
{ !started && <ButtonControl icon={'Start'} color={'blue'} handler={startTone} /> }
<AudioPlayBackManager playAudio={start} stopAudio={stop} />
<TempoSliderControl tempo={tempo} setTempo={setTempo} />
<SubDivisionControl setSubDivision={setSubDivision} />
</div>
)
}
I solved the problem. Within the Tone.Sequence, there is a line for the synth triggerAttackRelease. The problem was the second param (duration the note is held) was set to 0.1. Occasionally, an error would occur that would say, "Start time must be strictly greater than previous start time". To fix this, I changed that 0.1 value to a note length value such as 4n, 8n, and so on.