Skip to content

Commit

Permalink
First attempt at physical modeling. Not usable yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
severak2 committed Sep 26, 2024
1 parent d1771b8 commit 634698c
Showing 1 changed file with 317 additions and 0 deletions.
317 changes: 317 additions & 0 deletions test-pm.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Physical modelling test / Cyber Music Studio™</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/uboot.css">
<link rel="stylesheet" href="css/gh-fork-ribbon.css">
<script src="js/bluescreen.js"></script>
<script src="js/uboot.js"></script>
<script src="js/JZZ.js"></script>
<script src="js/JZZ.input.Kbd.js"></script>
<script src="js/JZZ.gui.Select.js"></script>
<script src="js/wavy-jones.js"></script>
<script src="js/wave-encoder-polyfill.js"></script>
<script src="js/heartbeat.js"></script>
<style>
body {
font-family: "Lucida Console", monospace;
background: url("img/1280px-Tsunami_by_hokusai_19th_century.jpg") plum no-repeat fixed top center/cover;
}

footer {
margin-top: 1em;
background-color: whitesmoke;
}

.ub-box {
background-color: #FFFFCC;
}

#box_welcome { width: 30em; margin: auto; }

a { color: black; text-decoration: underline dashed; text-decoration-thickness: 1px; }

#power {
font-weight: bold;
font-size: 200%;
}

.ub-container {
max-width: 60em !important;
}

.is-blinking {
animation: blinker 1s linear infinite;
}

@keyframes blinker {
50% {
opacity: 0;
}
}

.big-buttons button, .big-buttons label {
width: 98%;
font-weight: bold;
font-size: x-large;
}

#tape_menu {
width: 400px;
height: 250px;

}

.ub-form button.red {
background-color: red;
}

.presets a {
display: inline-block;
}
</style>
</head>
<body>

<a class="github-fork-ribbon" href="https://github.com/severak/cyber-music-studio" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>

<div class="ub-container">
<br><br>

<div class="ub-box" id="box_welcome">
<img src="img/preview.png" class="ub-fit-img">
<p>This is part of beta version of Cyber Music Studio™. It's not finished yet and can be broken at any moment.</p>
<p>Feel free to test it and report bugs <a href="https://github.com/severak/cyber-music-studio/issues" target="_blank">here</a>.</p>
<center><button id="power" class="ub-button">OK</button></center>
</div>

<form class="ub-form ub-hidden" id="form">
<div class="ub-box">
<div class="ub-cols">
<div class="big-buttons">
<button id="panic_button">PANIC!</button>
</div>
<div>
freq:<br><input type="range" min="80" max="10000" step="1" id="freq" value="10000">
</div>
<div>
feedback len:<br><input type="range" min="0.001" max="0.5" step="0.001" id="flen" value="0.001">
</div>
<div>
feedback depth:<br><input type="range" min="0.9" max="0.999" step="0.001" id="fdepth">
</div>
<div>
freq2:<br><input type="range" min="80" max="20000" step="1" id="freq2" value="20000">
</div>
</div>






<div>
Use computer keyboard or following widget:<br/>
<div id="keyboard3"></div>
or MIDI input: <select id="select_midi_in3"></select>
</div>
</div>

<footer>Part of <a href="index.html">Cyber Music Studio™</a> by <a href="http://tilde.town/~severak/">Severák</a>. Supports <a href="https://www.g200kg.com/en/docs/webmidilink/index.html" target="_blank">WebMidiLink</a>.</footer>

</form>
</div>

<script>
function keyboardMidiWrap(keyboardElemId, midiSelectorId, synth) {
// set up routing from external MIDI via HTML keyboard to synth itself
var kbd = JZZ.input.Kbd({ at:keyboardElemId, pos:'N', wl: 50, ww:21, bl: 25, bw:12, from:'F4', to:'C7' });
var midiIn = JZZ.gui.SelectMidiIn({ at: midiSelectorId });
kbd.connect(function (msg) {
hb.midi2call(msg, synth)
});

kbd.getKey('F4').setInnerHTML('Z');
kbd.getKey('C5').setInnerHTML('B');
kbd.getKey('F5').setInnerHTML('Q');
kbd.getKey('C6').setInnerHTML('T');
kbd.getKey('F6').setInnerHTML('I');
kbd.getKey('C7').setInnerHTML(']');

var ascii = JZZ.input.ASCII({
// lower row:
Z: 'F4',
S: 'F#4',
X: 'G4',
D: 'G#4',
C: 'A4',
F: 'A#4',
V: 'B4',
B: 'C5',
H: 'C#5',
N: 'D5',
J: 'D#5',
M: 'E5',
// upper row:
Q: 'F5',
2: 'F#5',
W: 'G5',
3: 'G#5',
E: 'A5',
4: 'A#5',
R: 'B5',
T: 'C6',
6: 'C#6',
Y: 'D6',
7: 'D#6',
U: 'E6',
I: 'F6',
9: 'F#6',
O: 'G6',
0: 'G#6',
P: 'A6',
'%': 'A#6',
'[': 'B6',
']': 'C7'
});

ascii.connect(kbd);

// handles all the selection stuff
midiIn.onSelect = function(name) {
JZZ().openMidiIn(name).and(function () {
if (kbd.currentExternal) kbd.currentExternal.disconnect(kbd);
this.connect(kbd);
kbd.currentExternal = this;
}).or(function () {
if (kbd.currentExternal) kbd.currentExternal.disconnect(kbd);
});
};
}

