<commit_before>/**
 * Object that we can throw audio data into and have it drain out.
 *
 * Because changing the number of channels on the fly is hard, hardcoding
 * to 2 output channels. That's also all we can do on IE with Flash output.
 *
 * @todo better timing!
 */
function AudioFeeder() {
	// assume W3C Audio API
	var self = this;
	
	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 = this.bufferSize = 4096,
		channels = 0, // call init()!
		rate = 0; // call init()!

	// Always create stereo output. For iOS we have to set this stuff up
	// before we've actually gotten the info from the codec because we
	// must initialize from a UI event. Bah!
	var outputChannels = 2;

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

	if(AudioContext) {
		context = new AudioContext;
		if (context.createScriptProcessor) {
			node = context.createScriptProcessor(bufferSize, 0, outputChannels)
		} else if (context.createJavaScriptNode) {
			node = context.createJavaScriptNode(bufferSize, 0, outputChannels)
		} else {
			throw new Error("Bad version of web audio API?");
		}
		var targetRate = this.targetRate = context.sampleRate;
	}
	
	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) {
			if (typeof event.playbackTime === "number") {
				playbackTimeAtBufferHead = event.playbackTime;
			} else if (typeof event.timeStamp === "number") {
				playbackTimeAtBufferHead = (event.timeStamp - Date.now()) / 1000 + context.currentTime;
			} else {
				console.log("Unrecognized AudioProgressEvent format, no playbackTime or timestamp");
			}
			var inputBuffer = popNextBuffer(bufferSize);
			if (!muted && inputBuffer) {
				bufferHead += (bufferSize / context.sampleRate);
				playbackTimeAtBufferHead += (bufferSize / context.sampleRate);
				for (var channel = 0; channel < outputChannels; 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 < outputChannels; 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) {
		if (rate == targetRate && channels == outputChannels) {
			return samples;
		} else {
			var newSamples = [];
			for (var channel = 0; channel < outputChannels; channel++) {
				var inputChannel = channel;
				if (channel >= channels) {
					inputChannel = 0;
				}
				var input = samples[inputChannel],
					output = new Float32Array(Math.round(input.length * targetRate / rate));
				for (var i = 0; i < output.length; i++) {
					output[i] = input[(i * rate / targetRate) | 0];
				}
				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 = (samples[0].length * (44100 / rate)) | 0;
		var newSamples = new Array(samplecount * 2);
		var channel1 = channels > 1 ? 1 : 0;
		for(var s = 0; s < samplecount; s++) {
			var idx = (s * sampleincr) | 0;
			var idx_out = s * 2;
			newSamples[idx_out] = (samples[0][idx] * 32768) | 0;
			newSamples[idx_out + 1] = (samples[channel1][idx] * 32768) | 0;
		}
		return newSamples;
	}

	function resampleFlashMuted(samples) {
		// if muted: generate fitting number of samples for audio clock
		var samplecount = (samples[0].length * (44100 / rate)) | 0;
		return new Array(samplecount * 2);
	}

	
	function pushSamples(samples) {
		var firstChannel = samples[0],
			sampleCount = firstChannel.length;
		for (var i = 0; i < sampleCount; i++) {
			for (var channel = 0; channel < outputChannels; channel++) {
				pendingBuffer[channel][pendingPos] = samples[channel][i];
			}
			if (++pendingPos == bufferSize) {
				buffers.push(pendingBuffer);
				pendingPos = 0;
				pendingBuffer = freshBuffer();
			}<commit_msg>make Flash resample code tiny bit more readable and perhaps a tiny bit faster<commit_after>/**
 * Object that we can throw audio data into and have it drain out.
 *
 * Because changing the number of channels on the fly is hard, hardcoding
 * to 2 output channels. That's also all we can do on IE with Flash output.
 *
 * @todo better timing!
 */
function AudioFeeder() {
	// assume W3C Audio API
	var self = this;
	
	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 = this.bufferSize = 4096,
		channels = 0, // call init()!
		rate = 0; // call init()!

	// Always create stereo output. For iOS we have to set this stuff up
	// before we've actually gotten the info from the codec because we
	// must initialize from a UI event. Bah!
	var outputChannels = 2;

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

	if(AudioContext) {
		context = new AudioContext;
		if (context.createScriptProcessor) {
			node = context.createScriptProcessor(bufferSize, 0, outputChannels)
		} else if (context.createJavaScriptNode) {
			node = context.createJavaScriptNode(bufferSize, 0, outputChannels)
		} else {
			throw new Error("Bad version of web audio API?");
		}
		var targetRate = this.targetRate = context.sampleRate;
	}
	
	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) {
			if (typeof event.playbackTime === "number") {
				playbackTimeAtBufferHead = event.playbackTime;
			} else if (typeof event.timeStamp === "number") {
				playbackTimeAtBufferHead = (event.timeStamp - Date.now()) / 1000 + context.currentTime;
			} else {
				console.log("Unrecognized AudioProgressEvent format, no playbackTime or timestamp");
			}
			var inputBuffer = popNextBuffer(bufferSize);
			if (!muted && inputBuffer) {
				bufferHead += (bufferSize / context.sampleRate);
				playbackTimeAtBufferHead += (bufferSize / context.sampleRate);
				for (var channel = 0; channel < outputChannels; 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 < outputChannels; 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) {
		if (rate == targetRate && channels == outputChannels) {
			return samples;
		} else {
			var newSamples = [];
			for (var channel = 0; channel < outputChannels; channel++) {
				var inputChannel = channel;
				if (channel >= channels) {
					inputChannel = 0;
				}
				var input = samples[inputChannel],
					output = new Float32Array(Math.round(input.length * targetRate / rate));
				for (var i = 0; i < output.length; i++) {
					output[i] = input[(i * rate / targetRate) | 0];
				}
				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 = (samples[0].length * (44100 / rate)) | 0;
		var newSamples = new Array(samplecount * 2);
		var chanLeft = samples[0];
		var chanRight = channels > 1 ? samples[1] : chanLeft;
		for(var s = 0; s < samplecount; s++) {
			var idx = (s * sampleincr) | 0;
			var idx_out = s * 2;
			newSamples[idx_out] = (chanLeft[idx] * 32768) | 0;
			newSamples[idx_out + 1] = (chanRight[idx] * 32768) | 0;
		}
		return newSamples;
	}

	function resampleFlashMuted(samples) {
		// if muted: generate fitting number of samples for audio clock
		var samplecount = (samples[0].length * (44100 / rate)) | 0;
		return new Array(samplecount * 2);
	}

	
	function pushSamples(samples) {
		var firstChannel = samples[0],
			sampleCount = firstChannel.length;
		for (var i = 0; i < sampleCount; i++) {
			for (var channel = 0; channel < outputChannels; channel++) {
				pendingBuffer[channel][pendingPos] = samples[channel][i];
			}
			if (++pendingPos == bufferSize) {
				buffers.push(pendingBuffer);
				pendingPos = 0;
				pendingBuffer = freshBuffer();
			}
{'fraction_non_alphanumeric': 0.12407886875124477, 'fraction_numerical': 0.016430989842660823, 'mean_word_length': 3.2483079526226732, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 9, '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': '5130330', 'n_tokens_mistral': 3799, 'n_tokens_neox': 3112, 'n_words': 966}