aboutsummaryrefslogtreecommitdiff
path: root/site/app/ocsillator
diff options
context:
space:
mode:
Diffstat (limited to 'site/app/ocsillator')
-rw-r--r--site/app/ocsillator/index.html319
-rw-r--r--site/app/ocsillator/ocsillator.csd183
2 files changed, 502 insertions, 0 deletions
diff --git a/site/app/ocsillator/index.html b/site/app/ocsillator/index.html
new file mode 100644
index 0000000..f115bcc
--- /dev/null
+++ b/site/app/ocsillator/index.html
@@ -0,0 +1,319 @@
+<html>
+<head>
+<script type="text/javascript" src="/code/jquery.js"></script>
+<script type="text/javascript" src="../base/base.js"></script>
+<script type="text/javascript">
+var appdata = {
+"instruments": [
+ {name: "Effemm bass", instr: "ocsinst_blockbass"},
+ {name: "Three Oh", instr: "ocsinst_303"},
+ {name: "Strung", instr: "ocsinst_strings"},
+ {name: "Harm", instr: "ocsinst_guitarharmonics"},
+ {name: "Cold nights", instr: "ocsinst_guitarharmonicsfx"},
+ {name: "Rhedos", instr: "ocsinst_rhodes1"},
+ {name: "Evolo", instr: "oscinst_pad1"},
+ {name: "Kaleb", instr: "oscinst_kalimba1"},
+ {name: "Freakperk", instr: "ocsinst_perc_freak", nvalue: true},
+ {name: "Canne", instr: "ocsinst_perc_case", nvalue: true},
+]};
+
+var Ocsillator = function(appdata) {
+ var elContainer = $("#main");
+ var elControls = $("#controls");
+ var elXy = $("#xy").css("background-color", "#121212");
+ var elNoteSelect = $("<select />").change(changeScale);
+ var elChordSelect = $("<select />").change(changeScale);
+ var elNoteRange = $("<input />").attr("type", "range").attr("min", 2).attr("max", 24).change(changeScale);
+ var elInstrumentSelect = $("<select />").change(changeInstrument);
+ var elDownload = $("<button />").text("Download").click(downloadFile);
+ var elRecord = $("<button />").text("Record").click(downloadFile);
+ var elPosition = $("<div />").css({width: "30px", height: "30px", "border-radius": "15px", "background-color": "#f5dd42", position: "absolute"}).hide();
+ var normaliseValue = false;
+ var notedata;
+ var uiNotes = [];
+ var mouseisdown;
+
+ function mousedown(e) {
+ mouseisdown = true;
+ elPosition.show();
+ handlePosition(e);
+ playInstrument();
+ }
+
+ function mousemove(e) {
+ if (!mouseisdown) return;
+ handlePosition(e);
+ }
+
+ function mouseup() {
+ mouseisdown = false;
+ elPosition.hide();
+ stopInstrument();
+ }
+
+ elXy.on("mousedown", mousedown).on("mousemove", mousemove).on("mouseup", mouseup).on("touchstart", function(e) {
+ mousedown(e.changedTouches[0]);
+ }).on("touchmove", function(e) {
+ mousemove(e.changedTouches[0]);
+ }).on("touchend", mouseup);
+
+ function handlePosition(e) {
+ var offs = elXy.offset();
+ var h = elXy.height();
+ var w = elXy.width();
+ var posX = e.clientX - offs.left;
+ var posY = e.clientY - offs.top;
+ if (posX < 0 || posX > w || posY < 0 || posY > h) return;
+ elPosition.css({left: (posX - 15) + "px", top: (posY - 15) + "px"});
+
+ var valX = posX / w;
+ var valY = 1 - (posY / h);
+
+ if (!normaliseValue) {
+ var note = uiNotes[Math.floor(valX * uiNotes.length)];
+ app.setControlChannel("note", note);
+ } else {
+ app.setControlChannel("valX", valX);
+ }
+ app.setControlChannel("valY", valY);
+ }
+
+ fetch("../base/notedata.json").then(function(r) {
+ r.json().then(function(j) {
+ notedata = j;
+ buildInputs();
+ });
+ });
+
+ function buildInputs() {
+ for (let n of notedata.notes) {
+ if (n[0] >= 24 && n[0] <= 84) {
+ $("<option />").val(n[0]).text(n[1]).appendTo(elNoteSelect);
+ }
+ }
+
+ for (let c in notedata.chords) {
+ $("<option />").val(c).text(notedata.chords[c].name).appendTo(elChordSelect);
+ }
+
+ for (let i in appdata.instruments) {
+ $("<option />").val(i).text(appdata.instruments[i].name).appendTo(elInstrumentSelect);
+ }
+
+ var tb = $("<tbody />").appendTo($("<table />").appendTo(elControls));
+ var tr = $("<tr />").appendTo(tb);
+ $("<td />").text("Base note").appendTo(tr);
+ $("<td />").text("Chord").appendTo(tr);
+ $("<td />").text("Note range").appendTo(tr);
+ $("<td />").text("Instrument").appendTo(tr);
+ $("<td />").appendTo(tr);
+
+ tr = $("<tr />").appendTo(tb);
+ $("<td />").append(elNoteSelect).appendTo(tr);
+ $("<td />").append(elChordSelect).appendTo(tr);
+ $("<td />").append(elNoteRange).appendTo(tr);
+ $("<td />").append(elInstrumentSelect).appendTo(tr);
+ $("<td />").append(elDownload).appendTo(tr);
+
+ elInstrumentSelect.trigger("change");
+ elNoteSelect.val(48);
+ elChordSelect.val(0);
+ elNoteRange.val(12);
+ changeScale();
+ }
+
+
+ function downloadFile() {
+
+ }
+
+ function recordStart() {
+ app.insertScore("ocsi_recordstart");
+ }
+
+ function recordStop() {
+ app.insertScore("ocsi_recordstop");
+ }
+
+ function recordClear() {
+ app.insertScore("ocsi_recordclear");
+ }
+
+ function changeInstrument() {
+ var instrument = appdata.instruments[elInstrumentSelect.val()];
+ if (instrument.nvalue) {
+ normaliseValue = instrument.nvalue;
+ } else {
+ normaliseValue = false;
+ }
+ app.insertScore("ocsi_setinstrument", [0, 1, instrument.instr]);
+ }
+
+
+ function playInstrument() {
+ app.insertScore("ocsi_play");
+ }
+
+ function stopInstrument() {
+ app.insertScore("ocsi_stop");
+ }
+
+ function changeScale() {
+ var noterange = elNoteRange.val();
+ var notenum = elNoteSelect.val();
+ var intervals = notedata.chords[elChordSelect.val()].intervals;
+ var intervalindex = 0;
+ var octave = 0;
+ var notes = [];
+ var note;
+ for (var i = 0; i < noterange; i++) {
+ note = parseInt(notenum) + (octave * 12) + parseInt(intervals[intervalindex]);
+ if (intervalindex < intervals.length - 1) {
+ intervalindex += 1;
+ } else {
+ intervalindex = 0;
+ octave += 1;
+ }
+ notes.push(note);
+ }
+ uiNotes = notes;
+ redraw();
+ }
+
+
+ function redraw() {
+ var w = window.innerWidth;
+ var h = window.innerHeight;
+ var size = Math.min(w, h);
+ elContainer.css({width: w, height: h});
+ var ch = Math.round(size * 0.1);
+ var xys = Math.round(size * 0.9);
+ elControls.css({width: w + "px", height: ch + "px"});
+ elXy.empty().css({width: xys + "px", height: xys + "px", top: ch + "px"}).append(elPosition);
+
+ var step = Math.round(xys / uiNotes.length);
+ for (var x = 0; x < xys; x += step) {
+ $("<div />").addClass("gridline").css({left: x + "px", height: xys + "px"}).appendTo(elXy);
+ }
+ }
+
+
+ window.onresize = redraw;
+};
+
+$(function() {
+ window.app = new CSApplication({
+ csdUrl: "ocsillator.csd",
+ onPlay: function () {
+ $("#loading").hide();
+ window.osc = new Ocsillator(appdata);
+ }
+ });
+ $("#begin").click(function() {
+ $("#begin").hide();
+ app.play();
+ });
+
+});
+
+</script>
+<style type="text/css">
+ body {
+ font-family: Arial, sans-serif;
+ user-select: none;
+ background-color: #a1a1a1;
+ }
+
+ .gridline {
+ width: 1px;
+ height: 1px;
+ position: absolute;
+ background-color: #33aa33;
+ z-index: 10;
+ }
+
+ #loading {
+ width: 100%;
+ height: 100%;
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ z-index: 20;
+ background-color: #344534;
+ }
+
+ #loading_inner {
+ left: 30%;
+ top: 30%;
+ width: 40%;
+ height: 40%;
+ text-align: center;
+ font-size: 48pt;
+ position: absolute
+
+ }
+
+ #begin {
+ width: 100%;
+ height: 100%;
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ z-index: 25;
+ text-align: center;
+ background-color: #344534;
+ cursor: pointer;
+ }
+
+ #begin_inner {
+ left: 30%;
+ top: 30%;
+ width: 40%;
+ height: 40%;
+ text-align: center;
+ font-size: 48pt;
+ position: absolute
+
+ }
+
+ #main {
+ width: 100%;
+ height: 100%;
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ }
+
+ #controls {
+ width: 100%;
+ height: 20%;
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ }
+
+ #xy {
+ position: absolute;
+ width: 80%;
+ height: 80%;
+ top: 20%;
+ left: 0px;
+ z-index: 1;
+ }
+
+</style>
+</head>
+<body>
+ <div id="loading">
+ <div id="loading_inner">Loading</div>
+ </div>
+ <div id="begin">
+ Ocsillator is inspired by the Korg Kaossilator.
+ <div id="begin_inner">Press to begin</div>
+ </div>
+ <div id="main">
+ <div id="controls"></div>
+ <div id="xy"></div>
+ </div>
+</body>
+</html>
diff --git a/site/app/ocsillator/ocsillator.csd b/site/app/ocsillator/ocsillator.csd
new file mode 100644
index 0000000..4ad464b
--- /dev/null
+++ b/site/app/ocsillator/ocsillator.csd
@@ -0,0 +1,183 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+sr = 44100
+ksmps = 16
+nchnls = 2
+nchnls_i = 1
+0dbfs = 2
+seed 0
+
+#include "interop.udo"
+#include "bussing.udo"
+#include "synth_instruments.udo"
+#include "synth_drums.udo"
+#include "sounddb.udo"
+#include "wavetables.udo"
+
+giocsicol_harmonics sounddb_getcollectionid "Guitar.Harmonics", 1
+
+isize = sr * 60
+giocsi_fnrecord[] fillarray ftgen(0, 0, isize, 2, 0), ftgen(0, 0, isize, 2, 0)
+giosci_loopend = isize
+giocsi_instrument = 0
+
+instr ocsi_recordstart
+ p3 = 99999
+ aL, aR bus_tap "ocsi"
+ apos lphasor 1, 0, giosci_loopend, 1
+ tablew aL, apos, giocsi_fnrecord[0]
+ tablew aR, apos, giocsi_fnrecord[1]
+endin
+
+instr ocsi_recordstop
+ turnoff2 "ocsi_recordstart", 0, 1
+ turnoff
+endin
+
+instr ocsi_recordclear
+
+endin
+
+
+opcode ocsi_defaultinput, kk, 0
+ kamp chnget "valY"
+ knote chnget "note"
+ xout kamp, knote
+endop
+
+instr ocsinst_blockbass
+ kamp, knote ocsi_defaultinput
+ aL, aR synth_fmbass1, cpsmidinn(knote) - 12
+ kenv linsegr 1, p3, 1, 0.2, 0
+ aL *= kenv * kamp
+ aR *= kenv * kamp
+ bus_mix("ocsi", aL, aR)
+endin
+
+
+instr ocsinst_303
+ ky, knote ocsi_defaultinput
+ ifilter = (chnget:i("valY") * 50) + 50
+ kdistortion = (1 - ky) + 1
+ aout synth_303 cpsmidinn(knote), ifilter, kdistortion
+ kenv linsegr 1, p3, 1, 0.2, 0
+ aout *= kenv
+ bus_mix("ocsi", aout, aout)
+endin
+
+instr ocsinst_strings
+ ky, knote ocsi_defaultinput
+ kfreq = cpsmidinn(knote)
+ aL synth_strings1 kfreq, 0.01 * random(0.5, 1.5) * ky * 4, 6 * random(0.5, 1.5) * ky, 0.1 * random(0.5, 1.5), 0.1 * random(0.5, 1.5)
+ aR synth_strings1 kfreq, 0.01 * random(0.5, 1.5) * ky * 4, 6 * random(0.5, 1.5) * ky, 0.1 * random(0.5, 1.5), 0.1 * random(0.5, 1.5)
+ kenv linsegr 1, p3, 1, 0.2, 0
+ aL *= kenv
+ aR *= kenv
+ bus_mix("ocsi", aL, aR)
+endin
+
+
+instr ocsinst_guitarharmonics
+ ky, knote ocsi_defaultinput
+ istartnote = chnget:i("note")
+ knote init istartnote
+ ifileid, ipitchratio sounddb_mel_nearestnote giocsicol_harmonics, chnget:i("note")
+ ifn, ichannels, iduration, irmsnorm sounddb_get ifileid
+ ipitchadjust = ipitchratio* (ftsr(ifn) / sr)
+ kpitch = (cpsmidinn(knote) / cpsmidinn(istartnote)) * ipitchadjust
+ krate = (ky * 10) + 1
+ apos = a(ky) * iduration;abs:k(oscil:k(iduration * 0.5, krate)) + (iduration * 0.1)
+ aL, aR sndwarpst 1, apos, a(port(kpitch, 0.01, ipitchadjust)), ifn, 0, 4410, 441, 4, gifnHanning, 1
+ kenv linsegr 0, 0.1, 1, p3 - 0.1, 1, 0.2, 0
+ aL *= kenv
+ aR *= kenv
+ bus_mix("ocsi", aL, aR)
+endin
+
+
+instr ocsinst_guitarharmonicsfx
+ ky, knote ocsi_defaultinput
+ istartnote = chnget:i("note")
+ knote init istartnote
+ ifileid, ipitchratio sounddb_mel_nearestnote giocsicol_harmonics, chnget:i("note")
+ ifn, ichannels, iduration, irmsnorm sounddb_get ifileid
+ ipitchadjust = ipitchratio * (ftsr(ifn) / sr)
+ kpitch = (cpsmidinn(knote) / cpsmidinn(istartnote)) * ipitchadjust
+ krate = (ky * 10) + 1
+ apos = ((a(ky) * abs:k(oscil:k(random(0.2, 1), random(2, 10)))) + 0.1) * iduration
+ aL, aR sndwarpst 1, apos, a(port(kpitch * 0.5, 0.01, ipitchadjust)), ifn, 0, 4410, 441, 1, gifnHanning, 1
+
+ ahL1, ahL2 hilbert2 aL, 1024, 256
+ amL, afmL fmanal ahL1, ahL2
+ aL oscil amL, afmL * 2
+
+ ahR1, ahR2 hilbert2 aR, 1024, 256
+ amR, afmR fmanal ahR1, ahL2
+ aR oscil amR, afmR * 2
+
+ aL butterhp aL, 500
+ aR butterhp aR, 500
+ ;aL reverb aL, 2 * (ky + 2)
+ ;aR reverb aR, 2 * (ky + 2)
+ aL tanh aL
+ aR tanh aR
+
+ kenv linsegr 1, p3 - 0.1, 1, 0.2, 0
+ aL *= kenv
+ aR *= kenv
+ bus_mix("ocsi", aL, aR)
+endin
+
+
+instr osci_recordplaystart
+ p3 = -1
+ apos lphasor 1, 0, giosci_loopend, 1
+ aL table3 apos, giocsi_fnrecord[0]
+ aR table3 apos, giocsi_fnrecord[1]
+ bus_mix("bufferplay", aL, aR)
+endin
+
+instr osci_recordplaystop
+ turnoff2 "osci_recordplaystart", 0, 1
+ turnoff
+endin
+
+instr ocsi_setinstrument
+ Sinstr = strget(p4)
+ turnoff2 giocsi_instrument, 0, 1
+ giocsi_instrument = nstrnum(Sinstr)
+ turnoff
+endin
+
+instr ocsi_play
+ schedule giocsi_instrument, 0, 99999
+ turnoff
+endin
+
+instr ocsi_stop
+ turnoff2 giocsi_instrument, 0, 1
+ turnoff
+endin
+
+instr ocsi_mixer
+ aLm, aRm bus_read "ocsi"
+ aLb, aRb bus_read "bufferplay"
+
+ aL = aLm + aLb
+ aR = aRm + aRb
+ outs aL, aR
+endin
+
+instr osci_boot
+ schedule "ocsi_mixer", 0, -1
+endin
+
+</CsInstruments>
+<CsScore>
+f0 z
+i"osci_boot" 0 1
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file