I began experimenting with Dittytoy and especially FM synthesis and ended up with this rendition of my Amstrad CPC cover of Zetrix/Arcane's Amiga cover (youtube.com/watch?v=5vy6g42ezby) of The Last Hero by Future Freak (csdb.dk/sid/?id=12652)
Log in to post a comment.
// Constants const TAU = Math.PI * 2; const sin = Math.sin; const exp = Math.exp; // Envelopes my_env = adsr.create( { attack: 0.1, decay: 0.2, release: 0.2, duration: 10 }); // Synths const square = synth.def( (phase, env, tick, options) => Math.sign(sin(phase*TAU)) * env.value); const saw = synth.def( (phase, env, tick, options) => ((phase % 1)*2-1) * env.value); const sinus = synth.def( (phase, env, tick, options) => sin(phase*TAU) * env.value); const fm = synth.def( class { constructor (options) { this.phase = 0; this.t = 0 // index of modulation this.iom = options.iom || 13.7; this.mul = options.multiplier || 0.5; } process(note, env, tick, options) { // carrier frequency const fc = midi_to_hz(note); // modulator frequency const fm = fc * this.mul; // forward time this.t += ditty.dt; const osc = sin( TAU*this.t*fc + this.iom*sin(TAU*this.t*fm) ) * env.value; // swing panning const swing = tick * 1.6128; const x = TAU*swing; const m = 0.5; const L = m - sin(x) * m; const R = m - sin(x+Math.PI) * m; return [osc * L, osc * R]; // left, right } }); class ST128 { constructor(options) { this.synth = options.synth; this.notes = options.notes; this.max = this.notes.length; this.adsr = options.adsr || { attack: 0.01, release: 0.25, duration: 0.125, amp: 1.0 }; this.speed = options.speed || 0.05; this.transpose = options.transpose || 0; this.arps = options.arps || []; this.pos = 0; } process(loopCount) { let tpl = this.notes[this.pos++]; if (this.pos >= this.max) this.pos = 0; this.pause = tpl[0]; this.note = tpl[1]; this.adsr.duration = this.pause * (this.speed * 0.95); if (this.note > 0) this.synth.play(this.note + this.transpose, this.adsr); sleep(this.pause * this.speed); } } // Song data const tracks = [ [[640, 0], [320, 0], [320, 0], [1280,0]] , [[640, 0], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 56], [20, 56], [30, 56], [30, 56], [20, 56], [30, 56], [30, 51], [20, 51], [20, 51], [10, 51], [30, 46], [20, 46], [30, 46], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 56], [20, 56], [30, 56], [30, 56], [20, 56], [30, 56], [30, 51], [20, 51], [20, 51], [10, 51], [30, 46], [20, 46], [30, 46], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 48], [20, 48], [30, 48], [30, 48], [20, 48], [20, 48], [10, 48], [30, 56], [20, 56], [30, 56], [30, 56], [20, 56], [30, 56], [30, 51], [20, 51], [20, 51], [10, 51], [30, 46], [20, 46], [20, 46], [10,0]] , [[660, 0], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 80], [10, 80], [30, 80], [40, 80], [10, 80], [30, 80], [40, 75], [40, 75], [40, 70], [10, 70], [30, 70], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 80], [10, 80], [30, 80], [40, 80], [10, 80], [30, 80], [40, 75], [40, 75], [40, 70], [10, 70], [30, 70], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 72], [10, 72], [30, 72], [40, 72], [40, 72], [40, 80], [10, 80], [30, 80], [40, 80], [10, 80], [30, 80], [40, 75], [40, 75], [40, 70], [10, 70], [10, 70]] , [[320, 60], [160, 68], [80, 67], [80, 65], [1920,0]] , [[10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 91], [10, 82], [10, 87], [10, 82], [10, 91], [10, 82], [10, 87], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 91], [10, 82], [10, 87], [10, 82], [10, 91], [10, 82], [10, 87], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 91], [10, 82], [10, 87], [10, 82], [10, 91], [10, 82], [10, 87], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 91], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 92], [10, 84], [10, 87], [10, 84], [10, 91], [10, 82], [10, 87], [10, 82], [10, 91], [10, 82], [10, 87], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82], [10, 89], [10, 82], [10, 86], [10, 82]] , [[1280, 0], [40, 79], [20, 77], [10, 79], [40, 72], [10, 72], [20, 75], [20, 77], [40, 79], [20, 77], [10, 82], [50, 79], [20, 75], [20, 77], [40, 79], [20, 77], [10, 79], [40, 70], [10, 70], [20, 75], [20, 77], [30, 79], [30, 80], [20, 82], [30, 79], [30, 77], [10, 75], [10, 77], [40, 79], [20, 77], [10, 79], [40, 72], [10, 72], [20, 75], [20, 77], [40, 79], [20, 77], [10, 82], [50, 79], [20, 75], [20, 77], [40, 79], [20, 77], [10, 79], [40, 70], [10, 70], [20, 75], [20, 77], [30, 79], [30, 80], [20, 82], [30, 79], [30, 77], [10, 75], [10, 77]] , [[1425, 0], [160, 77], [160, 77], [320, 77], [160, 77], [160, 77], [160, 77], [15,0]] , ]; const song = [ { name: 'Bass 1', synth: saw, notes: tracks[1], transpose: -12, adsr: { attack: 0.01, decay: 0.7, sustain: 0.25, amp: 0.6128 } },{ name: 'Arps 1', synth: sinus, notes: tracks[2], adsr: { attack: 0.01, decay: 0.5, sustain: 0.0, amp: 0.464 } },{ name: 'Bass 2', synth: fm, notes: tracks[3], transpose: -12, adsr: { attack: 0.01, decay: 4, sustain: 0.0, amp: 0.368 }, },{ name: 'Arps 2', synth: fm, iom: 4.23, notes: tracks[4], adsr: { attack: 0.01, decay: 0.5, sustain: 0.3, amp: 0.464 } },{ name: 'Lead', synth: saw, notes: tracks[5], adsr: { attack: 0.01, decay: 0.5, sustain: 0.2, amp: 0.6128 } } ]; // Play it again, Arnold! ditty.bpm = 120; for (let track of song) { loop(ST128, track); }