I am trying to make a small beatbox with tonejs and its sampler within a Vue3 typescript application.
It converts sequences of integers into drum patterns by first converting them to binary for polyphony.
You can see the whole code here:
And especially: .vue
It is even deployed here: /
I have previously written a small sequencer with a simple oscillator in a similar fashion and it works relatively well (/); this new beatbox app was even started as a copy of it. I wonder why I can't get the sampler to work in real time.
The download midi file functionality works as intended so the sequence of notes and velocities are correct until proven otherwise.
The mp3 samples for the beatbox seems to be loaded correctly.
But, on the call to triggerAttackRelease (there is only one in the code in the playStep method) I always get an InvalidStateError.
Could one of you sweethearts possibly help me debug this?
Have a nice day.
I am trying to make a small beatbox with tonejs and its sampler within a Vue3 typescript application.
It converts sequences of integers into drum patterns by first converting them to binary for polyphony.
You can see the whole code here: https://github/ncg777/super-beatbox-3000
And especially: https://github/ncg777/super-beatbox-3000/blob/main/src/App.vue
It is even deployed here: https://ncg777.github.io/super-beatbox-3000/
I have previously written a small sequencer with a simple oscillator in a similar fashion and it works relatively well (https://ncg777.github.io/super-sequencer-3000/); this new beatbox app was even started as a copy of it. I wonder why I can't get the sampler to work in real time.
The download midi file functionality works as intended so the sequence of notes and velocities are correct until proven otherwise.
The mp3 samples for the beatbox seems to be loaded correctly.
But, on the call to triggerAttackRelease (there is only one in the code in the playStep method) I always get an InvalidStateError.
Could one of you sweethearts possibly help me debug this?
Have a nice day.
Share Improve this question edited 2 days ago Nicolas Couture-Grenier asked 2 days ago Nicolas Couture-GrenierNicolas Couture-Grenier 1011 silver badge9 bronze badges1 Answer
Reset to default 1It looks like this is an unwanted consequence of how Vue.js implements what it calls Reactivity.
The error originates from here: https://github/chrisguttandin/standardized-audio-context/blob/11cde3f52dad83b6e3f971b3cb3dc4d98ad59b3b/src/factories/gain-node-constructor.ts#L23.
When creating a GainNode
standardized-audio-context tries to find the native AudioContext
which should be used to create the native GainNode
. But when everything gets wrapped with a Proxy
it is essentially a different object when comparing it with the original value. In the end standardized-audio-context can't find the native AudioContext
anymore and throws an error.
It's probably best to not put anything which belongs to Tone.js inside the state managed by Vue.js. But the easiest solution I can think of to make your code work is by using markRaw()
.
Instead of defining your component like this ...
import { defineComponent } from 'vue';
// ... other imports
export default defineComponent({
// ...
data() {
// ...
sampler: new Tone.Sampler({ /* ... */ })
// ...
}
// ...
});
... you could simply wrap the sampler with markRaw()
:
import { defineComponent, markRaw } from 'vue';
// ... other imports
export default defineComponent({
// ...
data() {
// ...
sampler: markRaw(
new Tone.Sampler({ /* ... */ })
)
// ...
}
// ...
});
By the way your code needs one more tweak to work. The onload
callback of the Sampler
doesn't work because this
refers to the context around the arrow function. In this case it's the component.
The following line ...
onload: () => {this.toDestination()},
... should become:
onload: () => {this.sampler.toDestination()},