In Tone.js I have made a class that creates a synth instance where .play() is called in a sequencer function, thereby playing a sound. In the class below there are absolutely no problems when this.synth in updateSynthType is a monophonic Tone.Synth, but the whole thing breaks when it is Tone.Polysynth and I receive the following error when trying to call updateSynthType.
Uncaught Error: Synth was already disposed
at ti (Tone.js:1)
at ra._scheduleEvent (Tone.js:21)
at Object.callback (Tone.js:21)
at Gi._timeoutLoop (Tone.js:21)
at Gi.emit (Tone.js:7)
I don't understand why this never happens with a regular Tone.Synth but when I try to change a Tone.PolySynth an error appears. I am trying to update the settings to change between the type of polysynth (e.g. Synth, AMSynth, MetalSyth etc). How can I stop this problem? Why does this class only work for a regular Tone.Synth? Is there a better way of updating the PolySynth type in this class?
Here is the class in question:
class PolyInstrument {
constructor(){
this.synth = null
this.gain = new Tone.Gain()
this.gain.toDestination()
}
play(note = null, beat, time = null){
if (this.synth){
if (note === null){
time ? this.synth.triggerAttackRelease(beat, time) : this.synth.triggerAttackRelease(beat)
} else {
time ? this.synth.triggerAttackRelease(note, beat, time) : this.synth.triggerAttackRelease(note, beat)
}
} else {
alert('error: no synth')
}
}
get defaultSettings(){
return {
Synth: {
oscillator: {
type: 'triangle'
},
envelope: {
attack: 0.005,
decay: 0.1,
sustain: 0.3,
release: 1
}
},
AMSynth: {
harmonicity: 3 ,
detune: 0 ,
oscillator: {
type: 'sine'
},
envelope: {
attack: 0.01 ,
decay: 0.01 ,
sustain: 1 ,
release: 0.5
},
modulation: {
type: 'square'
},
modulationEnvelope: {
attack: 0.5 ,
decay: 0 ,
sustain: 1 ,
release: 0.5
}
}
}
}
updateSynthType(synthType){
if (this.synth){
this.synth.disconnect(this.gain)
this.synth.dispose()
}
let settings = this.defaultSettings[synthType] || {}
this.synth = new Tone.PolySynth(Tone[synthType], settings)
this.synth.connect(this.gain)
this.play()
}
}
Thanks for reading.
Instead of using synth.dispose(), call synth.releaseAll().
https://tonejs.github.io/docs/14.7.77/PolySynth#releaseAll says:
Trigger the release portion of all the currently active voices immediately. Useful for silencing the synth.
I was able to fix this by clearing out the context timeline before disposing:
synth.context._timeouts.cancel(0);
synth.dispose();
Related
I need to add a custom attribute to components of a ReactJS app, for testing purposes. I have tried to use 2 different plugins, however, they apply the attribute to all JSXElements within that component and I want to apply it to just the first, otherwise, I end up with unnecessary duplication of the attribute which makes writing the tests even harder and I'm trying to save fragility.
I have gone through the docs and cannot find how to traverse to the first JSXElement, so have tried a couple of things myself and failed, these are
The below never adds the attribute
visitor: {
JSXElement( path, state ) {
if ( path.key === 0 )
{
path.node.openingElement.attributes.push(
t.jSXAttribute(
t.jSXIdentifier( 'data-e2e' ),
t.stringLiteral( `${someValue}` )
)
);
}
}
}
The below throughs error that firstElem in undefined
visitor: {
Program( path, state ) {
let arr = [];
path.traverse( {
enter( jsxPath )
{
if ( jsxPath.node.type === 'JSXElement' )
{
arr.push( jsxPath );
}
}
} );
let firstElem = arr[ 0 ]; <<< undefined
firstElem.node.openingElement.attributes.push(
t.jSXAttribute(
t.jSXIdentifier( 'data-e2e' ),
t.stringLiteral( `${someValue}` )
)
);
}
}
}
Can anyone suggest how to get just the first JSXElement.
So I found the answer by pure luck. I should have added in a stop() immediately after traversing the JSXElement
JSXElement( jsxPath )
{
jsxPath.stop();
...
The stop() function is not that will documented, in fact, none of BabelJS is that will documented for a beginner. Found this by looking at a someone's plugin and wondering what it was doing there and by trial and error, found it resolved the above propblem.
I have note like
<note default-x="106.96" default-y="-25.00">
<pitch>
<step>A</step>
<octave>3</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>eighth</type>
<stem>up</stem>
<staff>1</staff>
<beam number="1">begin</beam>
</note>
How can i find what time spend to play it (in second) if tempo = 120bpm ?
Create a table like this:
durationHashTable = {
{ "whole", 4.0 },
{ "half", 2.0 },
{ "quarter", 1.0 },
{ "eighth", 0.5 },
{ "16th", 0.25 } }
Then, the formula is:
noteDurationSeconds = ( 60.0 / beatsPerMinute ) * durationHashTable["eighth"];
This is for the special, simple case where
notes are not dotted
the time signature has <beat-type>4</beat-type>
you are not required to support tuplets.
Things can become significantly more complex, but I would recommend working with this special case first.
Why isn't my score recording on the playerprefs ? is there GetFloat method? Can anyone help me to post the least score of my game it just like the most least seconds will get the best time record ever
var myTimer: float = 0;
var GUITimer: GUIText;
function Start() {
}
function Update() {
GUITimer.text = "Time: " + myTimer;
if (myTimer > -1) {
myTimer += Time.deltaTime;
}
}
function OnTriggerEnter(other: Collider) {
if (other.tag == "FinishLine") {
SaveTime();
}
}
function OnGUI() {
GUI.Label(Rect(10, 10, 500, 200), myTimer.ToString());
}
function SaveTime() {
if (myTimer < PlayerPrefs.GetInt("JeepneyScore3")) {
PlayerPrefs.SetInt("JeepneyScore3", myTimer);
}
Application.LoadLevel("Levels");
}
I see three problems:
First, you're tracking a float, but calling GetInt() and SetInt(). Keep your data types consistent. You should either round/floor/etc, or call GetFloat() and SetFloat().
Second, you're not calling Save(), which means your changes will never write to disk. You might consider something like this:
PlayerPrefs.SetFloat("JeepneyScore3", myTimer);
PlayerPrefs.Save();
Third, you're not handling the case where no data exists. You could check for existing data with HasKey(), but in this case it's simpler to rely on the second form of GetFloat(). The default form, which you're calling, returns zero if the requested key isn't set:
//returns value of "foo", or zero if no such value
var prevBest = PlayerPrefs.GetFloat("foo");
If you're looking for a time below the player's previous best, but the default "best" is already 0.0, you're going to have a hard time beating that time.
You can instead provide your own default value:
//returns value of "foo", or ten thousand if no such value
var prevBest = PlayerPrefs.GetFloat("foo", 10000.0);
Finally, you should make sure that SaveTime() is actually being called at the appropriate time. You could add a simple debug line, like this:
Debug.Log("SaveTime was called");
And then make sure that's showing up. If not, you need to fix your collision check.
I've been working on a simulator in Unity3D and i need a customer object to be able to automatically find the shop object with the lowest price.
I've done a little testing on this myself and found it to be rather difficult to achive. So i was hoping someone could help me tweak my code a bit further in the right direction? :)
Here's the code i've got so far:
var cityName : String;
var shopScript : MarketScript;
function FindShopPlace () : GameObject //Make a queueing system
{
var max : float;
var target : GameObject;
var gos : GameObject[];
var goScript : MarketScript;
gos = GameObject.FindGameObjectsWithTag("market");
for (var go : GameObject in gos)
{
goScript = go.GetComponent(MarketScript);
if (goScript.cityName == cityName)
{
if (goScript.resalePrice >= max && goScript.cityName == cityName)
{
max = goScript.resalePrice;
}
if (goScript.resalePrice < max && goScript.cityName == cityName)
{
print ("test");
target = go;
}
}
}
shopScript = target.GetComponent(MarketScript);
return target;
}
Currently with this code, the target is never found and assigned. I get the following NullReferenceException from line number 3 from the bottom:
NullReferenceException: Object reference not set to an instance of an
object ConsumerScript.FindShopPlace () (at
Assets/_MyAssets/_Scripts/ConsumerScript.js:268) ConsumerScript.Update
() (at Assets/_MyAssets/_Scripts/ConsumerScript.js:96)
You get a NullReferenceException because target was never set to any object.
What you are doing in your loop is (1) finding the maximum price and (2) finding the last Object after maximum that is smaller than the maximum.
So if your prices in order are 1, 2, 3 target will never be set because in each step you are setting the maximum to the new value and are never setting target. Even when set its not necessarily the cheapest. Consider the prices 1, 3, 2.
First Step: Set maximum to 1
Second Step: Set maximum to 3
Third Step: Set target to the GameObject with price 2
If you get errors like this try out simple examples like this to get to the bottom of things. Also you are using the variable maximum(comparing the first time) without ever setting it to anything, not sure if this works in Javascript(it might) but its bad practice
What you really want isnt finding the maximum price or minimum price but the GameObject with the lowest resalePrice.
var min : float;
var success : boolean;
var firstHit : boolean;
...
success = false;
firstHit = true;
for (var go : GameObject in gos)
{
goScript = go.GetComponent(MarketScript);
if (goScript.cityName == cityName)
{
success = true;
if(firstHit) // alternatively to this would be to set minimum to a value that is higher than every possible price ( thats also what i meant with you shouldnt use max without setting it to anything)
{
min = goScript.resalePrice;
target = go;
}
else
{
if (goScript.resalePrice < min )
{
min = goScript.resalePrice;
target = go;
}
}
}
}
if(success)
{
shopScript = target.GetComponent(MarketScript);
return target;
}
else
{
// TODO: handle the case that there isnt a shop in the city.
// Maybe give an error Message with Debug.Log if this isnt supposed to happen
return null;
}
Hi is it possible to set the time range of a Dojo textTimeBox to 09:00 - 18:30.
I can't find anything in either the Zend or Dojo documentation that show how this can be done or if it can be done.
Many thanks in advance.
You can set max and min constraints for widget:
new dijit.form.TimeTextBox({
name: "prog_val",
value: new Date(),
constraints: {
timePattern: 'HH:mm:ss',
clickableIncrement: 'T00:15:00',
visibleIncrement: 'T00:15:00',
visibleRange: 'T01:00:00',
min:'T09:00:00',
max:'T18:30:00'
}
},
"prog_val");
It does not allow the user to enter data beyond the allowed values.
However this still allows user to scroll to the disabled times, user just cannot select them.
For hiding disabled times you should do some hack :)
You should override _getFilteredNodes method of dijit._TimePicker. For example :
dojo.declare("my._TimePicker", dijit._TimePicker, {
// extend the default show() method
_getFilteredNodes: function (/*number*/start, /*number*/maxNum, /*Boolean*/before) {
// summary:
// Returns an array of nodes with the filter applied. At most maxNum nodes
// will be returned - but fewer may be returned as well. If the
// before parameter is set to true, then it will return the elements
// before the given index
// tags:
// private
var nodes = [], n, i = start, max = this._maxIncrement + Math.abs(i),
chk = before ? -1 : 1, dec = before ? 1 : 0, inc = before ? 0 : 1;
do {
i = i - dec;
var date = new Date(this._refDate);
var incrementDate = this._clickableIncrementDate;
date.setHours(date.getHours() + incrementDate.getHours() * i,
date.getMinutes() + incrementDate.getMinutes() * i,
date.getSeconds() + incrementDate.getSeconds() * i);
if (!this.isDisabledDate(date)) {
n = this._createOption(i);
if (n) { nodes.push(n); }
}
i = i + inc;
} while (nodes.length < maxNum && (i * chk) < max);
if (before) { nodes.reverse(); }
return nodes;
}
});
And you need to set this new class ('my._TimePicker') as a popupClass property of your text time box:
dojo.addOnLoad(function () {
dijit.byId("prog_val").popupClass = "my._TimePicker";
});
And you can see : it works!