Experience the sounds of a distant futuristic city - a blend of technology and nature, where calmness meets bustling energy.
Log in to post a comment.
/* =========================================================== =========================================================== ================ ================== ================ FUTURISTIC CITYSCAPE ================== ================ ================== =========================================================== =========================================================== Let's imagine an artificial environment set in the distant future, specifically a large, bustling city on a different planet. The city is filled with towering buildings and advanced technology that makes everything run smoothly and efficiently. As you step into the city, the first thing you notice is the hum of energy that fills the air. The buildings are powered by advanced energy sources, and you can hear the low, steady hum of machinery as they work to keep the city running. Despite the technological hustle and bustle, there is a sense of calmness in the air. A soft, ambient music can be heard playing in the background, created by advanced AI algorithms that know exactly what type of music will help people feel relaxed and at ease. As you walk down the streets, you can hear the gentle whirring of electric cars and hoverbikes passing by. The streets are clean and quiet, thanks to the advanced transportation systems that are designed to minimize noise pollution. As you approach a park, you can hear the sound of water trickling from a nearby fountain. The water is illuminated by advanced bioluminescent technology, creating a beautiful and calming display. =========================================================== The text above was written by ChatGPT. So were the title and description. But the sound design is mine. - Alexis THIBAULT, March 2023 */ ditty.bpm = 60; const TWOPI = 2*Math.PI; const tri = (x) => 1 - 2 * Math.abs((x-(~~x)) - 0.5); function rn(a) { // Random number between -a and +a return 2*a*(Math.random()-0.5); } function nsin(a) { // Not quite a sinusoid let x = a - (~~a); //return Math.sin(2*Math.PI*x); return x*(x-1)*(x-0.5)*20.785; //x -= 0.5; x *= 2 * 3.0786; return x - x**3/6 + x**5/(1*2*3*4*5) - x**7/(1*2*3*4*5*6*7); } function softclip(x) { return x<-1?-1:x>1?1:1.5*(1-x*x/3)*x; } function varsaw(p, formant) { let x = p-~~p; return (x - 0.5) * softclip(formant*x*(1-x)); } class GrayNoise { constructor(bitDepth=16) { this.bitDepth = bitDepth; this.v = 1 << (bitDepth - 1); this.x = 0; } process() { let rnd = Math.random(); // Compute a random 16-bit number, // e.g. 1000100101101100 let m = ~~(rnd * (1 << this.bitDepth)); // Find largest power of two divisor of m, // e.g. 0000000000000100 m &= -m; // Toggle that bit in v this.v ^= m; // Compute the corresponding value in the -1 to 1 range this.x = this.v / (1 << (this.bitDepth-1)) - 1; return this.x; } } let grayNoise = synth.def(class { constructor(o) { this.gn = new GrayNoise(o.bitDepth); } process(n,e,t,o) { return this.gn.process() * e.value; } }, {bitDepth:5}); // =================== echo filter by srtuss =================== // https://dittytoy.net/ditty/cef878f9e1 class Delayline { constructor(n) { this.n = ~~n; this.p = 0; this.lastOut = 0; this.data = new Float32Array(n); } process(input) { this.lastOut = this.data[this.p]; this.data[this.p] = input; if(++this.p >= this.n) this.p = 0; return this.lastOut; } tap(offset) { var x = this.p - offset - 1; x %= this.n; if(x < 0) x += this.n; return this.data[x]; } } const echo = filter.def(class { constructor(opt) { this.lastOut = [0, 0]; var division = opt.division || 3/4; var pan = clamp01((opt.pan || 0)*.5+.5); var sidetime = (opt.sidetime || 0) / ditty.dt; var time = 60 * division / ditty.bpm; this.fb = clamp(opt.feedback || 0, -1, 1); this.kl = 1-pan; this.kr = pan; this.wet = opt.wet || .5; this.stereo = isFinite(opt.stereo) ? opt.stereo : 1; var n = ~~(time / ditty.dt); this.delay = [new Delayline(n), new Delayline(n)]; this.dside = new Delayline(~~sidetime); // --- Filtering added by athibaul this.a0 = clamp01(TWOPI*opt.cutoff*ditty.dt); debug.log("a0", this.a0); this.sfilt = [0, 0]; // --- } process(inv, opt) { this.dside.process(inv[0]); var l = this.dside.lastOut * this.kl; var r = inv[1] * this.kr; var nextl = l + this.delay[1].lastOut * this.fb; var nextr = r + this.delay[0].lastOut * this.fb; // --- Filtering added by athibaul this.sfilt[0] += this.a0 * (this.delay[0].lastOut - this.sfilt[0]); this.sfilt[1] += this.a0 * (this.delay[1].lastOut - this.sfilt[1]); this.lastOut[0] = inv[0] + this.sfilt[0] * this.wet; this.lastOut[1] = inv[1] + this.sfilt[0] * this.wet; // --- this.delay[0].process(nextl); this.delay[1].process(nextr); if(this.stereo != 1) { var m = (this.lastOut[0] + this.lastOut[1])*.5; var s = (this.lastOut[0] - this.lastOut[1])*.5; s *= this.stereo; this.lastOut[0] = m+s; this.lastOut[1] = m-s; } return this.lastOut; } }, {sidetime: .01, division: 1/2, pan: .5, wet: .5, feedback: .6, stereo: 2, cutoff:3000}); // ======================================================================= const hum = synth.def(class { constructor(o) { this.f = o.f; this.df = 0; this.p = 0; this.a0 = ditty.dt * o.dfHz; // Frequency variation speed this.s1 = 0; this.a1 = ditty.dt * o.nco; // Noise cutoff } process(n,e,t,o) { this.df += this.a0 * (-this.df + rn(o.dfAmt)); this.f = o.f * (1 + this.df); this.p += this.f * ditty.dt; let sig = nsin(this.p); let noise = rn(1); this.s1 += this.a1 * (noise - this.s1); sig += this.s1 * Math.exp(o.nSpiky * sig) * o.nAmt; return sig * e.value; } }, {f:55, dfHz:10, dfAmt:2, nco:1500, nSpiky:1, nAmt:0.2, env:adsr, attack:1, duration:1000, release:10, amp:0.1}); // City hum loop((i) => { hum.play(c4, {nco:1300, nAmt:0.2, attack:3,release:5,duration:10}); sleep(10*Math.random()); }, {name:"Hum", amp:0.5}) .connect(echo.create({wet:0.9,feedback:0.6})); // Car traffic loop((i) => { let freq = 110 + rn(10); let df = 10 + rn(6); let direction = Math.random() < 0.5 ? 1 : -1; hum.play(0, { f: (t) => freq - df * Math.atan(-1 + 2*t/6), dfAmt:8, dfHz:1, nco:800, nAmt:0.5, nSpiky:0.3, attack:3, release:3, duration:3, curve:[3,0,-3], pan: (t) => (-1 + 2*t/6) * direction, amp: Math.random() * 0.5, }); //hum.play(0, {f:110, dfAmt:8, dfHz:3, nco:800, nAmt:0.5, nSpiky:0.3, pan:1}); sleep(6 * Math.random()); }, {name: "Car traffic", amp:0.5}) .connect(echo.create({wet:0.6, feedback:0.5})); // Hoverbike traffic loop((i) => { sleep(20 * Math.random()); let freq = 60 + rn(20); let df = 2; let direction = Math.random() < 0.5 ? 1 : -1; hum.play(0, { f: (t) => freq - df * Math.atan(-1 + 2*t/10), dfAmt:20, dfHz:10, nco:2000, nAmt:0.03, nSpiky:4, attack:5, release:5, duration:5, curve:[3,0,-3], pan: (t) => (-1 + 2*t/10) * direction, amp: Math.random() * 0.3, }); sleep(0.1); //hum.play(0, {f:110, dfAmt:8, dfHz:3, nco:800, nAmt:0.5, nSpiky:0.3, pan:1}); }, {name: "Hoverbike traffic", amp:0.3}) .connect(echo.create({wet:0.6, feedback:0.5})); // ====================================== // Ambient music forked from my ditty "Blade Runner Pad" // https://dittytoy.net/ditty/7d36343a29 const lushPad = synth.def(class { constructor(options) { this.freq = midi_to_hz(options.note); this.notes = options.notes; this.relfreqs = this.notes.map( (nn) => 2**((nn-options.note)/12) * options.detune); this.phase = 0; } process(note, env, tick, options) { this.phase += this.freq * ditty.dt; let relfreqs = this.relfreqs; let phases = relfreqs.map((rf) => this.phase * rf); let vols = relfreqs.map( (rf) => 1/Math.sqrt(rf)); let pans = relfreqs.map( (rf,i) => nsin(i + 0.2*tick*Math.sqrt(6*rf)) ); let vib = relfreqs.map( (rf,i) => 1 + 0.3*nsin(i + 2*tick*Math.sqrt(rf)) ); let osc; if(options.type == "saw") { osc = phases.map( (p,i) => varsaw(p,30*env.value * vols[i] * vib[i]) * vols[i] * 0.1 * env.value); } else { osc = phases.map( (p,i) => Math.sin(TWOPI*p + vib[i]*nsin(p)*env.value) * vols[i] * 0.1 * env.value); } let osc2 = osc.map( (sig,i) => [sig * (1 - pans[i]), sig * (1 + pans[i])] ); let sig = osc2.reduce( (a,b) => [a[0]+b[0],a[1]+b[1]], [0,0]); return sig; } }, {detune:1, notes:[], type:"saw"}); const chimes = synth.def((p,e,t,o) => { let iom = e.value**4 * clamp01(0.8**(o.note-69)) * o.amp; let vib = 1+0.5*Math.cos(TWOPI*t*o.vibHz); return Math.sin(TWOPI*o.fc*p + iom * nsin(o.fm*p)) * e.value * vib; }, {fc:1, fm:7.05}); ditty.bpm = 60; /* const mychords = [[c2,c3,g3,b3,d4,e4,a4], [f2,c3,f3,g3,a3,d4,e4,b4], [e2,e3,a3,b3,c4,d4,g4], [f2,c3,f3,b3,c4,d4,e4,a4], [bb1,bb2,f3,a3,bb3,d4,f4,e5], [ab1,ab2,eb3,ab3,c4,eb4,g4,d5], [g2,f3,g3,a3,b3,c3,d4,e4]]; */ // Chord sequence inspired by a ChatGPT answer const mychords = [ [d2,a2,d3,fs3,a3,d4], // D [c2,c3,eb3,g3,c4,eb4,a4], // Cm6 [d2,a2,d3,e4,fs3,a3,c4,fs4,a4,d5], // D9 [c2,eb3,g3,bb3,d4,eb4,c4,a4], // Cm69 //[c2,eb4,g2,bb3,d4,eb3,bb4], // Cm7 //[bb1,e4,ab3,bb2,db4,f3,ab4], // Bbm7b5 [g2,bb3,d3,f3,g3,d4,g4], // Gm7 [f1,f2,ab3,c3,f3,eb4,f4,ab4,c5,f5], // Fm7 [eb1,eb2,bb2,db3,g3,bb3,db4,e4], // Eb7b9 ]; loop((i) => { lushPad.play(c4, {notes:mychords.ring(i), attack:5, decay:3, sustain:0.7, duration:10, release:2, detune:1, type:"fm"}); sleep(10); }, {name:"FM synth", amp:0.2}).connect(echo.create({wet:0.9})); loop((i) => { sleep(1); if(Math.floor(i / mychords.length) % 2 == 1) { lushPad.play(c4, {notes:mychords.ring(i), attack:5, decay:3, sustain:0.7, duration:10, release:2, amp:0.8, detune:1.01, type:"saw"}); } sleep(9); }, {name:"Saw synth", amp:0.3}).connect(echo.create()); loop((i) => { if(i % mychords.length<= 1) { return; } for(let j=0; j<100; j++) { let octave = 12 * Math.floor(Math.random() * 3); chimes.play( mychords.ring(i).choose() + octave, { amp:1.5*Math.random(),attack:0.01, decay:0.5,sustain:0.5,duration:0.5,release:1, pan:Math.random()*2-1, vibHz:6**Math.random() } ); sleep(Math.random()*0.5 + 0.05); // 0.3s on average } }, {name:"Chimes", amp:0.2*0.1, sync:10}) .connect(echo.create({wet:0.9})); loop((i) => { if(Math.floor(i / mychords.length) % 2 == 0) { return; } for(let j=0; j<100; j++) { let octave = 12 + 12 * Math.floor(Math.random() * 2); chimes.play( mychords.ring(i).choose() + octave, { amp:1.5*Math.random(), attack:0.1, decay:0.2,sustain:0.5,duration:0.3,release:0.2, pan:rn(1), vibHz:6**Math.random(), fc:2, fm:1 } ); sleep(0.25); // 0.3s on average } }, {name:"Chimes 2", amp:0.2*0.1, sync:10}) .connect(echo.create({wet:0.9})); let waterFX = synth.def(class { constructor(o) { this.gn = new GrayNoise(o.bitDepth); this.p = 0; } process(n,e,t,o) { // Fast, random frequency variation simulates the noise of bubbles this.gn.process(); let freq = o.fmin * (o.fmax/o.fmin)**this.gn.x; this.p += freq * ditty.dt; return Math.sin(2*Math.PI*this.p) * e.value; } }, {bitDepth:5, fmin:100, fmax:10000, amp:0.1}); const bioLumTech = synth.def((p,e,t,o) => tri(p + 0.5 * tri(10*t)*tri(6.1803*t)) * nsin(t) * e.value); loop((i) => { if(i % mychords.length == 4) { let width = adsr.create( { attack: 10, decay: 20, release: 0.2, duration: 1 }); grayNoise.play(c4, {env:adsr, attack:8, release:25, curve:[0,0,0],bitDepth:8}); grayNoise.play(c4, {env:adsr, attack:9, release:23, curve:[0,0,0], bitDepth:3, pan: () => 0.2 * width.value}); grayNoise.play(c4, {env:adsr, attack:10, release:20, curve:[0,0,0], bitDepth:5, pan: () => -0.2 * width.value}); bioLumTech.play(f5, {env:adsr, attack:10, release:20, curve:[0,0,0], amp:3}); for(let j=0; j<3; j++) { waterFX.play(c4, {env:adsr, attack:10, release:22,curve:[0,0,0], fmin:1000, fmax:10000, bitDepth:9+j, pan:0.2*(j-1), amp:0.3}); } } }, {name:"Fountain", sync:10, amp:0.01}) .connect(echo.create());