<commit_before>/**
 * Object that we can throw audio data into and have it drain out.
 *
 * @todo better timing!
 * @todo resample input
 */
function AudioFeeder(channels, rate) {
	// assume W3C Audio API
	
	var AudioContext = window.AudioContext || window.webkitAudioContext;
	if (!AudioContext) {
		// use Flash fallback
		console.log("No W3C Web Audio API available");
		this.flashaudio = new DynamicAudio();
	}
	

	var bufferSize = 1024;

	function freshBuffer() {
		var buffer = [];
		for (var channel = 0; channel < channels; channel++) {
			buffer[channel] = new Float32Array(bufferSize);
		}
		return buffer;
	}
	
	var buffers = [],
		context,
		node,
		pendingBuffer = freshBuffer(),
		pendingPos = 0,
		muted = false;

	if(AudioContext) {
		context = new AudioContext;
		if (context.createScriptProcessor) {
			node = context.createScriptProcessor(bufferSize, 0, channels)
		} else if (context.createJavaScriptNode) {
			node = context.createJavaScriptNode(bufferSize, 0, channels)
		} else {
			throw new Error("Bad version of web audio API?");
		}
	}
	
	function popNextBuffer() {
		// hack hack
		// fixme: grab the right number of samples
		// and... rescale 
		if (buffers.length > 0) {
			return buffers.shift();
		}
	}

	if(node) {
		node.onaudioprocess = function(event) {
			var inputBuffer = popNextBuffer(bufferSize);
			if (!muted && inputBuffer) {
				for (var channel = 0; channel < channels; channel++) {
					var input = inputBuffer[channel],
						output = event.outputBuffer.getChannelData(channel);
					for (var i = 0; i < Math.min(bufferSize, input.length); i++) {
						output[i] = input[i];
					}
				}
			} else {
				if (!inputBuffer) {
					console.log("Starved for audio!");
				}
				for (var channel = 0; channel < channels; channel++) {
					var output = event.outputBuffer.getChannelData(channel);
					for (var i = 0; i < bufferSize; i++) {
						output[i] = 0;
					}
				}
			}
		};
		node.connect(context.destination);
	}
	
	/**
	 * This is horribly naive and wrong.
	 * Replace me with a better algo!
	 */
	function resample(samples) {
		var targetRate = context.sampleRate;
		if (rate == targetRate) {
			return samples;
		} else {
			var newSamples = [];
			for (var channel = 0; channel < channels; channel++) {
				var input = samples[channel],
					output = new Float32Array(Math.round(input.length * targetRate / rate));
				for (var i = 0; i < output.length; i++) {
					output[i] = input[Math.floor(i * rate / targetRate)];
				}
				newSamples.push(output);
			}
			return newSamples;
		}
	}

	/**
	 * Resampling, scaling and reordering for the Flash fallback.
	 * The Flash fallback expects 44.1 kHz, stereo
	 * Resampling: This is horribly naive and wrong.
	 * TODO: Replace me with a better algo!
	 * TODO: Convert mono audio to stereo
	 */
	function resampleFlash(samples) {
		var sampleincr = rate / 44100;
		var samplecount = Math.floor(samples[0].length * (44100 / rate));
		var newSamples = new Array(samplecount * channels);
		for(var s = 0; s < samplecount; s++) {
			var idx = Math.floor(s * sampleincr);
			for(var c = 0; c < channels; ++c) {
				newSamples[(s * channels) + c] = Math.floor(samples[c][idx] * 32768);
			}
		}
		return newSamples;
	}

	
	function pushSamples(samples) {
		var firstChannel = samples[0],
			sampleCount = firstChannel.length;
		for (var i = 0; i < sampleCount; i++) {
			for (var channel = 0; channel < channels; channel++) {
				pendingBuffer[channel][pendingPos] = samples[channel][i];
			}
			if (++pendingPos == bufferSize) {
				buffers.push(pendingBuffer);
				pendingPos = 0;
				pendingBuffer = freshBuffer();
			}
		}
	}
	
	var self = this;
	this.bufferData = function(samplesPerChannel) {
		if(this.flashaudio) {
			var resamples = resampleFlash(samplesPerChannel);
			var flashElement = this.flashaudio.flashElement;
			if(resamples.length > 0 && flashElement.write) {
				flashElement.write(resamples.join(' '));
			}<commit_msg>always generate stereo PCM for the Flash audio fallback (upconvert from mono if necessary)<commit_after>/**
 * Object that we can throw audio data into and have it drain out.
 *
 * @todo better timing!
 * @todo resample input
 */
function AudioFeeder(channels, rate) {
	// assume W3C Audio API
	
	var AudioContext = window.AudioContext || window.webkitAudioContext;
	if (!AudioContext) {
		// use Flash fallback
		console.log("No W3C Web Audio API available");
		this.flashaudio = new DynamicAudio();
	}
	

	var bufferSize = 1024;

	function freshBuffer() {
		var buffer = [];
		for (var channel = 0; channel < channels; channel++) {
			buffer[channel] = new Float32Array(bufferSize);
		}
		return buffer;
	}
	
	var buffers = [],
		context,
		node,
		pendingBuffer = freshBuffer(),
		pendingPos = 0,
		muted = false;

	if(AudioContext) {
		context = new AudioContext;
		if (context.createScriptProcessor) {
			node = context.createScriptProcessor(bufferSize, 0, channels)
		} else if (context.createJavaScriptNode) {
			node = context.createJavaScriptNode(bufferSize, 0, channels)
		} else {
			throw new Error("Bad version of web audio API?");
		}
	}
	
	function popNextBuffer() {
		// hack hack
		// fixme: grab the right number of samples
		// and... rescale 
		if (buffers.length > 0) {
			return buffers.shift();
		}
	}

	if(node) {
		node.onaudioprocess = function(event) {
			var inputBuffer = popNextBuffer(bufferSize);
			if (!muted && inputBuffer) {
				for (var channel = 0; channel < channels; channel++) {
					var input = inputBuffer[channel],
						output = event.outputBuffer.getChannelData(channel);
					for (var i = 0; i < Math.min(bufferSize, input.length); i++) {
						output[i] = input[i];
					}
				}
			} else {
				if (!inputBuffer) {
					console.log("Starved for audio!");
				}
				for (var channel = 0; channel < channels; channel++) {
					var output = event.outputBuffer.getChannelData(channel);
					for (var i = 0; i < bufferSize; i++) {
						output[i] = 0;
					}
				}
			}
		};
		node.connect(context.destination);
	}
	
	/**
	 * This is horribly naive and wrong.
	 * Replace me with a better algo!
	 */
	function resample(samples) {
		var targetRate = context.sampleRate;
		if (rate == targetRate) {
			return samples;
		} else {
			var newSamples = [];
			for (var channel = 0; channel < channels; channel++) {
				var input = samples[channel],
					output = new Float32Array(Math.round(input.length * targetRate / rate));
				for (var i = 0; i < output.length; i++) {
					output[i] = input[Math.floor(i * rate / targetRate)];
				}
				newSamples.push(output);
			}
			return newSamples;
		}
	}

	/**
	 * Resampling, scaling and reordering for the Flash fallback.
	 * The Flash fallback expects 44.1 kHz, stereo
	 * Resampling: This is horribly naive and wrong.
	 * TODO: Replace me with a better algo!
	 */
	function resampleFlash(samples) {
		var sampleincr = rate / 44100;
		var samplecount = Math.floor(samples[0].length * (44100 / rate));
		var newSamples = new Array(samplecount * channels);
		var channel1 = channels > 1 ? 1 : 0;
		for(var s = 0; s < samplecount; s++) {
			var idx = Math.floor(s * sampleincr);
			var idx_out = s * 2;
			newSamples[idx_out] = Math.floor(samples[0][idx] * 32768);
			newSamples[idx_out + 1] = Math.floor(samples[channel1][idx] * 32768);
		}
		return newSamples;
	}

	
	function pushSamples(samples) {
		var firstChannel = samples[0],
			sampleCount = firstChannel.length;
		for (var i = 0; i < sampleCount; i++) {
			for (var channel = 0; channel < channels; channel++) {
				pendingBuffer[channel][pendingPos] = samples[channel][i];
			}
			if (++pendingPos == bufferSize) {
				buffers.push(pendingBuffer);
				pendingPos = 0;
				pendingBuffer = freshBuffer();
			}
		}
	}
	
	var self = this;
	this.bufferData = function(samplesPerChannel) {
		if(this.flashaudio) {
			var resamples = resampleFlash(samplesPerChannel);
			var flashElement = this.flashaudio.flashElement;
			if(resamples.length > 0 && flashElement.write) {
				flashElement.write(resamples.join(' '));
			}
{'fraction_non_alphanumeric': 0.13115778944736184, 'fraction_numerical': 0.01350337584396099, 'mean_word_length': 3.232275132275132, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6770610', 'n_tokens_mistral': 3089, 'n_tokens_neox': 2520, 'n_words': 713}