Using a string as parameter name

Hi everyone!

I want to make a simple interactive sequencer for my homepage, but I’m running into a problem when trying to play the single notes.

let ton1;
let ton2;
let ton3;

let beats = 16;
let tonName = [];
let sequence = [];
let currentTone;

let pStepCnt;
let stepCntRaw = 0;
let stepCnt = 0;
let tempo = .2;


function preload() {
    ton1 = loadSound('assets/ton1.WAV');
    ton2 = loadSound('assets/ton2.WAV');
    ton3 = loadSound('assets/ton3.WAV');
}

function setup() {
    createCanvas(windowWidth, windowHeight);

    tonName[0] = 'ton1';
    tonName[1] = 'ton2';
    tonName[2] = 'ton3';

    //fill sequencer with random notes 1-3
    for (let i=0; i<beats; i++) {
        sequence[i] = tonName[floor(random(tonName.length))];
    }
 
}

function draw() {
    pStepCnt = stepCnt;
    stepCntRaw+=tempo;
    stepCnt = floor(stepCntRaw)%beats;

 
    currentTone = sequence[stepCnt];
    if (stepCnt!=pStepCnt&&currentTone) {
        currentTone.play();
    }
}

The “sequence” array is filled with strings containing the loadSound name. However, calling these strings to play the respective tone doesn’t work (see last line). The error message is “Uncaught TypeError: currentTone.play is not a function”. Does anyone have a solution?

Thanks!

1 Like

I guess the language chooses the type of the variable automatically

Sequence comes out as String but you want a note

Eg. ton1.play();

Maybe use a if statement to get from string to tone or a switch() clause or a hashMap

why not just do something like

let beats = 16;
let tones = [];
let sequence = [];
let currentTone;

let pStepCnt;
let stepCntRaw = 0;
let stepCnt = 0;
let tempo = .2;


function preload() {
    tones = [
		loadSound('assets/ton1.WAV'),
		loadSound('assets/ton2.WAV'),
		loadSound('assets/ton3.WAV')
	];
}

function setup() {
    createCanvas(windowWidth, windowHeight);

    //fill sequencer with random notes 1-3
    for (let i=0; i<beats; i++) {
        sequence[i] = tones[floor(random(tones.length))];
    }
}

function draw() {
    pStepCnt = stepCnt;
    stepCntRaw+=tempo;
    stepCnt = floor(stepCntRaw)%beats;

 
    currentTone = sequence[stepCnt];
    if (stepCnt!=pStepCnt&&currentTone) {
        currentTone.play();
    }
}

why would you add another layer to the tones? unless it’s necessary i would just do as above and there are a few other things you could do to clean that up.

2 Likes

yess I went with hotfooteds way, didn’t know you could fill an array with functions.
What other things could I clean up? The thing is this is just a stripped down code, what I’m actually trying to do needs some more steps.

In the array there are no functions, just sound objects

The objects possess functions like play

The loadsounds just return objects into the array

3 Likes

p5js’ random() is overloaded to accept an array argument as well: :sunglasses:
p5js.org/reference/#/p5/random

So that whole loop can be rewritten more succinctly like this instead: :writing_hand:
for (let i = 0; i < beats; sequence[i++] = random(tones));

Or like this too, assuming the array is still empty (its length = 0) of course: :wink:
for (let i = 0; i < beats; ++i) sequence.push(random(tones));

2 Likes