// Repo URL: https://github.com/srikumarks/steller
// Demo URL: http://sriku.org/demos/steller_explorer
//
// Code goes here. To evaluate a line, position cursor on 
// it and press "Alt-Enter". To evaluate a selection, 
// select code and press "Alt-Enter".
//
// Methods of the canvas 2d context can simply be called 
// without the "context." object prefix.
// 
// Math functions can be used without the "Math." prefix.
//
// For CSS colors, the function rgba(r,g,b,a) is available
// and better suited for use with Animations.
//
// A steller Scheduler instance is now running and its 
// methods such as play(), track(), etc. are also available 
// without an object prefix.
//
// All the models in the 'models' property of the 
// steller Scheduler are also available unprefixed.
        
// Code goes here. To evaluate a line, position cursor on 
// it and press "Alt-Enter". To evaluate a selection, 
// select code and press "Alt-Enter".
//
// Methods of the canvas 2d context can simply be called 
// without the "context." object prefix.
// 
// Math functions can be used without the "Math." prefix.
//
// For CSS colors, the function rgba(r,g,b,a) is available
// and better suited for use with Animations.
//
// A steller Scheduler instance is now running and its 
// methods such as play(), track(), etc. are also available 
// without an object prefix.
//
// All the models in the 'models' property of the 
// steller Scheduler are also available unprefixed.

// Make a parameter that we'll animate.
pos = Param({min: 0.0, max: 1.0, value: 0.0});

xpos = 100;

// The draw function will draw a box at the position given
// by `pos`.
draw = function (clock) {
    clearRect(0, 0, canvas.width, canvas.height);
    fillStyle = 'blue';
    fillRect(xpos, canvas.height * pos.valueOf(), 20, 20);
};

// Start the draw loop.
play(loop(frame(draw)));

// Make a chime model instance and connect it to 
// the audio destination.
ch = chime().connect();

// Play a looping pattern and insert a sync object 
// at the start of the loop so that we can sync events 
// to that.
s = sync();
play(loop(track([
    s, 
    ch.note(72,0.5), 
    ch.note(79,0.5), 
    ch.note(84,0.5)
    ])));

// Run the line below to play a note exactly at 
// the start of the above loop.
s.play(ch.note(96,0.5));

// Run the line below to start animating the 
// rectangle's position exactly at the start of 
// the above note loop.
s.play(loop(track([
  fire(function () { xpos = canvas.width * (0.15 + random() * 0.75); }),
  anim(pos, 1.5, pos.spec.min, pos.spec.max)
  ])));
    
// Reminder: Alt-Enter on a line will evaluate that 
// line. If some text is selected, then that will 
// be evaluated.
//
// Select all of the text below and hit Alt-Enter 
// to run this example.
//
// After evaluating code, positioning cursor within 
// a name assigned to a Param will pop up a slider 
// to change its value.

// Note: Demonstrating simple temporal recursion to 
// produce a sequence of random notes. No visuals, 
// only sound.

ch = chime().connect(); // Chime instr connected to destination.

speed = Param({min:0.1, max:5.0, value:1.5, mapping:'log'});
pitch = Param({min:60, max:96, value:72});

durations = [0.25, 0.5, 0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 1.0];
random_duration = function () {
  return durations[floor(random() * durations.length)] / speed.value;
};

penta = [0, 2, 4, 7, 9, 12, 14, 16, 19, 21, 24];
penta1 = [0, 2, 4, 7, 9, 12];
major = [0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 21, 23, 24];
minor = [0, 2, 3, 5, 7, 9, 10, 12, 14, 15, 17, 19, 21, 22, 24];
maya = [0, 1, 4, 5, 7, 8, 11, 12];
scale = major;

random_note = dynamic(function (clock) {
    return track([
        ch.note(pitch.value + scale[floor(scale.length * random())], random_duration()), 
        random_note
        ]);
});

play(random_note);
    
// Reminder: Alt-Enter on a line will evaluate that line. 
// If some text is selected, then that will be evaluated.
//
// Select all of the text below and hit Alt-Enter to run 
// this example.
//
// This is a simple random note player with some 
// synchronized visuals. 

ch = chime().connect(); // Chime model connected to destination.

// Choose one from an array at random
choose = function (arr) {
  return arr[floor(arr.length * random())];
};

speed = Param({min:0.1, max:5.0, value:1.5, mapping:'log'});
pitch = Param({min:60, max:96, value:72});

durations = [0.25, 0.5, 0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 1.0];

canvas.style.backgroundColor = 'black';

// The draw function will draw a box at the position
// determined by n (note number) and d (duration).
draw = function (n, d) {
  return function (clock, t1r, t2r, start) {
    fillStyle = rgba(255,255,255,exp(-2*(t1r - start)/d));
    fillRect(16 + 24 * n, 32, 24, 128);
  };
};

// Clear the frame as the first step in every draw cycle.
play(loop(frame(function (clock) { 
    clearRect(0, 0, canvas.width, canvas.height); 
})));

noteWithVisual = dynamic(function (clock) {
  var n = choose(scale);
  var d = choose(durations);
  var ds = d / speed.value; // Speed-adjusted decay duration.
  return track([
    spawn(frames(5*ds, draw(n, 2*ds))), 
    ch.note(pitch.value + n, d)
    ]);
});

penta = [0, 2, 4, 7, 9, 12, 14, 16, 19, 21, 24];
penta1 = [0, 2, 4, 7, 9, 12];
major = [0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 21, 23, 24];
minor = [0, 2, 3, 5, 7, 9, 10, 12, 14, 15, 17, 19, 21, 22, 24];
maya = [0, 1, 4, 5, 7, 8, 11, 12];
scale = maya;

// Directly control the clock's rate using the speed 
// parameter. Notice that there is very little delay in 
// response when you change the speed, even if a long note. 
// has been just scheduled. Position the text cursor 
// within the "speed" variable name to control it.
play(track([rate(speed), loop(noteWithVisual)]));
            
// Simple audio-in/audio-out copying ScriptProcessor.
// Illustrates the two-buffer delay imposed by a
// ScriptProcessor node in Chrome and Safari.
//
// Change buffer length to vary the delay amount!!
jsn = audioContext.createScriptProcessor(4096, 1, 1);
jsn.onaudioprocess = function (event) {
  var inb = event.inputBuffer.getChannelData(0);
  var outb = event.outputBuffer.getChannelData(0);
  outb.set(inb, 0);
};

ch = chime(); // Instantiate a "chime" instrument.

// ch -> jsn -> destination
ch.connect(jsn);
jsn.connect(audioContext.destination);

// ch -> destination
ch.connect(audioContext.destination);

// You'll hear an echo when you play this.
play(ch.note(72,1.0)); 
            
  • Saved images appear below.
  • Click image to load its code.
  • Shift-click to delete a saved image.