# HG changeset patch # User Chris Cannam # Date 1355529622 0 # Node ID 0ddc2aa8885da765c5575a4f12341065cec81935 # Parent ff66f7df30bf379844fee76c62f14e097900c0e2 Pull out channel mixers to new file, add synthetic streams, start on playback diff -r ff66f7df30bf -r 0ddc2aa8885d audiofile.yeti --- a/audiofile.yeti Fri Dec 14 10:20:00 2012 +0000 +++ b/audiofile.yeti Sat Dec 15 00:00:22 2012 +0000 @@ -10,6 +10,7 @@ import java.nio: ByteBuffer, ByteOrder; mat = load fmatrix; +ch = load channels; decode8u bytes doubles n is ~byte[] -> ~double[] -> number -> () = (for [0..n-1] do i: @@ -70,13 +71,13 @@ read' { format is ~AudioFormat, stream is ~AudioInputStream } n = (doubles = readInterleaved' { format, stream } n; channels = format#getChannels(); - mat.deinterleaved channels doubles; + ch.deinterleaved channels doubles; ); readMono' { format is ~AudioFormat, stream is ~AudioInputStream } n = (doubles = readInterleaved' { format, stream } n; channels = format#getChannels(); - mat.mixedDownFromInterleaved channels doubles; + ch.mixedDownFromInterleaved channels doubles; ); // Note, all this assumes the stream is non-blocking (i.e. available() diff -r ff66f7df30bf -r 0ddc2aa8885d channels.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/channels.yeti Sat Dec 15 00:00:22 2012 +0000 @@ -0,0 +1,68 @@ + +module channels; + +vec = load fvector; +mat = load fmatrix; + +interleaved m = + ({ cols, rows } = mat.dimensions m; + v = vec.zeros (cols * rows); + for [0..rows-1] do row: + for [0..cols-1] do col: + v[col * rows + row] := m[row][col]; + done; + done; + v); + +deinterleaved rows v is number -> ~double[] -> array<~double[]> = + mat.generateMatrix do row col: + v[rows * col + row] + done rows ((vec.vectorLength v) / rows); + +mixedDown m = + (if empty? m then vec.zeros 0 else + { cols, rows } = mat.dimensions m; + v = vec.copyOfVector m[0]; + for [1..rows-1] do row: + for [0..cols-1] do col: + v[col] := v[col] + m[row][col]; + done; + done; + v; + fi); + +mixedDownFromInterleaved rows v is number -> ~double[] -> ~double[] = + (cols = ((vec.vectorLength v) / rows); + v' = vec.zeros cols; + for [0..rows-1] do row: + for [0..cols-1] do col: + v'[col] := v'[col] + v[col * rows + row]; + done; + done; + v'); + +mixedFromInterleavedTo targetRows rows v is number -> number -> ~double[] -> ~double[] = + if targetRows == rows then + v; + elif targetRows == 1 then + mixedDownFromInterleaved rows v; + else + cols = ((vec.vectorLength v) / rows); + v' = vec.zeros (cols * targetRows); + for [0..targetRows-1] do target: + for [0..cols-1] do col: + if target < rows then + v'[col * targetRows + target] := v[col * rows + target]; + elif rows == 1 then + v'[col * targetRows + target] := v[col * rows]; + fi + done + done; + v'; + fi; + +{ + interleaved, deinterleaved, + mixedDown, mixedDownFromInterleaved, mixedFromInterleavedTo, +} + diff -r ff66f7df30bf -r 0ddc2aa8885d fmatrix.yeti --- a/fmatrix.yeti Fri Dec 14 10:20:00 2012 +0000 +++ b/fmatrix.yeti Sat Dec 15 00:00:22 2012 +0000 @@ -29,49 +29,11 @@ transposed m is array<~double[]> -> array<~double[]> = generateMatrix do row col: m[col][row] done (cols m) (rows m); - -interleaved m = - ({ cols, rows } = dimensions m; - v = vec.zeros (cols * rows); - for [0..rows-1] do row: - for [0..cols-1] do col: - v[col * rows + row] := m[row][col]; - done; - done; - v); - -deinterleaved rows v is number -> ~double[] -> array<~double[]> = - generateMatrix do row col: - v[rows * col + row] - done rows ((vec.vectorLength v) / rows); - -mixedDown m = - (if empty? m then vec.zeros 0 else - { cols, rows } = dimensions m; - v = vec.copyOfVector m[0]; - for [1..rows-1] do row: - for [0..cols-1] do col: - v[col] := v[col] + m[row][col]; - done; - done; - v; - fi); - -mixedDownFromInterleaved rows v is number -> ~double[] -> ~double[] = - (cols = ((vec.vectorLength v) / rows); - v' = vec.zeros cols; - for [0..rows-1] do row: - for [0..cols-1] do col: - v'[col] := v'[col] + v[col * rows + row]; - done; - done; - v'); { generateMatrix, constMatrix, randomMatrix, zeroMatrix, identityMatrix, width, cols, height, rows, dimensions, copyOfMatrix, -transposed, interleaved, deinterleaved, -mixedDown, mixedDownFromInterleaved, +transposed, } diff -r ff66f7df30bf -r 0ddc2aa8885d playback.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playback.yeti Sat Dec 15 00:00:22 2012 +0000 @@ -0,0 +1,52 @@ + +module playback; + +vec = load fvector; +fr = load framer; +af = load audiofile; +ch = load channels; + +import javax.sound.sampled: + AudioSystem, AudioFormat, AudioFormat$Encoding, SourceDataLine; + +import java.nio: ByteBuffer, ByteOrder; + +open rate channels = + (format = new AudioFormat(AudioFormat$Encoding#PCM_SIGNED, rate, 16, + channels, channels * 2, rate, false); + line = AudioSystem#getSourceDataLine(format); + line#open(format); + line#start(); + { + line, + channels = line#getFormat()#getChannels(), + close () = line#close(), + }); + +play { line is ~SourceDataLine } samples = + (len = vec.vectorLength samples; + nb = len * 2; + bytes = new byte[nb]; + bb = ByteBuffer#wrap(bytes, 0, nb); + bb#order(ByteOrder#LITTLE_ENDIAN); + sb = bb#asShortBuffer(); + for [0..len-1] do i: sb#put(i, samples[i] * 32767.0); () done; + println "writing \(nb) bytes"; + actual = line#write(bytes, 0, nb); + ()); + +playStream stream = + (line = open stream.sampleRate stream.channels; + blocksize = 10240; + frames = fr.frames blocksize stream; + for frames do frame: + play line (ch.mixedFromInterleavedTo line.channels stream.channels frame) + done; + line.close()); + +playFile filename = playStream (af.open filename); + +{ + open, play, playStream, playFile, +} + diff -r ff66f7df30bf -r 0ddc2aa8885d syntheticstream.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/syntheticstream.yeti Sat Dec 15 00:00:22 2012 +0000 @@ -0,0 +1,44 @@ + +module syntheticstream; + +vec = load fvector; + +monoStream generator rate seconds = + (n = seconds * rate; + box = { + var position = 0, + readInterleaved count = + (rc = if position + count > n then n - position else count fi; + result = vec.zeros rc; + for [0..rc-1] do i: + result[i] := generator ((position + i) / rate) + done; + position := position + rc; + result), + get available () = n - position, + }; + { + box, + get channels () = 1, + get sampleRate () = rate, + get available () = box.available, + get finished? () = n <= box.position, + readInterleaved = box.readInterleaved, + read = box.readInterleaved, + readMono = box.readInterleaved, + readAll () = box.readInterleaved box.available, + readAllInterleaved () = box.readInterleaved box.available, + readAllMono () = box.readInterleaved box.available, + close = id, + }); + +sinusoid freq rate = + monoStream (sin . (* (freq / (2*pi * rate)))) rate; + +whiteNoise = + monoStream \((Math#random() * 2.0) - 1.0); + +{ + monoStream, sinusoid, whiteNoise, +} +