webgl-3d-animation
Version:
Interactive 3D animation using WebGL showing a 2D predator prey ecology on a grid which is real-time mapped onto the surface of a 3D torus. node.js server side gives access to WAV format files which are rendered using Web Audio API
1,237 lines (742 loc) • 39.2 kB
JavaScript
var webaudio_tooling_obj = function() {
var audio_context;
var BUFF_SIZE;
var BUFF_SIZE_TIME_DOMAIN;
var did_one_draw = false;
var was_anything_stopped = false;
var microphone_data = {};
function init_context_audio(given_buffer_size, given_buffer_size_time_domain) {
BUFF_SIZE = given_buffer_size;
BUFF_SIZE_TIME_DOMAIN = given_buffer_size_time_domain;
try {
// window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.AudioContext = window.AudioContext ||
window.webkitAudioContext ||
window.mozAudioContext ||
window.oAudioContext ||
window.msAudioContext;
audio_context = new AudioContext();
console.log("cool audio context established");
} catch (e) {
alert('Web Audio API is not supported by this browser\n ... get with wit yo');
}
// ---
gain_node = audio_context.createGain(); // Declare gain node
gain_node.connect(audio_context.destination); // Connect gain node to speakers
}
var gain_node;
var source_node;
var fft_analyzer;
var script_processor_audio_file_node;
var script_processor_fft_node;
var script_processor_synth_node;
var script_processor_time_domain_node;
var allow_synth = false;
function setup_time_domain(given_script_processor) {
given_script_processor.onaudioprocess = (function() {
return function(event) {
var input_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
input_buffer = event.inputBuffer.getChannelData(0); // stens TODO - do both channels not just left
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(input_buffer,
BUFF_SIZE_TIME_DOMAIN, "providence_4");
};
}());
} // setup_time_domain
function setup_audio_nodes(flag_loop) {
script_processor_time_domain_node = audio_context.createScriptProcessor(BUFF_SIZE_TIME_DOMAIN, 1, 1);
script_processor_time_domain_node.connect(gain_node);
// setup a javascript node
script_processor_audio_file_node = audio_context.createScriptProcessor(2048, 1, 1);
script_processor_audio_file_node.connect(gain_node);
// script_processor_audio_file_node.connect(script_processor_time_domain_node);
// setup a analyzer
fft_analyzer = audio_context.createAnalyser();
fft_analyzer.smoothingTimeConstant = 0;
fft_analyzer.fftSize = 1024;
// create a buffer source node
source_node = audio_context.createBufferSource();
source_node.loop = flag_loop;
source_node.connect(fft_analyzer);
fft_analyzer.connect(script_processor_audio_file_node);
source_node.connect(gain_node);
source_node.connect(script_processor_time_domain_node);
// ---
document.addEventListener('visibilityChange', on_visibility_change);
setup_time_domain(script_processor_time_domain_node); // stens TODO performance - is repeats forever
} // setup_audio_nodes
// load the specified sound
function load_sound(url, once_playback_starts_callback, given_mode, stop_callback) {
console.log('here is url ', url);
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// var file_suffix = url.substr(url.lastIndexOf('.') + 1); // get just the : wav
var file_name = url.substr(url.lastIndexOf('/') + 1);
// When loaded decode the data
request.onload = function() {
console.log("... onload triggered");
// decode the data
audio_context.decodeAudioData(request.response, function(buffer) {
// console.log('mp3 ... buffer.length ', buffer.length);
console.log(file_name, ' ... buffer.length ', buffer.length);
// ---
is_jam_happening = true;
// was_anything_stopped = false; // reset for any possible subsequent playback
play_sound(buffer, once_playback_starts_callback, given_mode, stop_callback);
// ---
}, on_error); // stens TODO - chase down why getting null error when attemping to decode filetype ogg / wav OK
};
gain_node.gain.value = 0.3;
// // --- enable volume control for output speakers
// document.getElementById('volume').addEventListener('change', function() {
// var curr_volume = this.value;
// gain_node.gain.value = curr_volume;
// console.log("curr_volume ", curr_volume);
// });
request.send();
console.log("onload ... should trigger momentarily");
} // load_sound
function get_was_anything_stopped() {
return was_anything_stopped;
}
function pause_jam_sound() {
source_node.disconnect();
}
function resume_jam_sound() {
source_node.connect(fft_analyzer);
source_node.connect(gain_node);
source_node.connect(script_processor_time_domain_node);
}
function stop_jam_sound() {
if (source_node) {
source_node.stop(0);
was_anything_stopped = true;
}
}
function play_sound(buffer, once_playback_starts_callback, given_mode, stop_callback) {
source_node.buffer = buffer;
source_node.start(0);
console.log("... just called start on source_node");
// // source_node.loop = true;
// source_node.loop = false;
// source_node.loopStart = 0;
// source_node.loopEnd = 0.1;
if (once_playback_starts_callback) {
console.log('OK do have once_playback_starts_callback so call it');
// execute callback --> do_another_sampling <-- when actually doing playback
// once_playback_starts_callback(given_mode);
once_playback_starts_callback(given_mode, stop_callback);
} else {
// console.log('BOO HOO do NOT have once_playback_starts_callback so ignore it');
}
}
// log if an error occurs
function on_error(e) {
console.log(e);
}
function on_visibility_change() {
if (document.Hidden) {
console.log('window tab is now hidden');
}
}
function setup_fft(flag_loop) {
setup_audio_nodes(flag_loop);
script_processor_audio_file_node.onaudioprocess = function() {
// get the average for the first channel
var array = new Uint8Array(fft_analyzer.frequencyBinCount);
fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram
if (source_node.playbackState == source_node.PLAYING_STATE) {
audio_display_obj.update_one_row(array);
}
};
}
// ---
function do_mute() { // bbb
console.log('inside do_mute');
// gain_node.disconnect();
gain_node.gain.value = 0.0;
}
function un_mute() {
// gain_node.connect(audio_context.destination); // Connect gain node to speakers
console.log('inside un_mute');
audio_context.resume();
gain_node.gain.value = 1.0;
}
// ----
/*
function main_glob() {
console.log('inside main_glob');
// Web Audio API uses 32-bit signed floats from -1.0 to 1.0
// legal range from 256 <--> 16384 :
// 256, 512, 1024, 2048, 4096, 8192, or 16384
// var MAX_FREQ = 300;
// var MIN_FREQ = 20;
// var increasing_freq_factor = 1.01;
// var decreasing_freq_factor = 0.98;
// var freq_factor = increasing_freq_factor;
var num_input_channels = 1;
var num_output_channels = 1;
var glob_script_processor_synth_node = audio_context.createScriptProcessor(BUFF_SIZE,
num_input_channels, num_output_channels);
// console.log("sample_rate retrieved from audio context is : ", sample_rate);
glob_script_processor_synth_node.MIN_FREQ = 20;
glob_script_processor_synth_node.MAX_FREQ = 300;
glob_script_processor_synth_node.sample_freq = glob_script_processor_synth_node.MIN_FREQ;// Hertz
glob_script_processor_synth_node.BUFF_SIZE = BUFF_SIZE;
glob_script_processor_synth_node.sample_rate = audio_context.sampleRate / (2 * Math.PI); // sample rate
glob_script_processor_synth_node.decreasing_freq_factor = 0.98;
glob_script_processor_synth_node.increasing_freq_factor = 1.01;
glob_script_processor_synth_node.freq_factor = glob_script_processor_synth_node.increasing_freq_factor;
glob_script_processor_synth_node.onaudioprocess = (function () {
return function (event) {
if (allow_synth) {
// console.log('inside main_glob callback onaudioprocess BUFF_SIZE ', BUFF_SIZE);
var synthesized_output_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
synthesized_output_buffer = event.outputBuffer.getChannelData(0); // stens TODO - do both channels not just left
var phi = 0, dphi = 2.0 * Math.PI * glob_script_processor_synth_node.sample_freq /
glob_script_processor_synth_node.sample_rate;
for (var curr_sample = 0; curr_sample < glob_script_processor_synth_node.BUFF_SIZE;
curr_sample++, phi += dphi) {
synthesized_output_buffer[curr_sample] = Math.sin(phi);
}
glob_script_processor_synth_node.sample_freq *= glob_script_processor_synth_node.freq_factor;
if (glob_script_processor_synth_node.sample_freq <
glob_script_processor_synth_node.MIN_FREQ) {
glob_script_processor_synth_node.freq_factor = glob_script_processor_synth_node.increasing_freq_factor;
} else if (glob_script_processor_synth_node.sample_freq >
glob_script_processor_synth_node.MAX_FREQ) {
glob_script_processor_synth_node.freq_factor = glob_script_processor_synth_node.decreasing_freq_factor;
}
// ---
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
BUFF_SIZE, "providence_2");
}
};
}());
glob_script_processor_synth_node.connect(gain_node);
// --- setup FFT processing --- //
this.glob_script_processor_fft_node = audio_context.createScriptProcessor(2048, 1, 1);
this.glob_script_processor_fft_node.connect(gain_node);
console.log('\n\ncw + ss thursday 120 \n\n');
// setup a analyzer
var glob_fft_analyzer = audio_context.createAnalyser();
glob_fft_analyzer.smoothingTimeConstant = 0;
glob_fft_analyzer.fftSize = 1024;
glob_script_processor_synth_node.connect(glob_fft_analyzer);
glob_fft_analyzer.connect(this.glob_script_processor_fft_node);
// ---
this.glob_script_processor_fft_node.onaudioprocess = function () {
// get the average for the first channel
var array = new Uint8Array(glob_fft_analyzer.frequencyBinCount);
glob_fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram of FFT data in frequency domain onto spinning cylinder
if (glob_script_processor_synth_node.playbackState ==
glob_script_processor_synth_node.PLAYING_STATE) {
// console.log('update_one_row ... synth array length ', array.length);
audio_display_obj.update_one_row(array);
}
}
} // main_glob
*/
// ----
/*
function launch_synth() {
// Web Audio API uses 32-bit signed floats from -1.0 to 1.0
// legal range from 256 <--> 16384 :
// 256, 512, 1024, 2048, 4096, 8192, or 16384
// var MAX_FREQ = 10000;
// var MAX_FREQ = 1000;
var MAX_FREQ = 300;
var MIN_FREQ = 20;
// var increasing_freq_factor = 1.05;
// var decreasing_freq_factor = 0.95;
// console.log('MAX_FREQ ', MAX_FREQ);
var increasing_freq_factor = 1.01;
var decreasing_freq_factor = 0.98;
var freq_factor = increasing_freq_factor;
var num_input_channels = 1;
var num_output_channels = 1;
script_processor_synth_node = audio_context.createScriptProcessor(BUFF_SIZE,
num_input_channels, num_output_channels);
var sample_rate = audio_context.sampleRate / (2 * Math.PI); // retrieve default sample rate
// console.log("sample_rate retrieved from audio context is : ", sample_rate);
var sample_freq = MIN_FREQ; // Hertz - cycles per second
script_processor_synth_node.onaudioprocess = (function () {
return function (event) {
if (allow_synth) {
console.log('inside launch_synth callback onaudioprocess BUFF_SIZE ', BUFF_SIZE);
var synthesized_output_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
synthesized_output_buffer = event.outputBuffer.getChannelData(0); // stens TODO - do both channels not just left
var phi = 0, dphi = 2.0 * Math.PI * sample_freq / sample_rate;
for (var curr_sample = 0; curr_sample < BUFF_SIZE; curr_sample++, phi += dphi) {
synthesized_output_buffer[curr_sample] = Math.sin(phi);
}
sample_freq *= freq_factor;
if (sample_freq < MIN_FREQ) {
freq_factor = increasing_freq_factor;
} else if (sample_freq > MAX_FREQ) {
freq_factor = decreasing_freq_factor;
}
// ---
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
BUFF_SIZE, "providence_2");
}
};
}());
script_processor_synth_node.connect(gain_node);
// --- setup FFT processing --- //
script_processor_fft_node = audio_context.createScriptProcessor(2048, 1, 1);
script_processor_fft_node.connect(gain_node);
// setup a analyzer
fft_analyzer = audio_context.createAnalyser();
fft_analyzer.smoothingTimeConstant = 0;
fft_analyzer.fftSize = 1024;
script_processor_synth_node.connect(fft_analyzer);
fft_analyzer.connect(script_processor_fft_node);
// ---
script_processor_fft_node.onaudioprocess = function () {
// get the average for the first channel
var array = new Uint8Array(fft_analyzer.frequencyBinCount);
fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram of FFT data in frequency domain onto spinning cylinder
if (script_processor_synth_node.playbackState == script_processor_synth_node.PLAYING_STATE) {
// console.log('update_one_row ... synth array length ', array.length);
audio_display_obj.update_one_row(array);
}
}
} // launch_synth
*/
// --------------------------------- setup microphone ------------------------------------ //
function show_some_data(given_typed_array, num_row_to_display, label) {
var size_buffer = given_typed_array.length;
var index = 0;
var max_index = num_row_to_display;
console.log("__________ " + label);
for (; index < max_index && index < size_buffer; index += 1) {
console.log(given_typed_array[index]);
}
}
var is_microphone_recording = false;
function process_microphone_buffer(event) {
var i, N, inp, microphone_output_buffer;
microphone_output_buffer = event.inputBuffer.getChannelData(0); // stens TODO - do both channels not just left
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(microphone_output_buffer,
microphone_output_buffer.length, "providence_3");
}
function start_microphone() { // stens TODO - verify fft works for microphone
// setup js processor
microphone_data.microphone_stream = audio_context.createMediaStreamSource(microphone_data.media_stream);
microphone_data.microphone_stream.connect(gain_node);
microphone_data.script_processor_node = audio_context.createScriptProcessor(BUFF_SIZE, 1, 1);
microphone_data.script_processor_node.onaudioprocess = process_microphone_buffer;
microphone_data.microphone_stream.connect(microphone_data.script_processor_node);
// microphone_data.script_processor_node.connect(microphone_data.fft_analyzer);
// --- setup FFT
microphone_data.script_processor_fft_node = audio_context.createScriptProcessor(2048, 1, 1);
microphone_data.script_processor_fft_node.connect(gain_node);
microphone_data.fft_analyzer = audio_context.createAnalyser();
microphone_data.fft_analyzer.smoothingTimeConstant = 0;
microphone_data.fft_analyzer.fftSize = 2048;
microphone_data.fft_analyzer.connect(microphone_data.script_processor_fft_node);
// get input media stream
console.log('OK microphone stream connected');
// ---
microphone_data.script_processor_fft_node.onaudioprocess = function() {
// get the average for the first channel
var array = new Uint8Array(microphone_data.fft_analyzer.frequencyBinCount);
microphone_data.fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram of FFT data in frequency domain onto spinning cylinder
if (microphone_data.microphone_stream.playbackState ==
microphone_data.microphone_stream.PLAYING_STATE) {
show_some_data(array, 50, "from fft");
audio_display_obj.update_one_row(array); // show another row on FFT display
}
};
is_microphone_recording = true;
was_anything_stopped = false; // reset for any possible subsequent playback
} // start_microphone
function stop_microphone() {
microphone_data.microphone_stream.disconnect();
microphone_data.script_processor_node.disconnect();
microphone_data.media_stream.stop();
microphone_data.script_processor_node.onaudioprocess = null;
was_anything_stopped = true;
console.log('... microphone now stopped');
}
function record_microphone() {
// audio_context
if (!navigator.getUserMedia) {
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
}
navigator.getUserMedia(
{
audio: true
},
function(stream) {
microphone_data.media_stream = stream;
start_microphone();
},
on_error
);
}
// --------------------------------- end of microphone ---------------------------------- //
function play_jam_N_do_sample(given_mode) {
inner_play_tune_jam(do_another_sampling, given_mode, stop_jam_sound);
}
var is_jam_happening = false;
function play_tune_jam(flag_loop) {
switch (flag_loop) {
case 1:
{
console.log('... OK no jam loop just play once ');
// source_node.loop = false;
inner_play_tune_jam(null, null, null, false);
break;
}
case 2:
{
console.log('... OK loop jam to play endlessly ... ');
inner_play_tune_jam(null, null, null, true);
break;
}
case 3:
{
console.log('render syn wav buffer directly');
// inner_play_tune_jam(null, null, null, true);
setup_fft(true);
var synthesized_wav_obj = {};
render_wav_obj.get_wav_buffer(synthesized_wav_obj);
console.log('size of synth wav buffer ', synthesized_wav_obj.buffer.length);
source_node.buffer = synthesized_wav_obj.buffer;
source_node.start(0);
break;
}
// --- default
break;
}
}
function inner_play_tune_jam(once_playback_starts_callback, given_mode, stop_callback, flag_loop) {
setup_fft(flag_loop);
// wav
// var chosen_audio_file = "Justice_Genesis_chewy_chocolate_cookies_gtZunGHG0ls_mono_30_seconds.mp3";
// var chosen_audio_file = "Justice_Genesis_chewy_chocolate_cookies_gtZunGHG0ls_mono.ogg";
// var chosen_audio_file = "Lee_Smolin_Physics_Envy_and_Economic_Theory-cWn86ESze6M_mono_1st_few_seconds.mp3";
// var chosen_audio_file = "Lee_Smolin_Physics_Envy_and_Economic_Theory-cWn86ESze6M_mono_tiny_snip.mp3";
// var chosen_audio_file = "Elephant_sounds_rgUFu_hVhlk_roar_mono_clip01.wav";
// var chosen_audio_file = "Ida_Corr_Fedde_Le_Grand_Let_Me_Think_About_It-19WUwZYM7bM.wav";
// var chosen_audio_file = "Justice_Genesis_chewy_chocolate_cookies_gtZunGHG0ls_mono.ogg";
// var chosen_audio_file = "../media/Ida_Corr_Fedde_Le_Grand_Let_Me_Think_About_It-19WUwZYM7bM.wav";
// var chosen_audio_file = "Chopin_Fantasie_Impromptu_opus_66-APQ2RKECMW8.wav";
// var chosen_audio_file = "Chopin_Fantasie_Impromptu_opus_66-APQ2RKECMW8.ogg";
// var chosen_audio_file = "Chopin_Fantasie_Impromptu_opus_66-APQ2RKECMW8_mono.wav";
// var chosen_audio_file = "Chopin_Fantasie_Impromptu_opus_66-APQ2RKECMW8_mono_8000_16.wav";
var chosen_audio_file = "Justice_Genesis_mono-y6iHYTjEyKU.wav";
// var chosen_audio_file = "pyramid.ogg";
// Stradivari viola
// var chosen_audio_file = "Viola_16_Jay_Haide_a_L_Ancienne_Stradivari-H4ri4jE14cE.mp3";
// var chosen_audio_file = "Elephant_sounds_rgUFu_hVhlk_roar_mono_tiny.wav";
console.log('chosen_audio_file ', chosen_audio_file);
// source_node.loop = flag_loop;
load_sound(chosen_audio_file, once_playback_starts_callback, given_mode, stop_callback);
was_anything_stopped = false; // reset for any possible subsequent playback
}
// console.log('\n\ncw + ss thursday 41999 \n\n');
function render_audio_buffer(render_this_buffer, render_size_buffer, done_callback) {
console.log('TOP of render_audio_buffer render_size_buffer', render_size_buffer,
' BUFF_SIZE ', BUFF_SIZE);
// ---
// setup_fft();
// ---
var script_processor_synth_from_sample_node;
script_processor_synth_from_sample_node = audio_context.createScriptProcessor(BUFF_SIZE, 1, 1);
var curr_index_synth_buffer = 0; // keep playing until this reaches size of synth buffer
// var last_time = new Date().getTime();
script_processor_synth_from_sample_node.onaudioprocess = (function() {
return function(event) {
var synthesized_output_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
synthesized_output_buffer = event.outputBuffer.getChannelData(0); // stens TODO - do both channels not just left
for (var curr_sample = 0; curr_sample < BUFF_SIZE; curr_sample++) {
synthesized_output_buffer[curr_sample] = render_this_buffer[curr_index_synth_buffer];
curr_index_synth_buffer++;
if (curr_index_synth_buffer >= render_size_buffer) {
// console.log('\n\ncw + ss thursday 419 \n\n');
if (script_processor_synth_from_sample_node) {
script_processor_synth_from_sample_node.disconnect(gain_node);
script_processor_synth_from_sample_node = null;
}
// ---
done_callback();
// console.log('render DONE curr_index_synth_buffer ', curr_index_synth_buffer);
}
}
// ---
// console.log('render_audio_buffer sending pipeline_buffer_for_time_domain_cylinder...');
// audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
// BUFF_SIZE, "providence_1");
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
BUFF_SIZE, "providence_1");
};
}());
// ---
script_processor_synth_from_sample_node.connect(gain_node);
/*
// --- setup FFT processing --- //
script_processor_fft_node = audio_context.createScriptProcessor(2048, 1, 1);
script_processor_fft_node.connect(gain_node);
// setup a analyzer
fft_analyzer = audio_context.createAnalyser();
fft_analyzer.smoothingTimeConstant = 0;
fft_analyzer.fftSize = 1024;
script_processor_synth_from_sample_node.connect(fft_analyzer);
fft_analyzer.connect(script_processor_fft_node);
// ---
script_processor_fft_node.onaudioprocess = function () {
// get the average for the first channel
var array = new Uint8Array(fft_analyzer.frequencyBinCount);
fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram of FFT data in frequency domain onto spinning cylinder
// if (script_processor_synth_from_sample_node.playbackState == script_processor_synth_from_sample_node.PLAYING_STATE) {
if (script_processor_synth_from_sample_node && script_processor_synth_from_sample_node.playbackState == script_processor_synth_from_sample_node.PLAYING_STATE) {
// console.log('update_one_row ... synth array length ', array.length);
audio_display_obj.update_one_row(array);
}
}
*/
} // render_audio_buffer
var in_middle_of_playback = false;
function set_false_in_middle_of_playback() {
in_middle_of_playback = false;
// console.log('just set false to in_middle_of_playback');
}
function render_buffer(given_flavor) {
// console.log('\n\ncw + ss thursday 310 \n\n');
if (true === in_middle_of_playback) {
console.log('currently in MIDDLE of a playback try later ...');
return;
}
console.log('launching playback in render_buffer in MIDDLE of playback given_flavor ', given_flavor);
// var local_buffer = audio_process_obj.get_buffer(given_flavor);
// var size_buffer = audio_process_obj.get_size_buffer(given_flavor);
var desired_buffer_obj = audio_process_obj.get_buffer(given_flavor);
// if (desired_buffer_obj && desired_buffer_obj.buffer) {
if (desired_buffer_obj) {
console.log('!!!!!!! !!!!!!! OK about to playback buffer given_flavor ', given_flavor);
// stens TODO - drill in to see if below is or can be async to followup audio rendering
/*
if (3 == given_flavor) { // elephant roar
console.log('about to send ELEPHANT Roar to server side size ',
desired_buffer_obj.buffer.length);
// communication_sockets_obj.socket_client(3, desired_buffer_obj.buffer);
communication_sockets_obj.socket_client(3, desired_buffer_obj);
} else {
console.log('about to send ELEPHANT Roar to server side size ',
desired_buffer_obj.buffer.length);
communication_sockets_obj.socket_client(3, desired_buffer_obj.buffer);
}
*/
// ---
switch (given_flavor) {
case 3:
{
console.log('about to send ELEPHANT Roar to server side size ',
desired_buffer_obj.buffer.length);
// communication_sockets_obj.socket_client(3, desired_buffer_obj.buffer);
communication_sockets_obj.socket_client(3, desired_buffer_obj);
// ---
in_middle_of_playback = true;
// ---
var this_glob_02 = audio_context.createScriptProcessor(BUFF_SIZE, 1, 1);
// init_synth_settings(this_glob_02);
setup_onaudioprocess_callback_render(this_glob_02, desired_buffer_obj.buffer,
desired_buffer_obj.size, set_false_in_middle_of_playback);
followup_fft(this_glob_02);
// ---
break;
}
case 4:
{
console.log('about to send genetic synth to server side size ',
desired_buffer_obj.size_buffer);
communication_sockets_obj.socket_client(4, desired_buffer_obj);
break;
}
// --- default
console.error("ERROR - failed to match given_flavor ", given_flavor);
break;
}
// ---
} else {
console.log('no playback buffer available');
}
} // render_buffer
function do_another_sampling(given_mode, stop_callback) {
if (allow_synth) {
// vvv
// audio_process_obj.take_another_sample(); // stens TODO pass callback here to call stop_synth()
audio_process_obj.take_another_sample(stop_synth, given_mode); // stens TODO pass callback here to call stop_synth()
// console.log(' since sample is DONE now stop synth');
// stop_synth(); // IMPORTANT cannot put here called too soon
} else if (is_jam_happening) {
// audio_process_obj.take_another_sample(null, given_mode);
audio_process_obj.take_another_sample(stop_callback, given_mode);
} else if (is_microphone_recording) {
audio_process_obj.take_another_sample(null, given_mode); // microphone gets sampled
} else {
console.log('cannot since not currently synthesizing audio');
}
}
function init_synth_settings_ignore(given_node) {
given_node.MIN_FREQ = 20;
given_node.MAX_FREQ = 300;
given_node.sample_freq = given_node.MIN_FREQ; // Hertz
given_node.BUFF_SIZE = BUFF_SIZE;
given_node.sample_rate = audio_context.sampleRate / (2 * Math.PI); // sample rate
given_node.decreasing_freq_factor = 0.98;
given_node.increasing_freq_factor = 1.01;
given_node.freq_factor = given_node.increasing_freq_factor;
}
function init_synth_settings(given_node, g_MIN_FREQ, g_MAX_FREQ, g_BUFF_SIZE, g_decreasing_freq_factor, g_increasing_freq_factor) {
given_node.MIN_FREQ = g_MIN_FREQ;
given_node.MAX_FREQ = g_MAX_FREQ;
given_node.sample_freq = given_node.MIN_FREQ; // Hertz
given_node.BUFF_SIZE = g_BUFF_SIZE;
given_node.sample_rate = audio_context.sampleRate / (2 * Math.PI); // sample rate
given_node.decreasing_freq_factor = g_decreasing_freq_factor;
given_node.increasing_freq_factor = g_increasing_freq_factor;
given_node.freq_factor = g_increasing_freq_factor;
}
function setup_onaudioprocess_callback(given_node) {
given_node.onaudioprocess = (function() {
return function(event) {
if (allow_synth) {
// console.log('inside main_glob callback onaudioprocess BUFF_SIZE ', BUFF_SIZE);
var synthesized_output_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
synthesized_output_buffer = event.outputBuffer.getChannelData(0); // stens TODO - do both channels not just left
var phi = 0,
dphi = 2.0 * Math.PI * given_node.sample_freq /
given_node.sample_rate;
for (var curr_sample = 0; curr_sample < given_node.BUFF_SIZE; curr_sample++, phi += dphi) {
synthesized_output_buffer[curr_sample] = Math.sin(phi);
}
given_node.sample_freq *= given_node.freq_factor;
if (given_node.sample_freq <
given_node.MIN_FREQ) {
given_node.freq_factor = given_node.increasing_freq_factor;
} else if (given_node.sample_freq > given_node.MAX_FREQ) {
given_node.freq_factor = given_node.decreasing_freq_factor;
}
// ---
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
BUFF_SIZE, "providence_2");
}
};
}());
}
function setup_onaudioprocess_callback_render(given_node, render_this_buffer, render_size_buffer, done_callback) {
var curr_index_synth_buffer = 0; // keep playing until this reaches size of synth buffer
given_node.onaudioprocess = (function() {
return function(event) {
var synthesized_output_buffer;
// stens TODO - how to pass in own buffer instead of being given object: out so I can do a circular ring of such buffers
synthesized_output_buffer = event.outputBuffer.getChannelData(0); // stens TODO - do both channels not just left
for (var curr_sample = 0; curr_sample < BUFF_SIZE; curr_sample++) {
synthesized_output_buffer[curr_sample] = render_this_buffer[curr_index_synth_buffer];
curr_index_synth_buffer++;
if (curr_index_synth_buffer >= render_size_buffer) {
// console.log('\n\ncw + ss thursday 434 \n\n');
if (given_node) {
given_node.disconnect(gain_node);
given_node = null;
console.log('just called disconnect on node attached to this callback ');
}
// ---
done_callback();
// console.log('render DONE curr_index_synth_buffer ', curr_index_synth_buffer);
}
}
// ---
// console.log('render_audio_buffer sending pipeline_buffer_for_time_domain_cylinder...');
// audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
// BUFF_SIZE, "providence_1");
audio_display_obj.pipeline_buffer_for_time_domain_cylinder(synthesized_output_buffer,
BUFF_SIZE, "providence_1");
};
}());
// do_engage(given_node);
} // setup_onaudioprocess_callback_render
function followup_fft(given_node) {
given_node.connect(gain_node);
// --- setup FFT processing --- //
var glob_script_processor_fft_node = audio_context.createScriptProcessor(2048, 1, 1);
glob_script_processor_fft_node.connect(gain_node);
// console.log('\n\ncw + ss thursday 428 \n\n');
// setup a analyzer
var glob_fft_analyzer = audio_context.createAnalyser();
glob_fft_analyzer.smoothingTimeConstant = 0;
glob_fft_analyzer.fftSize = 1024;
// glob_fft_analyzer.fftSize = 2048;
given_node.connect(glob_fft_analyzer);
glob_fft_analyzer.connect(glob_script_processor_fft_node);
// ---
glob_script_processor_fft_node.onaudioprocess = function() {
// get the average for the first channel
var array = new Uint8Array(glob_fft_analyzer.frequencyBinCount);
glob_fft_analyzer.getByteFrequencyData(array);
// draw the spectrogram of FFT data in frequency domain onto spinning cylinder
if (given_node.playbackState ==
given_node.PLAYING_STATE) {
// console.log('update_one_row ... synth array length ', array.length);
audio_display_obj.update_one_row(array); // show another row on FFT display
}
};
} // followup_fft
function run_synth() {
if (false === allow_synth) {
allow_synth = true;
// launch_synth();
// main_glob();
var this_glob_01 = audio_context.createScriptProcessor(BUFF_SIZE, 1, 1);
// init_synth_settings(this_glob_01);
// (given_node, g_MIN_FREQ, g_MAX_FREQ, g_BUFF_SIZE, g_decreasing_freq_factor, g_increasing_freq_factor) {
init_synth_settings(this_glob_01, 20, 300, BUFF_SIZE, 0.98, 1.01);
setup_onaudioprocess_callback(this_glob_01);
followup_fft(this_glob_01);
was_anything_stopped = false; // reset for any possible subsequent playback
} else {
console.log('we are already running synth');
}
}
function stop_synth() {
console.log('top of stop_synth ...........');
allow_synth = false;
was_anything_stopped = true;
}
function pause_tune() {
console.log("inside pause_tune ");
}
return { // to make visible to calling reference frame list function here
// load the sound
init_context_audio: init_context_audio,
play_tune_jam: play_tune_jam,
run_synth: run_synth,
pause_tune: pause_tune,
do_another_sampling: do_another_sampling,
record_microphone: record_microphone,
stop_microphone: stop_microphone,
stop_synth: stop_synth,
stop_jam_sound: stop_jam_sound,
render_buffer: render_buffer,
get_was_anything_stopped: get_was_anything_stopped,
pause_jam_sound: pause_jam_sound,
resume_jam_sound: resume_jam_sound,
play_jam_N_do_sample: play_jam_N_do_sample,
do_mute: do_mute,
un_mute: un_mute
};
}(); // webaudio_tooling_obj = function()