makeNoice = function(startAt) {
if (!startAt) startAt = hb.ac.currentTime;
// adapted from https://noisehack.com/generate-noise-web-audio-api/
// important - noise must be longer than 2s to be perceived as noise
var bufferSize = 30 * hb.ac.sampleRate,
noiseBuffer = hb.ac.createBuffer(1, bufferSize, hb.ac.sampleRate),
output = noiseBuffer.getChannelData(0);
for (var i = 0; i < bufferSize; i++) {
output[i] = Math.random() * 2 - 1;
}

var osc = hb.ac.createBufferSource();
osc.buffer = noiseBuffer;
osc.loop = true;
osc.start(startAt);

return osc;
};

// see https://github.com/web-audio-components/comb/tree/master

Natural = function() {
var me = {};
me.commonNoise = hb.makeNoiseOsc();
me._voices = {};
me.output = hb.makeGain(0.3);

me.param = function(name, val) {
me[name] = val;
console.log(name, val);
};

me._makeVoice = function(nn) {
var vox = {};
var noise = makeNoice();
var env = hb.makeGain(0);
vox.env= env;
hb.adsrStart(env.gain, {attack: 0.001, decay: 0.05});

//console.log('flen=' + me.flen + ' fdepth='+me.fdepth + ' freq='+me.freq);

//var ping = hb.makeOsc('sawtooth', hb.midi2cps(nn));

var delay = hb.ac.createDelay(1/hb.midi2cps(nn));
var feedback = hb.makeGain(me.fdepth);

var prefilter = hb.makeFilter('lowpass', me.freq);

//var filter2 = hb.makeFilter('lowpass', me.freq2);
//hb.setNow(filter2.Q, 0.3);

//hb.chain(ping, env);

hb.chain(noise, prefilter, env, delay, me.output)
hb.chain(delay, feedback, delay)

vox.noteOff = function () {};
me._voices[nn] = vox;

return vox;
};

me._restartVoice = function (nn) {
var env = me._voices[nn].env;
hb.adsrStart(env.gain, {attack: 0.001, decay: 0.004});
};

me.noteOn = function(nn) {
// console.log('on ' + nn);
if (me._voices[nn]) {
me._restartVoice(nn);
return;
} // už je
me._voices[nn] = me._makeVoice(nn);
};

me.noteOff = function(nn) {
// console.log('off ' + nn);
if (!me._voices[nn]) return; // už není
me._voices[nn].noteOff();
delete me._voices[nn];
};


me.panic = function() {
console.log('PANIC at the disco!');
for (var nn in me._voices) {
me._voices[nn].noteOff();
}
// me._vol.gain.setValueAtTime(0, me._ac.currentTime);
};



return me;
};

ub.on("power","click", function(ev){
ub.stop(ev);
ub.addClass("box_welcome", 'ub-hidden');
ub.delClass("form", 'ub-hidden');

ub.gebi('form').reset();
hb.start();

synth = Natural();
hb.chnget(synth, 'flen', 'flen');
hb.chnget(synth, 'fdepth', 'fdepth');
hb.chnget(synth, 'freq', 'freq');
hb.chnget(synth, 'freq2', 'freq2');
var safetyValve = hb.makeGain(1);
hb.chain(synth.output, safetyValve, hb.ac.destination);


ub.on('panic_button', 'click', function (ev){ub.stop(ev); hb.setNow(safetyValve.gain, 0); ub.addClass('panic_button', 'red'); });

keyboardMidiWrap('keyboard3', 'select_midi_in3', synth);
hb.enableWebMidiLink(synth);
});
</script>

<script src="//million.svita.cz/millions_v1.js"></script>
</body>
</html>

0 comments on commit 634698c

Please sign in to comment.