# HG changeset patch # User Chris Cannam # Date 1363773474 0 # Node ID 77d3292bbf12a334e1ad4cd2d93052a3af0373ea # Parent 6d6627fbbb7829186ba41be1e21f8a6e3356fa6a Reorganise files diff -r 6d6627fbbb78 -r 77d3292bbf12 audiofile.yeti --- a/audiofile.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ - -module audiofile; - -import javax.sound.sampled: - AudioSystem, AudioInputStream, AudioFormat, AudioFormat$Encoding, - UnsupportedAudioFileException; - -import java.io: File, IOException; - -import java.nio: ByteBuffer, ByteOrder; - -str = load stream; -ch = load channels; -block = load block; - -decode8u bytes doubles n is ~byte[] -> ~double[] -> number -> () = - (for [0..n-1] do i: - doubles[i] := (bytes[i] / 128.0) - 1.0; - done - ); - -decode16s bytes doubles n is ~byte[] -> ~double[] -> number -> () = - (bb = ByteBuffer#wrap(bytes, 0, n * 2); - bb#order(ByteOrder#LITTLE_ENDIAN); - for [0..n-1] do i: - doubles[i] := bb#getShort(i*2) / 32768.0; - done - ); - -decode32f bytes doubles n is ~byte[] -> ~double[] -> number -> () = - (bb = ByteBuffer#wrap(bytes, 0, n * 4); - bb#order(ByteOrder#LITTLE_ENDIAN); - for [0..n-1] do i: - doubles[i] := bb#getFloat(i*4); - done - ); - -decodeFail () = - throw new UnsupportedAudioFileException("File format not supported. Supported formats are 8-bit unsigned PCM, 16-bit signed little-endian PCM, or IEEE float"); - -decode { format is ~AudioFormat } bytes doubles n = - (if format#isBigEndian() then - decodeFail() - else - enc = format#getEncoding(); - bits = format#getSampleSizeInBits(); - if bits == 32 then - decode32f bytes doubles n; - elif bits == 16 and enc == AudioFormat$Encoding#PCM_SIGNED then - decode16s bytes doubles n; - elif bits == 8 and enc == AudioFormat$Encoding#PCM_UNSIGNED then - decode8u bytes doubles n; - else - decodeFail(); - fi - fi); - -readInterleaved' { format is ~AudioFormat, stream is ~AudioInputStream } nframes = - (channels = format#getChannels(); - bytesPerSample = format#getSampleSizeInBits() / 8; - bytes = new byte[nframes * channels * bytesPerSample]; - bytesRead = stream#read(bytes); - if bytesRead <= 0 then block.zeros 0; - else - n = int(bytesRead / bytesPerSample); - doubles = new double[n]; - decode { format } bytes doubles n; - block.block doubles; - fi; - ); - -read' { format is ~AudioFormat, stream is ~AudioInputStream } n = - (b = readInterleaved' { format, stream } n; - channels = format#getChannels(); - ch.deinterleaved channels b; - ); - -readMono' { format is ~AudioFormat, stream is ~AudioInputStream } n = - (b = readInterleaved' { format, stream } n; - channels = format#getChannels(); - ch.mixedDownFromInterleaved channels b; - ); - -// Note, all this assumes the stream is non-blocking (i.e. available() -// is to the end of file) - -available' { format is ~AudioFormat, stream is ~AudioInputStream } = - stream#available() / ((format#getSampleSizeInBits() / 8) * format#getChannels()); - -close' { stream is ~AudioInputStream } = - stream#close(); - -open name is string -> 'a = - try - f = new File(name); - stream = AudioSystem#getAudioInputStream(f); - format = stream#getFormat(); - len = available' { format, stream }; // at start of stream - Stream (str.stream { - stream, - format, - len, - rate = format#getSampleRate(), - channels = format#getChannels(), - get position () = len - available' { stream, format }, - get available () = available' { stream, format }, - read = read' { stream, format }, - readInterleaved = readInterleaved' { stream, format }, - readMono = readMono' { stream, format }, - close () = close' { stream }, - }); - catch Exception e: - Error "Failed to open audio file \"\(name)\": \(e)"; - yrt; - -{ - open -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 bin/yetilab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/yetilab Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,16 @@ +#!/bin/sh +MYDIR=`dirname $0` +YETII_DIR=../yetii +YETI_LIBDIR=${YETI_LIBDIR:=../yeti} +if [ ! -d "$YETI_LIBDIR" ]; then + YETI_LIBDIR=../other/yeti +fi +JVAMP_DIR=${JVAMP_DIR:=../jvamp} +YERTLE_DIR=${YERTLE_DIR:=../yertle} + +YETI_MODULE_SOURCE_PATH=${YETI_LIBDIR}/modules \ + LD_LIBRARY_PATH=$YETII_DIR:$JVAMP_DIR:$LD_LIBRARY_PATH \ + $JAVA_HOME/bin/java -classpath \ + $YETII_DIR/yetii.jar:$YETI_LIBDIR/yeti.jar:$YETI_LIBDIR/yeti-lib.jar:$YETII_DIR/libreadline-java.jar:$JVAMP_DIR/jvamp.jar:$YERTLE_DIR/yertle.jar:./jtransforms-2.4.jar \ + com.particularprograms.yetii "$@" + diff -r 6d6627fbbb78 -r 77d3292bbf12 block.yeti --- a/block.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ - -module block; - -vec = load fvector; - -typedef opaque block = ~double[]; - -{ -zeros = vec.zeros, -consts = vec.consts, -ones = vec.ones, -block v = v, -data b = b, -vector b = vec.copyOf b, -floats = vec.floats, -fromFloats ff = vec.fromFloats ff, -fromList l = vec.vector l, -list = vec.list, -length = vec.length, -equal = vec.equal, -copyOf = vec.copyOf, -rangeOf = vec.rangeOf, -resizedTo = vec.resizedTo, -concat = vec.concat, -} as { -zeros is number -> block, -consts is number -> number -> block, -ones is number -> block, -block is ~double[] -> block, -data is block -> ~double[], -vector is block -> ~double[], -floats is block -> ~float[], -fromFloats is ~float[] -> block, -fromList is list? -> block, -list is block -> list, -length is block -> number, -equal is block -> block -> boolean, -copyOf is block -> block, -rangeOf is block -> number -> number -> block, -resizedTo is number -> block -> block, -concat is list? -> block, -} - - - diff -r 6d6627fbbb78 -r 77d3292bbf12 blockfuncs.yeti --- a/blockfuncs.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ - -module blockfuncs; - -b = load block; - -sum' = - sum . b.list; - -mean bl = - case b.length bl of - 0: 0; - len: sum' bl / len - esac; - -multiply b1 b2 = - b.fromList (map2 (*) (b.list b1) (b.list b2)); - -divideBy n bl = - b.fromList (map (/ n) (b.list bl)); - -sqr bl = - multiply bl bl; - -rms = - sqrt . mean . sqr; - -sqrt' = - b.fromList . (map sqrt) . b.list; - -fftshift bl = - (len = b.length bl; - half = int(len/2 + 0.5); // round up for odd-length sequences - b.concat [b.rangeOf bl half (len-half), b.rangeOf bl 0 half]); - -ifftshift bl = - (len = b.length bl; - half = int(len/2); // round down for odd-length sequences - b.concat [b.rangeOf bl half (len-half), b.rangeOf bl 0 half]); - -{ -sum = sum', -mean, -multiply, divideBy, sqr, -sqrt = sqrt', -rms, -fftshift, -ifftshift, -} - - - diff -r 6d6627fbbb78 -r 77d3292bbf12 channels.yeti --- a/channels.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ - -module channels; - -vec = load fvector; -block = load block; -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; - block.block v); - -deinterleaved rows b = - (v = block.data b; - mat.generate do row col: - v[rows * col + row] - done rows ((vec.length v) / rows)); - -mixedDown m = - (if empty? m then block.zeros 0 else - { cols, rows } = mat.dimensions m; - v = vec.copyOf m[0]; - for [1..rows-1] do row: - for [0..cols-1] do col: - v[col] := v[col] + m[row][col]; - done; - done; - block.block v; - fi); - -mixedDownFromInterleaved rows b = - (v = block.data b; - cols = ((vec.length 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; - block.block v'); - -mixedFromInterleavedTo targetRows rows b = - if targetRows == rows then - b; - elif targetRows == 1 then - mixedDownFromInterleaved rows b; - else - v = block.data b; - cols = ((vec.length 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; - block.block v'; - fi; - -{ - interleaved, deinterleaved, - mixedDown, mixedDownFromInterleaved, mixedFromInterleavedTo, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 complex.yeti --- a/complex.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ - -module complex; - -import java.lang: ClassCastException; - -class Cplx(double real, double imag) - int getReal() - real, - int getImag() - imag, - double getMagnitude() - sqrt (real * real + imag * imag), - double getAngle() - Math#atan2(imag, real), - String toString() - if real == int real and imag == int imag then - if imag < 0 then - " \(int real) - \(int (-imag))i" - else - " \(int real) + \(int imag)i" - fi - else - if imag < 0 then - " \(real) - \((-imag))i" - else - " \(real) + \(imag)i" - fi - fi, - int hashCode() - Double#valueOf(real)#hashCode() + Double#valueOf(imag)#hashCode(), - boolean equals(Object other) - try - c = other unsafely_as ~Cplx; - c#getReal() == real and c#getImag() == imag - catch ClassCastException: - false - yrt, -end; - -typedef opaque cplx = ~Cplx; - -real c1 is ~Cplx -> number = - c1#getReal(); - -imaginary c1 is ~Cplx -> number = - c1#getImag(); - -complex re im is number -> number -> ~Cplx = - new Cplx(re, im); - -magnitude c is ~Cplx -> number = - c#getMagnitude(); - -angle c is ~Cplx -> number = - c#getAngle(); - -add c1 c2 is ~Cplx -> ~Cplx -> ~Cplx = - complex (real c1 + real c2) (imaginary c1 + imaginary c2); - -scale r c is number -> ~Cplx -> ~Cplx = - complex (r * real c) (r * imaginary c); - -{ - real, - imaginary, - complex, - magnitude, - angle, - add, - scale, -} as { - real is cplx -> number, - imaginary is cplx -> number, - complex is number -> number -> cplx, - magnitude is cplx -> number, - angle is cplx -> number, - add is cplx -> cplx -> cplx, - scale is number -> cplx -> cplx, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 fft.yeti --- a/fft.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ - -module fft; - -import edu.emory.mathcs.jtransforms.fft: DoubleFFT_1D; - -b = load block; -vec = load fvector; -complex = load complex; - -packedToComplex p = - (n = (vec.length p) / 2; - array - (map do i: - re = if i == n then p[1] else p[i*2] fi; - im = if i == 0 or i == n then 0 else p[i*2+1] fi; - complex.complex re im; - done [0..n])); - -complexToPacked arr = - (n = length arr; - v = vec.vector - (map do i: - ix = int (i/2); - if i == ix*2 then - complex.real arr[ix] - else - complex.imaginary arr[ix] - fi; - done [0..(n-1)*2-1]); - v[1] := complex.real arr[n-1]; - v); - -realForward n = - (d = new DoubleFFT_1D(n); - do bl: - v = b.vector bl; - d#realForward(v); - packedToComplex v; - done); - -realInverse n = - (d = new DoubleFFT_1D(n); - do arr: - v = complexToPacked arr; - d#realInverse(v, true); - b.block v; - done); - -{ -realForward, -realInverse, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 fmatrix.yeti --- a/fmatrix.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -module fmatrix; - -// Basic matrices using primitive array of double as each row - -vec = load fvector; - -zeroMatrix rows cols = array (map \(vec.zeros cols) [1..rows]); - -generate f rows cols = - (m = zeroMatrix rows cols; - for [0..rows-1] do row: - for [0..cols-1] do col: - m[row][col] := f row col; - done; - done; - m); - -constMatrix n = generate do row col: n done; -randomMatrix = generate do row col: Math#random() done; -identityMatrix = constMatrix 1; - -width m = if length m > 0 then vec.length m[0] else 0 fi; -cols = width; - -height m = length m; -rows = height; - -dimensions m = { cols = width m, rows = height m }; - -copyOf m = array (map vec.copyOf m); - -transposed m is array<~double[]> -> array<~double[]> = - generate do row col: m[col][row] done (cols m) (rows m); - -{ -generate, constMatrix, randomMatrix, zeroMatrix, identityMatrix, -width, cols, height, rows, dimensions, -copyOf, -transposed, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 framer.yeti --- a/framer.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ - -module framer; - -/** - * Framer expresses a stream (or a file) as a lazy list of (possibly - * overlapping) frames of mono data. - */ - -block = load block; -bf = load blockfuncs; -af = load audiofile; -win = load window; -fft = load fft; - -blockList framesize stream = - if stream.finished? then - (stream.close (); [] ); - else - block.resizedTo framesize (stream.readMono framesize) - :. \(blockList framesize stream); - fi; - -overlappingBlockList size hop stream valid buffer = - ( - b = stream.readMono hop; - obtained = block.length b; - - // Retain framesize - hop samples from old buffer, add hop samples - // (zero-padded if necessary) just read - buffer = block.concat - [block.rangeOf buffer hop (size-hop), - block.resizedTo hop b]; - - // Number of "valid" elements (not tail-end zero-padding) left in buffer - remaining = valid - (hop - obtained); - - if remaining <= 0 then - stream.close (); - []; - else - buffer :. \(overlappingBlockList size hop stream remaining buffer); - fi); - -frames { framesize, hop } stream = - if framesize == hop then - blockList framesize stream - else - overlappingBlockList framesize hop stream - framesize (block.zeros framesize); - fi; - -windowedFrames { framesize, hop, window } stream = - (win = window framesize; - map (bf.multiply win) (frames { framesize, hop } stream)); - -frequencyDomainFrames { framesize, hop } stream = - (f = fft.realForward framesize; - map f (windowedFrames { framesize, hop, window = win.hann } stream)); - -{ - frames, - windowedFrames, - frequencyDomainFrames, - - framesOfFile parameters filename = - case af.open filename of - Stream s: Frames (frames parameters s); - Error e: Error e; - esac, - - windowedFramesOfFile parameters filename = - case af.open filename of - Stream s: Frames (windowedFrames parameters s); - Error e: Error e; - esac, - - frequencyDomainFramesOfFile parameters filename = - case af.open filename of - Stream s: Frames (frequencyDomainFrames parameters s); - Error e: Error e; - esac, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 fvector.yeti --- a/fvector.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -module fvector; - -import java.util: Arrays; - -zeros n = - new double[n]; - -consts m n = - (a = zeros n; - for [0..n-1] do i: - a[i] := m; - done; - a); - -ones = consts 1.0; - -vector l is list? -> ~double[] = - (arr = array(l); - len = length arr; - v = zeros len; - for [0..len-1] do i: - v[i] := arr[i]; - done; - v); - -list' a is ~double[] -> list = - list a; - -length' = - length . list'; - -floats a is ~double[] -> ~float[] = - (len = length' a; - f = new float[len]; - for [0..len-1] do i: - f[i] := a[i]; - done; - f); - -fromFloats ff is ~float[] -> ~double[] = - (len = length (list ff); - a = new double[len]; - for [0..len-1] do i: - a[i] := ff[i]; - done; - a); - -equal v1 v2 = - list' v1 == list' v2; - -copyOf v is ~double[] -> ~double[] = - Arrays#copyOf(v, list' v |> length); - -rangeOf v start len is ~double[] -> number -> number -> ~double[] = - Arrays#copyOfRange(v, start, start + len); - -resizedTo n v is number -> ~double[] -> ~double[] = - Arrays#copyOf(v, n); - -concat vv is list?<~double[]> -> ~double[] = - (len = sum (map length' vv); - vout = zeros len; - var base = 0; - for vv do v: - vlen = length' v; - for [0..vlen-1] do i: vout[base + i] := v[i] done; - base := base + vlen; - done; - vout); - -{ -zeros, consts, ones, -vector, -length = length', -list = list', -floats, fromFloats, -equal, -copyOf, rangeOf, resizedTo, -concat, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 matrix.yeti --- a/matrix.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -module matrix; - -// Basic matrices using number type (rather than primitive arrays) - -zeros n = array(map \0 [1..n]); -ones n = array(map \1 [1..n]); - -generateMatrix f rows cols = array - (map do row: array - (map (f row) [0..cols-1]) - done [0..rows-1]); - -constMatrix n = generateMatrix do row col: n done; - -randomMatrix = generateMatrix do row col: Math#random() done; - -zeroMatrix = constMatrix 0; -identityMatrix = constMatrix 1; - -width m = if length m > 0 then length m[0] else 0 fi; - -height m = length m; - -dimensions m = { cols = width m, rows = height m }; - -transposed m = array - (map do n: array - (map do a: a[n-1] done m) - done [1..width m]); - -interleaved m = array(concat(transposed m)); - -deinterleaved rows v = - generateMatrix do row col: - v[rows * col + row] - done rows (length v / rows); - -{ -zeros, ones, -generateMatrix, constMatrix, randomMatrix, zeroMatrix, identityMatrix, -width, height, dimensions, -transposed, -interleaved, deinterleaved, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 playback.yeti --- a/playback.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ - -module playback; - -block = load block; -fr = load framer; -af = load audiofile; -ch = load channels; - -import javax.sound.sampled: - AudioSystem, AudioFormat, AudioFormat$Encoding, SourceDataLine; - -import java.nio: ByteBuffer, ByteOrder; - -playBlock line b is ~SourceDataLine -> 'a -> () = - (len = block.length b; - samples = block.unblock b; - 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; - actual = line#write(bytes, 0, nb); - ()); - -play line blocks = for blocks (playBlock line); - -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, - play = play line, - channels = line#getFormat()#getChannels(), - close () = (line#drain(); line#close()), - }); - -playStream stream = - (line = open { rate = stream.sampleRate, channels = stream.channels }; - blocksize = 10240; - not stream.finished? loop - line.play [(ch.mixedFromInterleavedTo line.channels stream.channels - (stream.readInterleaved blocksize))]; - line.close(); - stream.close()); - -playFile filename = playStream (af.open filename); - -{ - open, play, playStream, playFile, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 stream.yeti --- a/stream.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ - -module stream; - -monoStream box = - (readAll' box = box.read (box.len - box.position); - { - get position () = box.position, - get channels () = 1, - get sampleRate () = box.rate, - get available () = box.len - box.position, - get finished? () = not (box.len > box.position), - read = box.read, - readInterleaved = box.read, - readMono = box.read, - readAll () = readAll' box, - readAllInterleaved () = readAll' box, - readAllMono () = readAll' box, - close = box.close, - }); - -stream box = - ({ - get position () = box.position, - get channels () = box.channels, - get sampleRate () = box.rate, - get available () = box.len - box.position, - get finished? () = not (box.len > box.position), - read = box.read, - readInterleaved = box.readInterleaved, - readMono = box.readMono, - readAll () = box.read (box.len - box.position), - readAllInterleaved () = box.readInterleaved (box.len - box.position), - readAllMono () = box.readMono (box.len - box.position), - close = box.close, - }); - -{ monoStream, stream } - diff -r 6d6627fbbb78 -r 77d3292bbf12 syntheticstream.yeti --- a/syntheticstream.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ - -module syntheticstream; - -str = load stream; -vec = load fvector; -block = load block; - -generated rate generator seconds = - str.monoStream { - var position = 0, - len = int(seconds * rate + 0.5), - rate, - read count = - (rc = min count (len - position); - result = vec.zeros rc; - for [0..rc-1] do i: - result[i] := generator ((position + i) / rate) - done; - position := position + rc; - block.block result), - close = \(), - }; - -sinusoid rate freq seconds = - generated rate (sin . (* (freq / (2*pi * rate)))) seconds; - -whiteNoise rate seconds = - generated rate \((Math#random() * 2.0) - 1.0) seconds; - -precalculated rate data is number -> ~double[] -> 'a = - (n = vec.length data; - str.monoStream { - var position = 0, - len = n, - rate, - read count = - (rc = min count (len - position); - result = vec.rangeOf data position rc; - position := position + rc; - block.block result), - close = \(), - }); - -{ - generated, precalculated, sinusoid, whiteNoise, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/all.yeti --- a/test/all.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ - -program test.all; - -{ runTests } = load test.test; - -tests = [ -"fvector" : load test.test_fvector, -"framer" : load test.test_framer, -"blockfuncs" : load test.test_blockfuncs, -"complex" : load test.test_complex, -"fft" : load test.test_fft, -"vamppost" : load test.test_vamppost, -]; - -bad = sum (mapHash do name testHash: runTests name testHash done tests); - -if (bad > 0) then - println "\n** \(bad) test(s) failed!"; -else - () -fi - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test.yeti --- a/test/test.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ - -module test.test; - -vec = load fvector; -ss = load syntheticstream; - -testStream n is number -> 'a = ss.precalculated 1000 (vec.vector [1..n]); - -compare obtained expected = - if obtained == expected then - true; - else - println "** expected: \(expected)\n obtained: \(obtained)"; - false; - fi; - -select f = fold do r x: if f x then x::r else r fi done []; - -failedTests testHash = - select (!= "") - (mapHash do name f: - if f () then "" else - println "Test \(name) failed"; - name; - fi - done testHash); - -runTests group testHash = - (failed = failedTests testHash; - good = (length testHash - length failed); - bad = length failed; - println "\(group): \(good)/\(good+bad) tests passed"; - if not empty? failed then - println "\(group): Failed tests [\(bad)]: \(strJoin ' ' failed)"; - fi; - bad); - -{ - testStream, compare, failedTests, runTests -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_blockfuncs.yeti --- a/test/test_blockfuncs.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ - -module test.test_blockfuncs; - -stdSqrt = sqrt; - -{ zeros, consts, ones, fromList, list } = load block; -{ sum, mean, multiply, divideBy, sqr, sqrt, rms, fftshift, ifftshift } = load blockfuncs; -{ compare } = load test.test; - -[ - -"sum": \( - compare ((sum . zeros) 0) 0 and - compare ((sum . zeros) 5) 0 and - compare ((sum . ones) 5) 5 and - compare ((sum . fromList) [1,-2,3,0]) 2 -), - -"mean": \( - compare ((mean . zeros) 0) 0 and - compare ((mean . zeros) 5) 0 and - compare ((mean . ones) 5) 1 and - compare ((mean . fromList) [1,-2,3,0]) 0.5 -), - -"multiply": \( - compare (list (multiply (zeros 0) (ones 5))) [] and - compare (list (multiply (consts (-3) 4) (fromList [1,2,3]))) [-3,-6,-9] -), - -"divideBy": \( - compare (list (divideBy 5 (ones 0))) [] and - compare (list (divideBy 5 (fromList [1,2,-3]))) [0.2,0.4,-0.6] -), - -"sqr": \( - compare ((list . sqr . zeros) 0) [] and - compare ((list . sqr . ones) 5) [1,1,1,1,1] and - compare ((list . sqr . fromList) [0.5,-2,3,0]) [0.25,4,9,0] -), - -"sqrt": \( - compare ((list . sqrt . zeros) 0) [] and - compare ((list . sqrt . ones) 5) [1,1,1,1,1] and - compare ((list . sqrt . fromList) [0.25,4,9,0]) [0.5,2,3,0] -), - -"rms": \( - compare ((rms . zeros) 0) 0 and - compare ((rms . ones) 5) 1 and - compare ((rms . fromList) [-1,2,2]) (stdSqrt 3) -), - -"fftshift": \( - compare ((list . fftshift . zeros) 0) [] and - compare ((list . fftshift . fromList) [1,2,3,4]) [3,4,1,2] and - compare ((list . fftshift . fromList) [1,2,3,4,5]) [4,5,1,2,3] -), - -"ifftshift": \( - compare ((list . ifftshift . zeros) 0) [] and - compare ((list . ifftshift . fromList) [3,4,1,2]) [1,2,3,4] and - compare ((list . ifftshift . fromList) [4,5,1,2,3]) [1,2,3,4,5] -), - -] is hash boolean>; - - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_complex.yeti --- a/test/test_complex.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -module test.test_complex; - -{ real, imaginary, complex, magnitude, angle, add, scale } - = load complex; - -{ compare } = load test.test; - -[ - -"complex": \( - compare (complex 1 2) (complex 1 2) and - complex (-1) 2 != complex 1 2 -), - -"real": \( - compare (real (complex 3 2)) 3 -), - -"imaginary": \( - compare (imaginary (complex 3 4)) 4 -), - -"magnitude": \( - compare (magnitude (complex (-3) 4)) 5 -), - -"angle": \( - compare (angle (complex 1 0)) 0 and - compare (angle (complex 1 1)) (pi/4) and - compare (angle (complex 0 1)) (pi/2) and - compare (angle (complex (-1) 0)) pi and - compare (angle (complex 0 (-1))) (-pi/2) -), - -"add": \( - compare (add (complex 2 3) (complex (-4) 5)) (complex (-2) 8) -), - -"scale": \( - compare (scale 4 (complex 2 3)) (complex 8 12) -), - -] is hash boolean>; - - - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_fft.yeti --- a/test/test_fft.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ - -module test.test_fft; - -{ realForward, realInverse } = load fft; -{ list, fromList } = load block; -{ complex } = load complex; - -{ compare } = load test.test; - -testFFT orig reals imags = - (out = realForward (length orig) (fromList orig); - back = realInverse (length orig) out; - compare out (array (map2 complex reals imags)) and compare orig (list back)); - -[ - -"dc": \( - testFFT [1,1,1,1] [4,0,0] [0,0,0]; -), - -"sine": \( - testFFT [0,1,0,-1] [0,0,0] [0,-2,0]; -), - -"cosine": \( - testFFT [1,0,-1,0] [0,2,0] [0,0,0]; -), - -"sineCosine": \( - testFFT [0.5,1,-0.5,-1] [0,1,0] [0,-2,0]; -), - -"nyquist": \( - testFFT [1,-1,1,-1] [0,0,4] [0,0,0]; -), - -"dirac": \( - testFFT [1,0,0,0] [1,1,1] [0,0,0] and - testFFT [0,1,0,0] [1,0,-1] [0,-1,0] and - testFFT [0,0,1,0] [1,-1,1] [0,0,0] and - testFFT [0,0,0,1] [1,0,-1] [0,1,0]; -), - -] is hash boolean>; - - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_framer.yeti --- a/test/test_framer.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ - -module test.test_framer; - -fr = load framer; -block = load block; - -{ compare, testStream } = load test.test; - -[ - -"framecount-2x2": \( - fr = fr.frames { framesize = 2, hop = 2 } (testStream 2); - compare (length fr) 1 -), - -"framecount-2x3": \( - fr = fr.frames { framesize = 2, hop = 2 } (testStream 3); - compare (length fr) 2 -), - -"framecount-2x4": \( - fr = fr.frames { framesize = 2, hop = 2 } (testStream 4); - compare (length fr) 2 -), - -"framecount-2.1x0": \( - fr = fr.frames { framesize = 2, hop = 1 } (testStream 0); - compare (length fr) 1 -), - -"framecount-2.1x1": \( - fr = fr.frames { framesize = 2, hop = 1 } (testStream 1); - compare (length fr) 2 -), - -"framecount-2.1x2": \( - fr = fr.frames { framesize = 2, hop = 1 } (testStream 2); - compare (length fr) 3 -), - -"framecount-2.1x3": \( - fr = fr.frames { framesize = 2, hop = 1 } (testStream 3); - compare (length fr) 4 -), - -"framecount-4.1x4": \( - fr = fr.frames { framesize = 4, hop = 1 } (testStream 4); - compare (length fr) 7 -), - -"framecount-4.3x4": \( - fr = fr.frames { framesize = 4, hop = 3 } (testStream 4); - compare (length fr) 2 -), - -"framecount-4.4x4": \( - fr = fr.frames { framesize = 4, hop = 4 } (testStream 4); - compare (length fr) 1 -), - -"framecount-3.2x4": \( - fr = fr.frames { framesize = 3, hop = 2 } (testStream 4); - compare (length fr) 3 -), - -"frames-2x5": \( - fr = fr.frames { framesize = 2, hop = 2 } (testStream 5); - expected = [ [1,2], [3,4], [5,0] ]; - compare (map block.list fr) expected; -), - -"frames-4.3x4": \( - fr = fr.frames { framesize = 4, hop = 3 } (testStream 4); - expected = [ [0,1,2,3], [3,4,0,0] ]; - compare (map block.list fr) expected; -), - -"frames-3.2x4": \( - fr = fr.frames { framesize = 3, hop = 2 } (testStream 4); - expected = [ [0,1,2], [2,3,4], [4,0,0] ]; - compare (map block.list fr) expected; -), - -"frames-3.1x6": \( - fr = fr.frames { framesize = 3, hop = 1 } (testStream 6); - expected = [ [0,0,1], [0,1,2], [1,2,3], [2,3,4], - [3,4,5], [4,5,6], [5,6,0], [6,0,0] ]; - compare (map block.list fr) expected; -), - -] is hash boolean>; - - - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_fvector.yeti --- a/test/test_fvector.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ - -module test.test_fvector; - -vec = load fvector; - -{ compare } = load test.test; - -[ - -"zeros-empty": \( - v = vec.zeros 0; - compare (vec.length v) 0; -), - -"zeros": \( - v = vec.zeros 3; - compare (vec.length v) 3 and - compare v[0] 0 and - compare v[1] 0 and - compare v[2] 0; -), - -"consts-empty": \( - v = vec.consts 4 0; - compare (vec.length v) 0; -), - -"consts": \( - v = vec.consts 4 3; - compare (vec.length v) 3 and - compare v[0] 4 and - compare v[1] 4 and - compare v[2] 4; -), - -"ones-empty": \( - v = vec.ones 0; - compare (vec.length v) 0; -), - -"ones": \( - v = vec.ones 3; - compare (vec.length v) 3 and - compare v[0] 1 and - compare v[1] 1 and - compare v[2] 1; -), - -"from-list-empty": \( - v = vec.vector []; - compare (vec.length v) 0; -), - -"from-list": \( - v = vec.vector [1,2,3,4]; - compare (vec.length v) 4 and - compare v[0] 1 and - compare v[1] 2 and - compare v[2] 3 and - compare v[3] 4; -), - -"equal-empty": \( - vec.equal (vec.vector []) (vec.vector []) -), - -"equal": \( - v = vec.vector [1,1,1,1]; - w = vec.ones 4; - w' = vec.zeros 4; - w'' = vec.ones 3; - vec.equal v w and not vec.equal v w' and not vec.equal v w''; -), - -"copyOf-empty": \( - vec.equal (vec.vector []) (vec.copyOf (vec.vector [])) -), - -"copyOf": \( - v = vec.vector [1,2,3,4]; - w = vec.copyOf v; - vec.equal v w and ( - v[0] := 0; // check result is not aliasing inputs - not vec.equal v w - ); -), - -"rangeOf": \( - v = vec.vector [1,2,3,4]; - vec.equal (vec.rangeOf v 0 4) v and ( - vec.equal (vec.rangeOf v 2 2) (vec.vector [3,4]) - ) -), - -"resizedTo": \( - vec.equal (vec.resizedTo 4 (vec.vector [])) (vec.zeros 4) and - vec.equal (vec.resizedTo 2 (vec.vector [1,2])) (vec.vector [1,2]) and - vec.equal (vec.resizedTo 3 (vec.vector [1,2])) (vec.vector [1,2,0]) and - vec.equal (vec.resizedTo 2 (vec.vector [1,2,3])) (vec.vector [1,2]); -), - -"concat2": \( - v = vec.vector [1,2,3]; - w = vec.vector [4,5,6]; - x = vec.concat [v, w]; - x' = vec.vector [1,2,3,4,5,6]; - vec.equal x x' and - (v[0] := 0; // check result is not aliasing inputs - w[0] := 0; - vec.equal x x') and - vec.equal x' (vec.concat [x', vec.vector []]) and - vec.equal x' (vec.concat [vec.vector [], x']) -), - -"concatn": \( - v = vec.vector [1,2,3]; - w = vec.vector [4,5,6]; - vec.equal (vec.concat []) (vec.zeros 0) and - vec.equal (vec.concat [v]) v and - vec.equal (vec.concat [v,w,v]) (vec.vector [1,2,3,4,5,6,1,2,3]) -), - -] is hash boolean>; - - - diff -r 6d6627fbbb78 -r 77d3292bbf12 test/test_vamppost.yeti --- a/test/test_vamppost.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -module test.test_vamppost; - -vp = load vamppost; - -{ compare } = load test.test; - -untimed n = { timestamp = Untimed (), values = [n] }; -timed t n = { timestamp = Time t, values = [n] }; - -testdata = { - output = { sampleType = OneSamplePerStep () }, - config = { sampleRate = 1000, stepSize = 100 }, - features = [ - [], - [ untimed 1 ], - [ untimed 1, untimed 2 ], - [], - [ timed 1.1 1, untimed 2, timed 4 3 ] - ] -}; - -[ - -"fillOneSamplePerStep": \( - // All features returned within a single process call (i.e. within - // a single sub-list of the feature list) should be given the same - // timestamp; the timestamp increments according to the config - // step size between sub-lists - filled = vp.fillTimestamps - (testdata with { output = { sampleType = OneSamplePerStep () } }); - compare filled [ - timed 0.1 1 , - timed 0.2 1, timed 0.2 2 , - timed 0.4 1, timed 0.4 2, timed 0.4 3 - ]; -), - -"fillFixedSampleRate": \( - // "If the output feature's hasTimestamp field is true, the host - // should read and use the output feature's timestamp. The host - // may round the timestamp according to the sample rate given in - // the output descriptor's sampleRate field [...] If - // [hasTimestamp] is false, its time will be implicitly calculated - // by incrementing the time of the previous feature according to - // the [output descriptor's] sample rate". Note that the time is - // based on that of the previous feature, not that of the previous - // process cycle (as is the case with OneSamplePerStep features). - filled = vp.fillTimestamps - (testdata with { output = { sampleType = FixedSampleRate 5 } }); - compare filled [ - timed 0 1 , - timed 0.2 1, timed 0.4 2 , - timed 1.0 1, timed 1.2 2, timed 4.0 3 - ]; -), - -"fillVariableSampleRate": \( - // For VariableSampleRate outputs, the timestamps should always - // be left entirely alone by fillTimestamps -- it's an error for - // the plugin to return any features without valid timestamps, - // but it isn't the job of fillTimestamps to handle that error - filled = vp.fillTimestamps - (testdata with { output = { sampleType = VariableSampleRate 5 } }); - compare filled [ - untimed 1 , - untimed 1, untimed 2 , - timed 1.1 1, untimed 2, timed 4.0 3 - ]; -), - -] is hash boolean>; - diff -r 6d6627fbbb78 -r 77d3292bbf12 vamp.yeti --- a/vamp.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ -module vamp; - -import org.vamp_plugins: - Plugin, Plugin$InputDomain, - PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, - ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, - RealTime, Feature; - -import java.lang: UnsatisfiedLinkError; - -import java.util: Map, List; - -block = load block; -fr = load framer; -af = load audiofile; -vamprdf = load vamprdf; - -store = load yertle.store; - -realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); - -feature f is ~Feature -> 'a = { - timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, - duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, - values = f#values, - label = f#label, - }; - -featureList fl is ~Object -> 'a = - if nullptr? fl then [] - else - a = fl unsafely_as ~List; - result = array []; - itr = a#iterator(); - itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); - list result - fi; - -featureSet fs is ~Map -> 'a = - (numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); - s = [:]; - kk = list fs#keySet()#toArray(); - for kk do k: s[numberOf k] := featureList fs#get(k) done; - s); - -getStandardStore = - (s = store.newRdfStore (); - var loaded = false; - \(synchronized s do: - if not loaded then - vamprdf.loadSystemVampRdf s; - loaded := true - fi; - s - done) - ); - -getPluginPath () = - (try - map string PluginLoader#getInstance()#getPluginPath(); - catch UnsatisfiedLinkError e: - eprintln "Warning: Unable to obtain plugin path:\n\(e)"; - []; - yrt); - -listPlugins () = - (try - map string PluginLoader#getInstance()#listPlugins(); - catch UnsatisfiedLinkError e: - eprintln "Warning: Unable to obtain plugin list:\n\(e)"; - []; - yrt); - -categoryOf key = - list PluginLoader#getInstance()#getPluginCategory(key); - -inputDomain d is ~Plugin$InputDomain -> 'a = - if d == Plugin$InputDomain#FREQUENCY_DOMAIN then - FrequencyDomain () - else - TimeDomain () - fi; - -parameterDescriptor pd is ~ParameterDescriptor -> 'a = { - identifier = pd#identifier, - name = pd#name, - description = pd#description, - unit = pd#unit, - minValue = pd#minValue, - maxValue = pd#maxValue, - defaultValue = pd#defaultValue, - get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, - valueNames = map string pd#valueNames - }; - -sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = - if t == OutputDescriptor$SampleType#OneSamplePerStep then - OneSamplePerStep () - elif t == OutputDescriptor$SampleType#FixedSampleRate then - FixedSampleRate rate - else - VariableSampleRate rate - fi; - -structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = - (computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; - s = getStandardStore (); - noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; - if od#hasFixedBinCount and od#binCount == 0 then - Instants (); - elif od#hasDuration then - if computes != Unknown () then - if computes == Event noteIRI then Notes (); - else Regions (); - fi - elif od#hasFixedBinCount then - if od#binCount > 1 then Notes (); - elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); - else Regions (); - fi - else - Unknown (); - fi - elif od#hasFixedBinCount and od#binCount == 1 then - case computes of - Event e: - if strEnds? e "Segment" then Segmentation (); - else Curve (); - fi; - _: Curve (); - esac; - elif od#hasFixedBinCount and - od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then - Grid (); - else - Unknown (); - fi); - -outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = { - identifier = od#identifier, - name = od#name, - description = od#description, - get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, - get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi, - get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, - valueUnit = od#unit, - binNames = array (map string od#binNames), - sampleType = sampleType od#sampleType od#sampleRate, - hasDuration = od#hasDuration, - get computes () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, - get inferredStructure () = structureOf rdfOutputData od, - }; - -plugin key p is string -> ~Plugin -> 'a = - (rdfData = vamprdf.pluginDataByKey (getStandardStore ()) key; - { - plugin = p, - key, - get apiVersion () = p#getVampApiVersion(), - get identifier () = p#getIdentifier(), - get name () = p#getName(), - get description () = p#getDescription(), - get maker () = p#getMaker(), - get copyright () = p#getCopyright(), - get version () = p#getPluginVersion(), - get category () = PluginLoader#getInstance()#getPluginCategory(key), - get hasRdfDescription () = (rdfData != None ()), - get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, - get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), - parameterValue identifier = p#getParameter(identifier), - setParameterValue identifier value = p#setParameter(identifier, value), - get programs () = array (map string p#getPrograms()), - get currentProgram () = p#getCurrentProgram(), - selectProgram pr = p#selectProgram(pr), - get inputDomain () = inputDomain p#getInputDomain(), - get preferredBlockSize () = p#getPreferredBlockSize(), - get preferredStepSize () = p#getPreferredStepSize(), - get minChannelCount () = p#getMinChannelCount(), - get maxChannelCount () = p#getMaxChannelCount(), - initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize), - reset () = p#reset(), - get outputs () = - array case rdfData of - Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); - None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); - esac, - process blocks time is 'a -> ~RealTime -> 'b = - featureSet p#process((map block.floats blocks) as ~float[][], 0, time), - getRemainingFeatures () = featureSet p#getRemainingFeatures(), - dispose () = p#dispose(), - }); - -featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; - -outputNumberByName p name = - (outputs = p.outputs; - case find ((== name) . (.identifier)) outputs of - first::rest: index first outputs; - _: -1; - esac); - -loadPlugin rate key = - try - OK (plugin key - PluginLoader#getInstance()#loadPlugin(key, rate, - PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + - PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) - catch PluginLoader$LoadFailedException _: - Error "Failed to load Vamp plugin with key \(key)" - yrt; - -processed { p, sampleRate, hop } frames count - // I don't know why this type declaration is necessary. Without - // it, yeti records the return type as 'a and can't do anything - // useful with it (giving IncompatibleClassChangeError when - // e.g. accessing the values array) - is 'a -> 'b -> 'c -> - list>> = - case frames of - frame::rest: - p.process [frame] RealTime#frame2RealTime(count, sampleRate) - :. - \(processed { p, sampleRate, hop } rest (count + hop)); - _: - (rf = p.getRemainingFeatures (); - p.dispose (); - [rf]); - esac; - -converted { p, sampleRate, hop } outputNo fl = - map (featuresFromSet outputNo) fl; - -returnErrorFrom p stream text = (p.dispose (); stream.close (); Error text); - -processWith key p outputNo stream = - (blockSize = p.preferredBlockSize; - stepSize = p.preferredStepSize; - channels = 1; - params = { - p, sampleRate = stream.sampleRate, channels = 1, - framesize = blockSize, blockSize, hop = stepSize - }; - if p.initialise params then - OK { - key = key, - output = p.outputs[outputNo], - parameters = mapIntoHash id p.parameterValue - (map (.identifier) p.parameters), - config = { - channels, blockSize, stepSize, - sampleRate = stream.sampleRate - }, - features = converted params outputNo - (processed params (fr.frames params stream) 0) - }; - // If processing completed successfully, then p is - // disposed by processed and stream is closed by the - // framer - else - returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; - fi); - -process key output stream = - case loadPlugin stream.sampleRate key of - OK p: - outputNo = outputNumberByName p output; - if outputNo >= 0 then - processWith key p outputNo stream - else - outputs = strJoin ", " (map (.identifier) p.outputs); - returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are \(outputs))" - fi; - Error e: Error e; - esac; - -processFile key output filename = - case af.open filename of - Stream s: process key output s; - Error e: Error e; - esac; - -{ -get pluginPath = getPluginPath, -get pluginKeys = listPlugins, -loadPlugin, -categoryOf, -process, -processFile, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 vamppost.yeti --- a/vamppost.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -module vamppost; - -fmat = load fmatrix; - -fillOneSamplePerStep config features = - (fill' n pending features = - case pending of - feature::rest: - stamped = feature with - { timestamp = Time ((n * config.stepSize) / config.sampleRate) }; - stamped :. \(fill' n rest features); - _: - if empty? features then [] - else fill' (n+1) (head features) (tail features); - fi; - esac; - fill' (-1) [] features); - -fillFixedSampleRate config rate features = - (eps = 0.0001; - fill' n pending features = - case pending of - feature::rest: - n = case feature.timestamp of - Untimed (): n + 1; - Time t: int (t * rate + eps); - esac; - stamped = feature with { timestamp = Time (n / rate) }; - stamped :. \(fill' n rest features); - _: - if empty? features then [] - else fill' n (head features) (tail features); - fi; - esac; - fill' (-1) [] features); - -fillTimestamps { output, config, features } = - case output.sampleType of - OneSamplePerStep (): - fillOneSamplePerStep config features; - FixedSampleRate rate: - fillFixedSampleRate config rate features; - VariableSampleRate _: - concat features; - esac; - -structureGrid binCount features = - if empty? features then - fmat.constMatrix binCount 0 0; - else - fmat.generate - do row col: - features[col].values[row]; - done binCount (length features); - fi; - -structure data = - (type = data.output.inferredStructure; - features = - case type of - Grid (): concat data.features; - _: fillTimestamps data; - esac; - binCount = - case data.output.binCount of - Fixed n: n; - _: 0; - esac; - case type of - Curve (): // No duration, one value - Curve features; - Grid (): // No duration, >1 value, not variable rate - Grid (structureGrid binCount (array features)); - Instants (): // Zero-valued features - Instants features; - Notes (): // Duration, at least one value (pitch or freq) - Notes features; - Regions (): // Duration, zero or more values - Regions features; - Segmentation (): // No duration, one value, segment type in RDF - Segmentation features; - Unknown (): // Other - Unknown features; - esac); - -postprocess data = - case data of - OK data: - structure data; - Error e: - Error e; - esac; - -{ -fillTimestamps, -postprocess -} - - diff -r 6d6627fbbb78 -r 77d3292bbf12 vamprdf.yeti --- a/vamprdf.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,294 +0,0 @@ - -module vamprdf; - -read = load yertle.read; -{ newRdfStore } = load yertle.store; - -import java.io: File; - -import org.vamp_plugins: PluginLoader; - -import java.lang: UnsatisfiedLinkError; - -getPluginPath () = - (try map string PluginLoader#getInstance()#getPluginPath(); - catch UnsatisfiedLinkError e: []; - yrt); - -systemVampRdfFiles () = - concat - (map do p: - map ((p ^ File#separator ^) . (.name)) - (filter do entry: - entry.file? and - (lc = strLower entry.name; - (strEnds? lc ".ttl") or - (strEnds? lc ".n3") or - (strEnds? lc ".nt")) - done (listDirectory false p)) - done (getPluginPath ())); - -addVampPrefixes store = - (store.addPrefix "vamp" "http://purl.org/ontology/vamp/"; - store.addPrefix "dc" "http://purl.org/dc/elements/1.1/"; - store.addPrefix "foaf" "http://xmlns.com/foaf/0.1/"; - store.addPrefix "owl" "http://www.w3.org/2002/07/owl#"; - store.addPrefix "af" "http://purl.org/ontology/af/"); - -loadSystemVampRdf store = - (addVampPrefixes store; - for (systemVampRdfFiles ()) do file: - case read.loadTurtleFile store ("file://" ^ file) file of - OK (): (); - Error e: eprintln - "WARNING: Failed to load Vamp plugin RDF file \"\(file)\": \(e)"; - esac - done); - -getGlobalPluginIndex () = - list (strSplit "\n" (fetchURL [ Timeout 10 ] (Handle getContents) - "http://www.vamp-plugins.org/rdf/plugins/index.txt")); - -//!!! need to cache these retrievals -parseGlobalVampRdf () = - (parse urls = - case urls of - url::rest: - (doc = fetchURL [ Timeout 10 ] (Handle getContents) url; - parsed = read.parseTurtleString url doc; - { url, parsed } :. \(parse rest)); - _: []; - esac; - parse (getGlobalPluginIndex ())); - -loadGlobalVampRdf store = - for (parseGlobalVampRdf ()) do { url, parsed }: - case read.loadParsedTriples store parsed of - OK (): (); - Error e: eprintln "WARNING: Failed to load Vamp RDF from URL \(url): \(e)"; - esac; - done; - -filterIRIsFromNodes nodes = - map do r: case r of IRI iri: iri; esac done - (filter do r: case r of IRI iri: true; _: false esac done nodes); - -subjects = map (.s); - -iriTypes = - map do t: - case t of - IRI iri: IRI iri; - Blank n: Blank n; - esac done; - -iriSubjects = iriTypes . subjects; - -allLibraryNodes store = - iriSubjects - (store.match { - s = Wildcard (), - p = Known (store.expand "a"), - o = Known (store.expand "vamp:PluginLibrary") - }); - -allPluginNodes store = - iriSubjects - (store.match { - s = Wildcard (), - p = Known (store.expand "a"), - o = Known (store.expand "vamp:Plugin") - }); - -pluginsWithId store id = - iriTypes - (filter do pnode: - store.contains { - s = pnode, - p = store.expand "vamp:identifier", - o = Literal { value = id, type = "", language = "" } - } - done (allPluginNodes store)); - -librariesWithId store id = - iriTypes - (filter do lnode: - store.contains { - s = lnode, - p = store.expand "vamp:identifier", - o = Literal { value = id, type = "", language = "" } - } - done (allLibraryNodes store)); - -splitPluginKey key = - (bits = strSplit ":" key; - reversed = reverse bits; - soname = strJoin ":" (reverse (tail reversed)); - identifier = head reversed; - { soname, identifier }); - -pluginNodesByKey store key = - (case splitPluginKey key of { soname, identifier }: - candidatePlugins = pluginsWithId store identifier; - candidateLibraries = librariesWithId store soname; - filter do pnode: - any do lnode: - store.contains { - s = lnode, - p = store.expand "vamp:available_plugin", - o = pnode - } - done candidateLibraries - done candidatePlugins - esac); - -libraryNodeFor store pluginNode = - case store.match { - s = Wildcard (), p = Known (store.expand "vamp:available_plugin"), o = Known pluginNode - } of - { s = IRI iri }::others: Some (IRI iri); - { s = Blank n }::others: Some (Blank n); - _: None (); - esac; - -textProperty store subject name = - case store.match { - s = Known subject, p = Known (store.expand name), o = Wildcard () - } of - { o = Literal { value = text } }::others: text; - _: ""; - esac; - -iriProperty store subject name = - case store.match { - s = Known subject, p = Known (store.expand name), o = Wildcard () - } of - { o = IRI iri }::others: IRI iri; - _: None (); - esac; - -nodeProperty store subject name = - case store.match { - s = Known subject, p = Known (store.expand name), o = Wildcard () - } of - { o = IRI iri }::others: Some (IRI iri); - { o = Blank n }::others: Some (Blank n); - _: None (); - esac; - -inputDomainOf store pluginNode = - case store.match { - s = Known pluginNode, p = Known (store.expand "vamp:input_domain"), o = Wildcard () - } of - { o = IRI iri }::others: - if IRI iri == store.expand "vamp:FrequencyDomain" - then FrequencyDomain () - else TimeDomain () - fi; - _: TimeDomain (); - esac; - -outputDescriptor store outputNode = - (tprop abbr = textProperty store outputNode abbr; - iprop abbr = iriProperty store outputNode abbr; - bprop abbr deflt = - (b = strLower (textProperty store outputNode abbr); - if b == "true" then true elif b == "false" then false else deflt fi); - nprop abbr = - try number (textProperty store outputNode abbr); catch Exception _: 0 yrt; - { - identifier = tprop "vamp:identifier", - name = tprop "dc:title", - description = tprop "dc:description", - rdfType = case iprop "a" of IRI iri: iri; _: "" esac, - valueUnit = tprop "vamp:unit", - binCount = - if bprop "vamp:fixed_bin_count" false - then Known (nprop "vamp:bin_count") - else Unknown () - fi, - computes = - case iprop "vamp:computes_event_type" of - IRI iri: Event iri; - _: case iprop "vamp:computes_signal_type" of - IRI iri: Signal iri; - _: case iprop "vamp:computes_feature_type" of - IRI iri: Feature iri; - _: Unknown (); - esac - esac - esac, - //!!! and some other properties - }); - -pluginDataByNode store pluginNode = - (tprop abbr = textProperty store pluginNode abbr; - nprop abbr = - try number (textProperty store pluginNode abbr); catch Exception _: 0 yrt; - soname = - case libraryNodeFor store pluginNode of - None (): ""; - Some n: textProperty store n "vamp:identifier"; - esac; - { - pluginKey = soname ^ ":" ^ tprop "vamp:identifier", - soname, - apiVersion = nprop "vamp:vamp_API_version", - identifier = tprop "vamp:identifier", - name = tprop "dc:title", - description = tprop "dc:description", - maker = - (tmaker = tprop "foaf:maker"; - if tmaker == "" then - case nodeProperty store pluginNode "foaf:maker" of - Some n: textProperty store n "foaf:name"; - None (): ""; - esac - else - tmaker - fi), - copyright = tprop "dc:rights", - version = tprop "owl:versionInfo", - category = tprop "vamp:category", - inputDomain = inputDomainOf store pluginNode, - infoURL = - (case iriProperty store pluginNode "foaf:page" of - IRI iri: iri; - None (): - case libraryNodeFor store pluginNode of - None (): ""; - Some n: - case iriProperty store n "foaf:page" of - IRI iri: iri; - None (): ""; - esac; - esac; - esac), - outputs = - (matches = store.match { s = Known pluginNode, - p = Known (store.expand "vamp:output"), - o = Wildcard () }; - array (map do t: - case t.o of - IRI iri: outputDescriptor store (IRI iri); - Blank n: outputDescriptor store (Blank n); - esac - done matches)), - }); - -pluginDataByKey store key = - case pluginNodesByKey store key of - node::others: Some (pluginDataByNode store node); - _: None () - esac; - -{ -loadSystemVampRdf, -loadGlobalVampRdf, -allPluginNodes, -allLibraryNodes, -pluginNodesByKey, -pluginDataByNode, -pluginDataByKey, -} - diff -r 6d6627fbbb78 -r 77d3292bbf12 window.yeti --- a/window.yeti Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ - -module window; - -b = load block; -bf = load blockfuncs; - -cosinewin a0 a1 a2 a3 n = - b.fromList - (map do i: - a0 - - a1 * cos(2 * pi * i / n) - + a2 * cos(4 * pi * i / n) - - a2 * cos(6 * pi * i / n) - done [0..n-1]); - -hann = cosinewin 0.5 0.5 0.0 0.0; -hamming = cosinewin 0.54 0.46 0.0 0.0; -blackman = cosinewin 0.42 0.50 0.08 0.0; -nuttall = cosinewin 0.3635819 0.4891775 0.1365995 0.0106411; -blackmanHarris = cosinewin 0.35875 0.48829 0.14128 0.01168; -boxcar = b.consts 0.5; - -bartlett n = - b.fromList - (m = n/2; - concat [ - map do i: - i / m - done [0..m-1], - map do i: - 1.0 - (i / m) - done [0..m-1] - ]); - -windowed windowFunc frames = - case frames of - []: frames; - _: (first = head frames; - window = windowFunc (b.length first); - map (bf.multiply window) frames); - esac; - -{ -cosinewin, hann, hamming, blackman, nuttall, blackmanHarris, boxcar, bartlett, -windowed -}; - diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab --- a/yetilab Tue Mar 19 13:43:39 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#!/bin/sh -MYDIR=`dirname $0` -YETII_DIR=../yetii -YETI_LIBDIR=${YETI_LIBDIR:=../yeti} -if [ ! -d "$YETI_LIBDIR" ]; then - YETI_LIBDIR=../other/yeti -fi -JVAMP_DIR=${JVAMP_DIR:=../jvamp} -YERTLE_DIR=${YERTLE_DIR:=../yertle} - -YETI_MODULE_SOURCE_PATH=${YETI_LIBDIR}/modules \ - LD_LIBRARY_PATH=$YETII_DIR:$JVAMP_DIR:$LD_LIBRARY_PATH \ - $JAVA_HOME/bin/java -classpath \ - $YETII_DIR/yetii.jar:$YETI_LIBDIR/yeti.jar:$YETI_LIBDIR/yeti-lib.jar:$YETII_DIR/libreadline-java.jar:$JVAMP_DIR/jvamp.jar:$YERTLE_DIR/yertle.jar:./jtransforms-2.4.jar \ - com.particularprograms.yetii "$@" - diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/block.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/block.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,45 @@ + +module block; + +vec = load fvector; + +typedef opaque block = ~double[]; + +{ +zeros = vec.zeros, +consts = vec.consts, +ones = vec.ones, +block v = v, +data b = b, +vector b = vec.copyOf b, +floats = vec.floats, +fromFloats ff = vec.fromFloats ff, +fromList l = vec.vector l, +list = vec.list, +length = vec.length, +equal = vec.equal, +copyOf = vec.copyOf, +rangeOf = vec.rangeOf, +resizedTo = vec.resizedTo, +concat = vec.concat, +} as { +zeros is number -> block, +consts is number -> number -> block, +ones is number -> block, +block is ~double[] -> block, +data is block -> ~double[], +vector is block -> ~double[], +floats is block -> ~float[], +fromFloats is ~float[] -> block, +fromList is list? -> block, +list is block -> list, +length is block -> number, +equal is block -> block -> boolean, +copyOf is block -> block, +rangeOf is block -> number -> number -> block, +resizedTo is number -> block -> block, +concat is list? -> block, +} + + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/blockfuncs.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/blockfuncs.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,51 @@ + +module blockfuncs; + +b = load block; + +sum' = + sum . b.list; + +mean bl = + case b.length bl of + 0: 0; + len: sum' bl / len + esac; + +multiply b1 b2 = + b.fromList (map2 (*) (b.list b1) (b.list b2)); + +divideBy n bl = + b.fromList (map (/ n) (b.list bl)); + +sqr bl = + multiply bl bl; + +rms = + sqrt . mean . sqr; + +sqrt' = + b.fromList . (map sqrt) . b.list; + +fftshift bl = + (len = b.length bl; + half = int(len/2 + 0.5); // round up for odd-length sequences + b.concat [b.rangeOf bl half (len-half), b.rangeOf bl 0 half]); + +ifftshift bl = + (len = b.length bl; + half = int(len/2); // round down for odd-length sequences + b.concat [b.rangeOf bl half (len-half), b.rangeOf bl 0 half]); + +{ +sum = sum', +mean, +multiply, divideBy, sqr, +sqrt = sqrt', +rms, +fftshift, +ifftshift, +} + + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/complex.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/complex.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,80 @@ + +module complex; + +import java.lang: ClassCastException; + +class Cplx(double real, double imag) + int getReal() + real, + int getImag() + imag, + double getMagnitude() + sqrt (real * real + imag * imag), + double getAngle() + Math#atan2(imag, real), + String toString() + if real == int real and imag == int imag then + if imag < 0 then + " \(int real) - \(int (-imag))i" + else + " \(int real) + \(int imag)i" + fi + else + if imag < 0 then + " \(real) - \((-imag))i" + else + " \(real) + \(imag)i" + fi + fi, + int hashCode() + Double#valueOf(real)#hashCode() + Double#valueOf(imag)#hashCode(), + boolean equals(Object other) + try + c = other unsafely_as ~Cplx; + c#getReal() == real and c#getImag() == imag + catch ClassCastException: + false + yrt, +end; + +typedef opaque cplx = ~Cplx; + +real c1 is ~Cplx -> number = + c1#getReal(); + +imaginary c1 is ~Cplx -> number = + c1#getImag(); + +complex re im is number -> number -> ~Cplx = + new Cplx(re, im); + +magnitude c is ~Cplx -> number = + c#getMagnitude(); + +angle c is ~Cplx -> number = + c#getAngle(); + +add c1 c2 is ~Cplx -> ~Cplx -> ~Cplx = + complex (real c1 + real c2) (imaginary c1 + imaginary c2); + +scale r c is number -> ~Cplx -> ~Cplx = + complex (r * real c) (r * imaginary c); + +{ + real, + imaginary, + complex, + magnitude, + angle, + add, + scale, +} as { + real is cplx -> number, + imaginary is cplx -> number, + complex is number -> number -> cplx, + magnitude is cplx -> number, + angle is cplx -> number, + add is cplx -> cplx -> cplx, + scale is number -> cplx -> cplx, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/fmatrix.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/fmatrix.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,41 @@ +module fmatrix; + +// Basic matrices using primitive array of double as each row + +vec = load fvector; + +zeroMatrix rows cols = array (map \(vec.zeros cols) [1..rows]); + +generate f rows cols = + (m = zeroMatrix rows cols; + for [0..rows-1] do row: + for [0..cols-1] do col: + m[row][col] := f row col; + done; + done; + m); + +constMatrix n = generate do row col: n done; +randomMatrix = generate do row col: Math#random() done; +identityMatrix = constMatrix 1; + +width m = if length m > 0 then vec.length m[0] else 0 fi; +cols = width; + +height m = length m; +rows = height; + +dimensions m = { cols = width m, rows = height m }; + +copyOf m = array (map vec.copyOf m); + +transposed m is array<~double[]> -> array<~double[]> = + generate do row col: m[col][row] done (cols m) (rows m); + +{ +generate, constMatrix, randomMatrix, zeroMatrix, identityMatrix, +width, cols, height, rows, dimensions, +copyOf, +transposed, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/fvector.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/fvector.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,81 @@ +module fvector; + +import java.util: Arrays; + +zeros n = + new double[n]; + +consts m n = + (a = zeros n; + for [0..n-1] do i: + a[i] := m; + done; + a); + +ones = consts 1.0; + +vector l is list? -> ~double[] = + (arr = array(l); + len = length arr; + v = zeros len; + for [0..len-1] do i: + v[i] := arr[i]; + done; + v); + +list' a is ~double[] -> list = + list a; + +length' = + length . list'; + +floats a is ~double[] -> ~float[] = + (len = length' a; + f = new float[len]; + for [0..len-1] do i: + f[i] := a[i]; + done; + f); + +fromFloats ff is ~float[] -> ~double[] = + (len = length (list ff); + a = new double[len]; + for [0..len-1] do i: + a[i] := ff[i]; + done; + a); + +equal v1 v2 = + list' v1 == list' v2; + +copyOf v is ~double[] -> ~double[] = + Arrays#copyOf(v, list' v |> length); + +rangeOf v start len is ~double[] -> number -> number -> ~double[] = + Arrays#copyOfRange(v, start, start + len); + +resizedTo n v is number -> ~double[] -> ~double[] = + Arrays#copyOf(v, n); + +concat vv is list?<~double[]> -> ~double[] = + (len = sum (map length' vv); + vout = zeros len; + var base = 0; + for vv do v: + vlen = length' v; + for [0..vlen-1] do i: vout[base + i] := v[i] done; + base := base + vlen; + done; + vout); + +{ +zeros, consts, ones, +vector, +length = length', +list = list', +floats, fromFloats, +equal, +copyOf, rangeOf, resizedTo, +concat, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/matrix.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/matrix.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,45 @@ +module matrix; + +// Basic matrices using number type (rather than primitive arrays) + +zeros n = array(map \0 [1..n]); +ones n = array(map \1 [1..n]); + +generateMatrix f rows cols = array + (map do row: array + (map (f row) [0..cols-1]) + done [0..rows-1]); + +constMatrix n = generateMatrix do row col: n done; + +randomMatrix = generateMatrix do row col: Math#random() done; + +zeroMatrix = constMatrix 0; +identityMatrix = constMatrix 1; + +width m = if length m > 0 then length m[0] else 0 fi; + +height m = length m; + +dimensions m = { cols = width m, rows = height m }; + +transposed m = array + (map do n: array + (map do a: a[n-1] done m) + done [1..width m]); + +interleaved m = array(concat(transposed m)); + +deinterleaved rows v = + generateMatrix do row col: + v[rows * col + row] + done rows (length v / rows); + +{ +zeros, ones, +generateMatrix, constMatrix, randomMatrix, zeroMatrix, identityMatrix, +width, height, dimensions, +transposed, +interleaved, deinterleaved, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/test/test_blockfuncs.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/test/test_blockfuncs.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,68 @@ + +module test.test_blockfuncs; + +stdSqrt = sqrt; + +{ zeros, consts, ones, fromList, list } = load block; +{ sum, mean, multiply, divideBy, sqr, sqrt, rms, fftshift, ifftshift } = load blockfuncs; +{ compare } = load test.test; + +[ + +"sum": \( + compare ((sum . zeros) 0) 0 and + compare ((sum . zeros) 5) 0 and + compare ((sum . ones) 5) 5 and + compare ((sum . fromList) [1,-2,3,0]) 2 +), + +"mean": \( + compare ((mean . zeros) 0) 0 and + compare ((mean . zeros) 5) 0 and + compare ((mean . ones) 5) 1 and + compare ((mean . fromList) [1,-2,3,0]) 0.5 +), + +"multiply": \( + compare (list (multiply (zeros 0) (ones 5))) [] and + compare (list (multiply (consts (-3) 4) (fromList [1,2,3]))) [-3,-6,-9] +), + +"divideBy": \( + compare (list (divideBy 5 (ones 0))) [] and + compare (list (divideBy 5 (fromList [1,2,-3]))) [0.2,0.4,-0.6] +), + +"sqr": \( + compare ((list . sqr . zeros) 0) [] and + compare ((list . sqr . ones) 5) [1,1,1,1,1] and + compare ((list . sqr . fromList) [0.5,-2,3,0]) [0.25,4,9,0] +), + +"sqrt": \( + compare ((list . sqrt . zeros) 0) [] and + compare ((list . sqrt . ones) 5) [1,1,1,1,1] and + compare ((list . sqrt . fromList) [0.25,4,9,0]) [0.5,2,3,0] +), + +"rms": \( + compare ((rms . zeros) 0) 0 and + compare ((rms . ones) 5) 1 and + compare ((rms . fromList) [-1,2,2]) (stdSqrt 3) +), + +"fftshift": \( + compare ((list . fftshift . zeros) 0) [] and + compare ((list . fftshift . fromList) [1,2,3,4]) [3,4,1,2] and + compare ((list . fftshift . fromList) [1,2,3,4,5]) [4,5,1,2,3] +), + +"ifftshift": \( + compare ((list . ifftshift . zeros) 0) [] and + compare ((list . ifftshift . fromList) [3,4,1,2]) [1,2,3,4] and + compare ((list . ifftshift . fromList) [4,5,1,2,3]) [1,2,3,4,5] +), + +] is hash boolean>; + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/test/test_complex.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/test/test_complex.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,46 @@ +module test.test_complex; + +{ real, imaginary, complex, magnitude, angle, add, scale } + = load complex; + +{ compare } = load test.test; + +[ + +"complex": \( + compare (complex 1 2) (complex 1 2) and + complex (-1) 2 != complex 1 2 +), + +"real": \( + compare (real (complex 3 2)) 3 +), + +"imaginary": \( + compare (imaginary (complex 3 4)) 4 +), + +"magnitude": \( + compare (magnitude (complex (-3) 4)) 5 +), + +"angle": \( + compare (angle (complex 1 0)) 0 and + compare (angle (complex 1 1)) (pi/4) and + compare (angle (complex 0 1)) (pi/2) and + compare (angle (complex (-1) 0)) pi and + compare (angle (complex 0 (-1))) (-pi/2) +), + +"add": \( + compare (add (complex 2 3) (complex (-4) 5)) (complex (-2) 8) +), + +"scale": \( + compare (scale 4 (complex 2 3)) (complex 8 12) +), + +] is hash boolean>; + + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/block/test/test_fvector.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/block/test/test_fvector.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,126 @@ + +module test.test_fvector; + +vec = load fvector; + +{ compare } = load test.test; + +[ + +"zeros-empty": \( + v = vec.zeros 0; + compare (vec.length v) 0; +), + +"zeros": \( + v = vec.zeros 3; + compare (vec.length v) 3 and + compare v[0] 0 and + compare v[1] 0 and + compare v[2] 0; +), + +"consts-empty": \( + v = vec.consts 4 0; + compare (vec.length v) 0; +), + +"consts": \( + v = vec.consts 4 3; + compare (vec.length v) 3 and + compare v[0] 4 and + compare v[1] 4 and + compare v[2] 4; +), + +"ones-empty": \( + v = vec.ones 0; + compare (vec.length v) 0; +), + +"ones": \( + v = vec.ones 3; + compare (vec.length v) 3 and + compare v[0] 1 and + compare v[1] 1 and + compare v[2] 1; +), + +"from-list-empty": \( + v = vec.vector []; + compare (vec.length v) 0; +), + +"from-list": \( + v = vec.vector [1,2,3,4]; + compare (vec.length v) 4 and + compare v[0] 1 and + compare v[1] 2 and + compare v[2] 3 and + compare v[3] 4; +), + +"equal-empty": \( + vec.equal (vec.vector []) (vec.vector []) +), + +"equal": \( + v = vec.vector [1,1,1,1]; + w = vec.ones 4; + w' = vec.zeros 4; + w'' = vec.ones 3; + vec.equal v w and not vec.equal v w' and not vec.equal v w''; +), + +"copyOf-empty": \( + vec.equal (vec.vector []) (vec.copyOf (vec.vector [])) +), + +"copyOf": \( + v = vec.vector [1,2,3,4]; + w = vec.copyOf v; + vec.equal v w and ( + v[0] := 0; // check result is not aliasing inputs + not vec.equal v w + ); +), + +"rangeOf": \( + v = vec.vector [1,2,3,4]; + vec.equal (vec.rangeOf v 0 4) v and ( + vec.equal (vec.rangeOf v 2 2) (vec.vector [3,4]) + ) +), + +"resizedTo": \( + vec.equal (vec.resizedTo 4 (vec.vector [])) (vec.zeros 4) and + vec.equal (vec.resizedTo 2 (vec.vector [1,2])) (vec.vector [1,2]) and + vec.equal (vec.resizedTo 3 (vec.vector [1,2])) (vec.vector [1,2,0]) and + vec.equal (vec.resizedTo 2 (vec.vector [1,2,3])) (vec.vector [1,2]); +), + +"concat2": \( + v = vec.vector [1,2,3]; + w = vec.vector [4,5,6]; + x = vec.concat [v, w]; + x' = vec.vector [1,2,3,4,5,6]; + vec.equal x x' and + (v[0] := 0; // check result is not aliasing inputs + w[0] := 0; + vec.equal x x') and + vec.equal x' (vec.concat [x', vec.vector []]) and + vec.equal x' (vec.concat [vec.vector [], x']) +), + +"concatn": \( + v = vec.vector [1,2,3]; + w = vec.vector [4,5,6]; + vec.equal (vec.concat []) (vec.zeros 0) and + vec.equal (vec.concat [v]) v and + vec.equal (vec.concat [v,w,v]) (vec.vector [1,2,3,4,5,6,1,2,3]) +), + +] is hash boolean>; + + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/audiofile.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/audiofile.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,119 @@ + +module audiofile; + +import javax.sound.sampled: + AudioSystem, AudioInputStream, AudioFormat, AudioFormat$Encoding, + UnsupportedAudioFileException; + +import java.io: File, IOException; + +import java.nio: ByteBuffer, ByteOrder; + +str = load stream; +ch = load channels; +block = load block; + +decode8u bytes doubles n is ~byte[] -> ~double[] -> number -> () = + (for [0..n-1] do i: + doubles[i] := (bytes[i] / 128.0) - 1.0; + done + ); + +decode16s bytes doubles n is ~byte[] -> ~double[] -> number -> () = + (bb = ByteBuffer#wrap(bytes, 0, n * 2); + bb#order(ByteOrder#LITTLE_ENDIAN); + for [0..n-1] do i: + doubles[i] := bb#getShort(i*2) / 32768.0; + done + ); + +decode32f bytes doubles n is ~byte[] -> ~double[] -> number -> () = + (bb = ByteBuffer#wrap(bytes, 0, n * 4); + bb#order(ByteOrder#LITTLE_ENDIAN); + for [0..n-1] do i: + doubles[i] := bb#getFloat(i*4); + done + ); + +decodeFail () = + throw new UnsupportedAudioFileException("File format not supported. Supported formats are 8-bit unsigned PCM, 16-bit signed little-endian PCM, or IEEE float"); + +decode { format is ~AudioFormat } bytes doubles n = + (if format#isBigEndian() then + decodeFail() + else + enc = format#getEncoding(); + bits = format#getSampleSizeInBits(); + if bits == 32 then + decode32f bytes doubles n; + elif bits == 16 and enc == AudioFormat$Encoding#PCM_SIGNED then + decode16s bytes doubles n; + elif bits == 8 and enc == AudioFormat$Encoding#PCM_UNSIGNED then + decode8u bytes doubles n; + else + decodeFail(); + fi + fi); + +readInterleaved' { format is ~AudioFormat, stream is ~AudioInputStream } nframes = + (channels = format#getChannels(); + bytesPerSample = format#getSampleSizeInBits() / 8; + bytes = new byte[nframes * channels * bytesPerSample]; + bytesRead = stream#read(bytes); + if bytesRead <= 0 then block.zeros 0; + else + n = int(bytesRead / bytesPerSample); + doubles = new double[n]; + decode { format } bytes doubles n; + block.block doubles; + fi; + ); + +read' { format is ~AudioFormat, stream is ~AudioInputStream } n = + (b = readInterleaved' { format, stream } n; + channels = format#getChannels(); + ch.deinterleaved channels b; + ); + +readMono' { format is ~AudioFormat, stream is ~AudioInputStream } n = + (b = readInterleaved' { format, stream } n; + channels = format#getChannels(); + ch.mixedDownFromInterleaved channels b; + ); + +// Note, all this assumes the stream is non-blocking (i.e. available() +// is to the end of file) + +available' { format is ~AudioFormat, stream is ~AudioInputStream } = + stream#available() / ((format#getSampleSizeInBits() / 8) * format#getChannels()); + +close' { stream is ~AudioInputStream } = + stream#close(); + +open name is string -> 'a = + try + f = new File(name); + stream = AudioSystem#getAudioInputStream(f); + format = stream#getFormat(); + len = available' { format, stream }; // at start of stream + Stream (str.stream { + stream, + format, + len, + rate = format#getSampleRate(), + channels = format#getChannels(), + get position () = len - available' { stream, format }, + get available () = available' { stream, format }, + read = read' { stream, format }, + readInterleaved = readInterleaved' { stream, format }, + readMono = readMono' { stream, format }, + close () = close' { stream }, + }); + catch Exception e: + Error "Failed to open audio file \"\(name)\": \(e)"; + yrt; + +{ + open +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/channels.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/channels.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,72 @@ + +module channels; + +vec = load fvector; +block = load block; +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; + block.block v); + +deinterleaved rows b = + (v = block.data b; + mat.generate do row col: + v[rows * col + row] + done rows ((vec.length v) / rows)); + +mixedDown m = + (if empty? m then block.zeros 0 else + { cols, rows } = mat.dimensions m; + v = vec.copyOf m[0]; + for [1..rows-1] do row: + for [0..cols-1] do col: + v[col] := v[col] + m[row][col]; + done; + done; + block.block v; + fi); + +mixedDownFromInterleaved rows b = + (v = block.data b; + cols = ((vec.length 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; + block.block v'); + +mixedFromInterleavedTo targetRows rows b = + if targetRows == rows then + b; + elif targetRows == 1 then + mixedDownFromInterleaved rows b; + else + v = block.data b; + cols = ((vec.length 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; + block.block v'; + fi; + +{ + interleaved, deinterleaved, + mixedDown, mixedDownFromInterleaved, mixedFromInterleavedTo, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/framer.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/framer.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,83 @@ + +module framer; + +/** + * Framer expresses a stream (or a file) as a lazy list of (possibly + * overlapping) frames of mono data. + */ + +block = load block; +bf = load blockfuncs; +af = load audiofile; +win = load window; +fft = load fft; + +blockList framesize stream = + if stream.finished? then + (stream.close (); [] ); + else + block.resizedTo framesize (stream.readMono framesize) + :. \(blockList framesize stream); + fi; + +overlappingBlockList size hop stream valid buffer = + ( + b = stream.readMono hop; + obtained = block.length b; + + // Retain framesize - hop samples from old buffer, add hop samples + // (zero-padded if necessary) just read + buffer = block.concat + [block.rangeOf buffer hop (size-hop), + block.resizedTo hop b]; + + // Number of "valid" elements (not tail-end zero-padding) left in buffer + remaining = valid - (hop - obtained); + + if remaining <= 0 then + stream.close (); + []; + else + buffer :. \(overlappingBlockList size hop stream remaining buffer); + fi); + +frames { framesize, hop } stream = + if framesize == hop then + blockList framesize stream + else + overlappingBlockList framesize hop stream + framesize (block.zeros framesize); + fi; + +windowedFrames { framesize, hop, window } stream = + (win = window framesize; + map (bf.multiply win) (frames { framesize, hop } stream)); + +frequencyDomainFrames { framesize, hop } stream = + (f = fft.realForward framesize; + map f (windowedFrames { framesize, hop, window = win.hann } stream)); + +{ + frames, + windowedFrames, + frequencyDomainFrames, + + framesOfFile parameters filename = + case af.open filename of + Stream s: Frames (frames parameters s); + Error e: Error e; + esac, + + windowedFramesOfFile parameters filename = + case af.open filename of + Stream s: Frames (windowedFrames parameters s); + Error e: Error e; + esac, + + frequencyDomainFramesOfFile parameters filename = + case af.open filename of + Stream s: Frames (frequencyDomainFrames parameters s); + Error e: Error e; + esac, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/playback.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/playback.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,55 @@ + +module playback; + +block = load block; +fr = load framer; +af = load audiofile; +ch = load channels; + +import javax.sound.sampled: + AudioSystem, AudioFormat, AudioFormat$Encoding, SourceDataLine; + +import java.nio: ByteBuffer, ByteOrder; + +playBlock line b is ~SourceDataLine -> 'a -> () = + (len = block.length b; + samples = block.unblock b; + 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; + actual = line#write(bytes, 0, nb); + ()); + +play line blocks = for blocks (playBlock line); + +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, + play = play line, + channels = line#getFormat()#getChannels(), + close () = (line#drain(); line#close()), + }); + +playStream stream = + (line = open { rate = stream.sampleRate, channels = stream.channels }; + blocksize = 10240; + not stream.finished? loop + line.play [(ch.mixedFromInterleavedTo line.channels stream.channels + (stream.readInterleaved blocksize))]; + line.close(); + stream.close()); + +playFile filename = playStream (af.open filename); + +{ + open, play, playStream, playFile, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/stream.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/stream.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,38 @@ + +module stream; + +monoStream box = + (readAll' box = box.read (box.len - box.position); + { + get position () = box.position, + get channels () = 1, + get sampleRate () = box.rate, + get available () = box.len - box.position, + get finished? () = not (box.len > box.position), + read = box.read, + readInterleaved = box.read, + readMono = box.read, + readAll () = readAll' box, + readAllInterleaved () = readAll' box, + readAllMono () = readAll' box, + close = box.close, + }); + +stream box = + ({ + get position () = box.position, + get channels () = box.channels, + get sampleRate () = box.rate, + get available () = box.len - box.position, + get finished? () = not (box.len > box.position), + read = box.read, + readInterleaved = box.readInterleaved, + readMono = box.readMono, + readAll () = box.read (box.len - box.position), + readAllInterleaved () = box.readInterleaved (box.len - box.position), + readAllMono () = box.readMono (box.len - box.position), + close = box.close, + }); + +{ monoStream, stream } + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/syntheticstream.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/syntheticstream.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,47 @@ + +module syntheticstream; + +str = load stream; +vec = load fvector; +block = load block; + +generated rate generator seconds = + str.monoStream { + var position = 0, + len = int(seconds * rate + 0.5), + rate, + read count = + (rc = min count (len - position); + result = vec.zeros rc; + for [0..rc-1] do i: + result[i] := generator ((position + i) / rate) + done; + position := position + rc; + block.block result), + close = \(), + }; + +sinusoid rate freq seconds = + generated rate (sin . (* (freq / (2*pi * rate)))) seconds; + +whiteNoise rate seconds = + generated rate \((Math#random() * 2.0) - 1.0) seconds; + +precalculated rate data is number -> ~double[] -> 'a = + (n = vec.length data; + str.monoStream { + var position = 0, + len = n, + rate, + read count = + (rc = min count (len - position); + result = vec.rangeOf data position rc; + position := position + rc; + block.block result), + close = \(), + }); + +{ + generated, precalculated, sinusoid, whiteNoise, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/stream/test/test_framer.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/test/test_framer.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,94 @@ + +module test.test_framer; + +fr = load framer; +block = load block; + +{ compare, testStream } = load test.test; + +[ + +"framecount-2x2": \( + fr = fr.frames { framesize = 2, hop = 2 } (testStream 2); + compare (length fr) 1 +), + +"framecount-2x3": \( + fr = fr.frames { framesize = 2, hop = 2 } (testStream 3); + compare (length fr) 2 +), + +"framecount-2x4": \( + fr = fr.frames { framesize = 2, hop = 2 } (testStream 4); + compare (length fr) 2 +), + +"framecount-2.1x0": \( + fr = fr.frames { framesize = 2, hop = 1 } (testStream 0); + compare (length fr) 1 +), + +"framecount-2.1x1": \( + fr = fr.frames { framesize = 2, hop = 1 } (testStream 1); + compare (length fr) 2 +), + +"framecount-2.1x2": \( + fr = fr.frames { framesize = 2, hop = 1 } (testStream 2); + compare (length fr) 3 +), + +"framecount-2.1x3": \( + fr = fr.frames { framesize = 2, hop = 1 } (testStream 3); + compare (length fr) 4 +), + +"framecount-4.1x4": \( + fr = fr.frames { framesize = 4, hop = 1 } (testStream 4); + compare (length fr) 7 +), + +"framecount-4.3x4": \( + fr = fr.frames { framesize = 4, hop = 3 } (testStream 4); + compare (length fr) 2 +), + +"framecount-4.4x4": \( + fr = fr.frames { framesize = 4, hop = 4 } (testStream 4); + compare (length fr) 1 +), + +"framecount-3.2x4": \( + fr = fr.frames { framesize = 3, hop = 2 } (testStream 4); + compare (length fr) 3 +), + +"frames-2x5": \( + fr = fr.frames { framesize = 2, hop = 2 } (testStream 5); + expected = [ [1,2], [3,4], [5,0] ]; + compare (map block.list fr) expected; +), + +"frames-4.3x4": \( + fr = fr.frames { framesize = 4, hop = 3 } (testStream 4); + expected = [ [0,1,2,3], [3,4,0,0] ]; + compare (map block.list fr) expected; +), + +"frames-3.2x4": \( + fr = fr.frames { framesize = 3, hop = 2 } (testStream 4); + expected = [ [0,1,2], [2,3,4], [4,0,0] ]; + compare (map block.list fr) expected; +), + +"frames-3.1x6": \( + fr = fr.frames { framesize = 3, hop = 1 } (testStream 6); + expected = [ [0,0,1], [0,1,2], [1,2,3], [2,3,4], + [3,4,5], [4,5,6], [5,6,0], [6,0,0] ]; + compare (map block.list fr) expected; +), + +] is hash boolean>; + + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/test/all.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/test/all.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,22 @@ + +program test.all; + +{ runTests } = load test.test; + +tests = [ +"fvector" : load test.test_fvector, +"framer" : load test.test_framer, +"blockfuncs" : load test.test_blockfuncs, +"complex" : load test.test_complex, +"fft" : load test.test_fft, +"vamppost" : load test.test_vamppost, +]; + +bad = sum (mapHash do name testHash: runTests name testHash done tests); + +if (bad > 0) then + println "\n** \(bad) test(s) failed!"; +else + () +fi + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/test/test.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/test/test.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,41 @@ + +module test.test; + +vec = load fvector; +ss = load syntheticstream; + +testStream n is number -> 'a = ss.precalculated 1000 (vec.vector [1..n]); + +compare obtained expected = + if obtained == expected then + true; + else + println "** expected: \(expected)\n obtained: \(obtained)"; + false; + fi; + +select f = fold do r x: if f x then x::r else r fi done []; + +failedTests testHash = + select (!= "") + (mapHash do name f: + if f () then "" else + println "Test \(name) failed"; + name; + fi + done testHash); + +runTests group testHash = + (failed = failedTests testHash; + good = (length testHash - length failed); + bad = length failed; + println "\(group): \(good)/\(good+bad) tests passed"; + if not empty? failed then + println "\(group): Failed tests [\(bad)]: \(strJoin ' ' failed)"; + fi; + bad); + +{ + testStream, compare, failedTests, runTests +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/transform/fft.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/transform/fft.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,53 @@ + +module fft; + +import edu.emory.mathcs.jtransforms.fft: DoubleFFT_1D; + +b = load block; +vec = load fvector; +complex = load complex; + +packedToComplex p = + (n = (vec.length p) / 2; + array + (map do i: + re = if i == n then p[1] else p[i*2] fi; + im = if i == 0 or i == n then 0 else p[i*2+1] fi; + complex.complex re im; + done [0..n])); + +complexToPacked arr = + (n = length arr; + v = vec.vector + (map do i: + ix = int (i/2); + if i == ix*2 then + complex.real arr[ix] + else + complex.imaginary arr[ix] + fi; + done [0..(n-1)*2-1]); + v[1] := complex.real arr[n-1]; + v); + +realForward n = + (d = new DoubleFFT_1D(n); + do bl: + v = b.vector bl; + d#realForward(v); + packedToComplex v; + done); + +realInverse n = + (d = new DoubleFFT_1D(n); + do arr: + v = complexToPacked arr; + d#realInverse(v, true); + b.block v; + done); + +{ +realForward, +realInverse, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/transform/test/test_fft.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/transform/test/test_fft.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,46 @@ + +module test.test_fft; + +{ realForward, realInverse } = load fft; +{ list, fromList } = load block; +{ complex } = load complex; + +{ compare } = load test.test; + +testFFT orig reals imags = + (out = realForward (length orig) (fromList orig); + back = realInverse (length orig) out; + compare out (array (map2 complex reals imags)) and compare orig (list back)); + +[ + +"dc": \( + testFFT [1,1,1,1] [4,0,0] [0,0,0]; +), + +"sine": \( + testFFT [0,1,0,-1] [0,0,0] [0,-2,0]; +), + +"cosine": \( + testFFT [1,0,-1,0] [0,2,0] [0,0,0]; +), + +"sineCosine": \( + testFFT [0.5,1,-0.5,-1] [0,1,0] [0,-2,0]; +), + +"nyquist": \( + testFFT [1,-1,1,-1] [0,0,4] [0,0,0]; +), + +"dirac": \( + testFFT [1,0,0,0] [1,1,1] [0,0,0] and + testFFT [0,1,0,0] [1,0,-1] [0,-1,0] and + testFFT [0,0,1,0] [1,-1,1] [0,0,0] and + testFFT [0,0,0,1] [1,0,-1] [0,1,0]; +), + +] is hash boolean>; + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/transform/window.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/transform/window.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,47 @@ + +module window; + +b = load block; +bf = load blockfuncs; + +cosinewin a0 a1 a2 a3 n = + b.fromList + (map do i: + a0 + - a1 * cos(2 * pi * i / n) + + a2 * cos(4 * pi * i / n) + - a2 * cos(6 * pi * i / n) + done [0..n-1]); + +hann = cosinewin 0.5 0.5 0.0 0.0; +hamming = cosinewin 0.54 0.46 0.0 0.0; +blackman = cosinewin 0.42 0.50 0.08 0.0; +nuttall = cosinewin 0.3635819 0.4891775 0.1365995 0.0106411; +blackmanHarris = cosinewin 0.35875 0.48829 0.14128 0.01168; +boxcar = b.consts 0.5; + +bartlett n = + b.fromList + (m = n/2; + concat [ + map do i: + i / m + done [0..m-1], + map do i: + 1.0 - (i / m) + done [0..m-1] + ]); + +windowed windowFunc frames = + case frames of + []: frames; + _: (first = head frames; + window = windowFunc (b.length first); + map (bf.multiply window) frames); + esac; + +{ +cosinewin, hann, hamming, blackman, nuttall, blackmanHarris, boxcar, bartlett, +windowed +}; + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/vamp/test/test_vamppost.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vamp/test/test_vamppost.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,72 @@ +module test.test_vamppost; + +vp = load vamppost; + +{ compare } = load test.test; + +untimed n = { timestamp = Untimed (), values = [n] }; +timed t n = { timestamp = Time t, values = [n] }; + +testdata = { + output = { sampleType = OneSamplePerStep () }, + config = { sampleRate = 1000, stepSize = 100 }, + features = [ + [], + [ untimed 1 ], + [ untimed 1, untimed 2 ], + [], + [ timed 1.1 1, untimed 2, timed 4 3 ] + ] +}; + +[ + +"fillOneSamplePerStep": \( + // All features returned within a single process call (i.e. within + // a single sub-list of the feature list) should be given the same + // timestamp; the timestamp increments according to the config + // step size between sub-lists + filled = vp.fillTimestamps + (testdata with { output = { sampleType = OneSamplePerStep () } }); + compare filled [ + timed 0.1 1 , + timed 0.2 1, timed 0.2 2 , + timed 0.4 1, timed 0.4 2, timed 0.4 3 + ]; +), + +"fillFixedSampleRate": \( + // "If the output feature's hasTimestamp field is true, the host + // should read and use the output feature's timestamp. The host + // may round the timestamp according to the sample rate given in + // the output descriptor's sampleRate field [...] If + // [hasTimestamp] is false, its time will be implicitly calculated + // by incrementing the time of the previous feature according to + // the [output descriptor's] sample rate". Note that the time is + // based on that of the previous feature, not that of the previous + // process cycle (as is the case with OneSamplePerStep features). + filled = vp.fillTimestamps + (testdata with { output = { sampleType = FixedSampleRate 5 } }); + compare filled [ + timed 0 1 , + timed 0.2 1, timed 0.4 2 , + timed 1.0 1, timed 1.2 2, timed 4.0 3 + ]; +), + +"fillVariableSampleRate": \( + // For VariableSampleRate outputs, the timestamps should always + // be left entirely alone by fillTimestamps -- it's an error for + // the plugin to return any features without valid timestamps, + // but it isn't the job of fillTimestamps to handle that error + filled = vp.fillTimestamps + (testdata with { output = { sampleType = VariableSampleRate 5 } }); + compare filled [ + untimed 1 , + untimed 1, untimed 2 , + timed 1.1 1, untimed 2, timed 4.0 3 + ]; +), + +] is hash boolean>; + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/vamp/vamp.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vamp/vamp.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,295 @@ +module vamp; + +import org.vamp_plugins: + Plugin, Plugin$InputDomain, + PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, + ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, + RealTime, Feature; + +import java.lang: UnsatisfiedLinkError; + +import java.util: Map, List; + +block = load block; +fr = load framer; +af = load audiofile; +vamprdf = load vamprdf; + +store = load yertle.store; + +realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); + +feature f is ~Feature -> 'a = { + timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, + duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, + values = f#values, + label = f#label, + }; + +featureList fl is ~Object -> 'a = + if nullptr? fl then [] + else + a = fl unsafely_as ~List; + result = array []; + itr = a#iterator(); + itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); + list result + fi; + +featureSet fs is ~Map -> 'a = + (numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); + s = [:]; + kk = list fs#keySet()#toArray(); + for kk do k: s[numberOf k] := featureList fs#get(k) done; + s); + +getStandardStore = + (s = store.newRdfStore (); + var loaded = false; + \(synchronized s do: + if not loaded then + vamprdf.loadSystemVampRdf s; + loaded := true + fi; + s + done) + ); + +getPluginPath () = + (try + map string PluginLoader#getInstance()#getPluginPath(); + catch UnsatisfiedLinkError e: + eprintln "Warning: Unable to obtain plugin path:\n\(e)"; + []; + yrt); + +listPlugins () = + (try + map string PluginLoader#getInstance()#listPlugins(); + catch UnsatisfiedLinkError e: + eprintln "Warning: Unable to obtain plugin list:\n\(e)"; + []; + yrt); + +categoryOf key = + list PluginLoader#getInstance()#getPluginCategory(key); + +inputDomain d is ~Plugin$InputDomain -> 'a = + if d == Plugin$InputDomain#FREQUENCY_DOMAIN then + FrequencyDomain () + else + TimeDomain () + fi; + +parameterDescriptor pd is ~ParameterDescriptor -> 'a = { + identifier = pd#identifier, + name = pd#name, + description = pd#description, + unit = pd#unit, + minValue = pd#minValue, + maxValue = pd#maxValue, + defaultValue = pd#defaultValue, + get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, + valueNames = map string pd#valueNames + }; + +sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = + if t == OutputDescriptor$SampleType#OneSamplePerStep then + OneSamplePerStep () + elif t == OutputDescriptor$SampleType#FixedSampleRate then + FixedSampleRate rate + else + VariableSampleRate rate + fi; + +structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = + (computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; + s = getStandardStore (); + noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; + if od#hasFixedBinCount and od#binCount == 0 then + Instants (); + elif od#hasDuration then + if computes != Unknown () then + if computes == Event noteIRI then Notes (); + else Regions (); + fi + elif od#hasFixedBinCount then + if od#binCount > 1 then Notes (); + elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); + else Regions (); + fi + else + Unknown (); + fi + elif od#hasFixedBinCount and od#binCount == 1 then + case computes of + Event e: + if strEnds? e "Segment" then Segmentation (); + else Curve (); + fi; + _: Curve (); + esac; + elif od#hasFixedBinCount and + od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then + Grid (); + else + Unknown (); + fi); + +outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = { + identifier = od#identifier, + name = od#name, + description = od#description, + get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, + get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi, + get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, + valueUnit = od#unit, + binNames = array (map string od#binNames), + sampleType = sampleType od#sampleType od#sampleRate, + hasDuration = od#hasDuration, + get computes () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, + get inferredStructure () = structureOf rdfOutputData od, + }; + +plugin key p is string -> ~Plugin -> 'a = + (rdfData = vamprdf.pluginDataByKey (getStandardStore ()) key; + { + plugin = p, + key, + get apiVersion () = p#getVampApiVersion(), + get identifier () = p#getIdentifier(), + get name () = p#getName(), + get description () = p#getDescription(), + get maker () = p#getMaker(), + get copyright () = p#getCopyright(), + get version () = p#getPluginVersion(), + get category () = PluginLoader#getInstance()#getPluginCategory(key), + get hasRdfDescription () = (rdfData != None ()), + get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, + get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), + parameterValue identifier = p#getParameter(identifier), + setParameterValue identifier value = p#setParameter(identifier, value), + get programs () = array (map string p#getPrograms()), + get currentProgram () = p#getCurrentProgram(), + selectProgram pr = p#selectProgram(pr), + get inputDomain () = inputDomain p#getInputDomain(), + get preferredBlockSize () = p#getPreferredBlockSize(), + get preferredStepSize () = p#getPreferredStepSize(), + get minChannelCount () = p#getMinChannelCount(), + get maxChannelCount () = p#getMaxChannelCount(), + initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize), + reset () = p#reset(), + get outputs () = + array case rdfData of + Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); + None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); + esac, + process blocks time is 'a -> ~RealTime -> 'b = + featureSet p#process((map block.floats blocks) as ~float[][], 0, time), + getRemainingFeatures () = featureSet p#getRemainingFeatures(), + dispose () = p#dispose(), + }); + +featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; + +outputNumberByName p name = + (outputs = p.outputs; + case find ((== name) . (.identifier)) outputs of + first::rest: index first outputs; + _: -1; + esac); + +loadPlugin rate key = + try + OK (plugin key + PluginLoader#getInstance()#loadPlugin(key, rate, + PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + + PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) + catch PluginLoader$LoadFailedException _: + Error "Failed to load Vamp plugin with key \(key)" + yrt; + +processed { p, sampleRate, hop } frames count + // I don't know why this type declaration is necessary. Without + // it, yeti records the return type as 'a and can't do anything + // useful with it (giving IncompatibleClassChangeError when + // e.g. accessing the values array) + is 'a -> 'b -> 'c -> + list>> = + case frames of + frame::rest: + p.process [frame] RealTime#frame2RealTime(count, sampleRate) + :. + \(processed { p, sampleRate, hop } rest (count + hop)); + _: + (rf = p.getRemainingFeatures (); + p.dispose (); + [rf]); + esac; + +converted { p, sampleRate, hop } outputNo fl = + map (featuresFromSet outputNo) fl; + +returnErrorFrom p stream text = (p.dispose (); stream.close (); Error text); + +processWith key p outputNo stream = + (blockSize = p.preferredBlockSize; + stepSize = p.preferredStepSize; + channels = 1; + params = { + p, sampleRate = stream.sampleRate, channels = 1, + framesize = blockSize, blockSize, hop = stepSize + }; + if p.initialise params then + OK { + key = key, + output = p.outputs[outputNo], + parameters = mapIntoHash id p.parameterValue + (map (.identifier) p.parameters), + config = { + channels, blockSize, stepSize, + sampleRate = stream.sampleRate + }, + features = converted params outputNo + (processed params (fr.frames params stream) 0) + }; + // If processing completed successfully, then p is + // disposed by processed and stream is closed by the + // framer + else + returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; + fi); + +process key output stream = + case loadPlugin stream.sampleRate key of + OK p: + outputNo = outputNumberByName p output; + if outputNo >= 0 then + processWith key p outputNo stream + else + outputs = strJoin ", " (map (.identifier) p.outputs); + returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are \(outputs))" + fi; + Error e: Error e; + esac; + +processFile key output filename = + case af.open filename of + Stream s: process key output s; + Error e: Error e; + esac; + +{ +get pluginPath = getPluginPath, +get pluginKeys = listPlugins, +loadPlugin, +categoryOf, +process, +processFile, +} + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/vamp/vamppost.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vamp/vamppost.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,99 @@ +module vamppost; + +fmat = load fmatrix; + +fillOneSamplePerStep config features = + (fill' n pending features = + case pending of + feature::rest: + stamped = feature with + { timestamp = Time ((n * config.stepSize) / config.sampleRate) }; + stamped :. \(fill' n rest features); + _: + if empty? features then [] + else fill' (n+1) (head features) (tail features); + fi; + esac; + fill' (-1) [] features); + +fillFixedSampleRate config rate features = + (eps = 0.0001; + fill' n pending features = + case pending of + feature::rest: + n = case feature.timestamp of + Untimed (): n + 1; + Time t: int (t * rate + eps); + esac; + stamped = feature with { timestamp = Time (n / rate) }; + stamped :. \(fill' n rest features); + _: + if empty? features then [] + else fill' n (head features) (tail features); + fi; + esac; + fill' (-1) [] features); + +fillTimestamps { output, config, features } = + case output.sampleType of + OneSamplePerStep (): + fillOneSamplePerStep config features; + FixedSampleRate rate: + fillFixedSampleRate config rate features; + VariableSampleRate _: + concat features; + esac; + +structureGrid binCount features = + if empty? features then + fmat.constMatrix binCount 0 0; + else + fmat.generate + do row col: + features[col].values[row]; + done binCount (length features); + fi; + +structure data = + (type = data.output.inferredStructure; + features = + case type of + Grid (): concat data.features; + _: fillTimestamps data; + esac; + binCount = + case data.output.binCount of + Fixed n: n; + _: 0; + esac; + case type of + Curve (): // No duration, one value + Curve features; + Grid (): // No duration, >1 value, not variable rate + Grid (structureGrid binCount (array features)); + Instants (): // Zero-valued features + Instants features; + Notes (): // Duration, at least one value (pitch or freq) + Notes features; + Regions (): // Duration, zero or more values + Regions features; + Segmentation (): // No duration, one value, segment type in RDF + Segmentation features; + Unknown (): // Other + Unknown features; + esac); + +postprocess data = + case data of + OK data: + structure data; + Error e: + Error e; + esac; + +{ +fillTimestamps, +postprocess +} + + diff -r 6d6627fbbb78 -r 77d3292bbf12 yetilab/vamp/vamprdf.yeti --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vamp/vamprdf.yeti Wed Mar 20 09:57:54 2013 +0000 @@ -0,0 +1,294 @@ + +module vamprdf; + +read = load yertle.read; +{ newRdfStore } = load yertle.store; + +import java.io: File; + +import org.vamp_plugins: PluginLoader; + +import java.lang: UnsatisfiedLinkError; + +getPluginPath () = + (try map string PluginLoader#getInstance()#getPluginPath(); + catch UnsatisfiedLinkError e: []; + yrt); + +systemVampRdfFiles () = + concat + (map do p: + map ((p ^ File#separator ^) . (.name)) + (filter do entry: + entry.file? and + (lc = strLower entry.name; + (strEnds? lc ".ttl") or + (strEnds? lc ".n3") or + (strEnds? lc ".nt")) + done (listDirectory false p)) + done (getPluginPath ())); + +addVampPrefixes store = + (store.addPrefix "vamp" "http://purl.org/ontology/vamp/"; + store.addPrefix "dc" "http://purl.org/dc/elements/1.1/"; + store.addPrefix "foaf" "http://xmlns.com/foaf/0.1/"; + store.addPrefix "owl" "http://www.w3.org/2002/07/owl#"; + store.addPrefix "af" "http://purl.org/ontology/af/"); + +loadSystemVampRdf store = + (addVampPrefixes store; + for (systemVampRdfFiles ()) do file: + case read.loadTurtleFile store ("file://" ^ file) file of + OK (): (); + Error e: eprintln + "WARNING: Failed to load Vamp plugin RDF file \"\(file)\": \(e)"; + esac + done); + +getGlobalPluginIndex () = + list (strSplit "\n" (fetchURL [ Timeout 10 ] (Handle getContents) + "http://www.vamp-plugins.org/rdf/plugins/index.txt")); + +//!!! need to cache these retrievals +parseGlobalVampRdf () = + (parse urls = + case urls of + url::rest: + (doc = fetchURL [ Timeout 10 ] (Handle getContents) url; + parsed = read.parseTurtleString url doc; + { url, parsed } :. \(parse rest)); + _: []; + esac; + parse (getGlobalPluginIndex ())); + +loadGlobalVampRdf store = + for (parseGlobalVampRdf ()) do { url, parsed }: + case read.loadParsedTriples store parsed of + OK (): (); + Error e: eprintln "WARNING: Failed to load Vamp RDF from URL \(url): \(e)"; + esac; + done; + +filterIRIsFromNodes nodes = + map do r: case r of IRI iri: iri; esac done + (filter do r: case r of IRI iri: true; _: false esac done nodes); + +subjects = map (.s); + +iriTypes = + map do t: + case t of + IRI iri: IRI iri; + Blank n: Blank n; + esac done; + +iriSubjects = iriTypes . subjects; + +allLibraryNodes store = + iriSubjects + (store.match { + s = Wildcard (), + p = Known (store.expand "a"), + o = Known (store.expand "vamp:PluginLibrary") + }); + +allPluginNodes store = + iriSubjects + (store.match { + s = Wildcard (), + p = Known (store.expand "a"), + o = Known (store.expand "vamp:Plugin") + }); + +pluginsWithId store id = + iriTypes + (filter do pnode: + store.contains { + s = pnode, + p = store.expand "vamp:identifier", + o = Literal { value = id, type = "", language = "" } + } + done (allPluginNodes store)); + +librariesWithId store id = + iriTypes + (filter do lnode: + store.contains { + s = lnode, + p = store.expand "vamp:identifier", + o = Literal { value = id, type = "", language = "" } + } + done (allLibraryNodes store)); + +splitPluginKey key = + (bits = strSplit ":" key; + reversed = reverse bits; + soname = strJoin ":" (reverse (tail reversed)); + identifier = head reversed; + { soname, identifier }); + +pluginNodesByKey store key = + (case splitPluginKey key of { soname, identifier }: + candidatePlugins = pluginsWithId store identifier; + candidateLibraries = librariesWithId store soname; + filter do pnode: + any do lnode: + store.contains { + s = lnode, + p = store.expand "vamp:available_plugin", + o = pnode + } + done candidateLibraries + done candidatePlugins + esac); + +libraryNodeFor store pluginNode = + case store.match { + s = Wildcard (), p = Known (store.expand "vamp:available_plugin"), o = Known pluginNode + } of + { s = IRI iri }::others: Some (IRI iri); + { s = Blank n }::others: Some (Blank n); + _: None (); + esac; + +textProperty store subject name = + case store.match { + s = Known subject, p = Known (store.expand name), o = Wildcard () + } of + { o = Literal { value = text } }::others: text; + _: ""; + esac; + +iriProperty store subject name = + case store.match { + s = Known subject, p = Known (store.expand name), o = Wildcard () + } of + { o = IRI iri }::others: IRI iri; + _: None (); + esac; + +nodeProperty store subject name = + case store.match { + s = Known subject, p = Known (store.expand name), o = Wildcard () + } of + { o = IRI iri }::others: Some (IRI iri); + { o = Blank n }::others: Some (Blank n); + _: None (); + esac; + +inputDomainOf store pluginNode = + case store.match { + s = Known pluginNode, p = Known (store.expand "vamp:input_domain"), o = Wildcard () + } of + { o = IRI iri }::others: + if IRI iri == store.expand "vamp:FrequencyDomain" + then FrequencyDomain () + else TimeDomain () + fi; + _: TimeDomain (); + esac; + +outputDescriptor store outputNode = + (tprop abbr = textProperty store outputNode abbr; + iprop abbr = iriProperty store outputNode abbr; + bprop abbr deflt = + (b = strLower (textProperty store outputNode abbr); + if b == "true" then true elif b == "false" then false else deflt fi); + nprop abbr = + try number (textProperty store outputNode abbr); catch Exception _: 0 yrt; + { + identifier = tprop "vamp:identifier", + name = tprop "dc:title", + description = tprop "dc:description", + rdfType = case iprop "a" of IRI iri: iri; _: "" esac, + valueUnit = tprop "vamp:unit", + binCount = + if bprop "vamp:fixed_bin_count" false + then Known (nprop "vamp:bin_count") + else Unknown () + fi, + computes = + case iprop "vamp:computes_event_type" of + IRI iri: Event iri; + _: case iprop "vamp:computes_signal_type" of + IRI iri: Signal iri; + _: case iprop "vamp:computes_feature_type" of + IRI iri: Feature iri; + _: Unknown (); + esac + esac + esac, + //!!! and some other properties + }); + +pluginDataByNode store pluginNode = + (tprop abbr = textProperty store pluginNode abbr; + nprop abbr = + try number (textProperty store pluginNode abbr); catch Exception _: 0 yrt; + soname = + case libraryNodeFor store pluginNode of + None (): ""; + Some n: textProperty store n "vamp:identifier"; + esac; + { + pluginKey = soname ^ ":" ^ tprop "vamp:identifier", + soname, + apiVersion = nprop "vamp:vamp_API_version", + identifier = tprop "vamp:identifier", + name = tprop "dc:title", + description = tprop "dc:description", + maker = + (tmaker = tprop "foaf:maker"; + if tmaker == "" then + case nodeProperty store pluginNode "foaf:maker" of + Some n: textProperty store n "foaf:name"; + None (): ""; + esac + else + tmaker + fi), + copyright = tprop "dc:rights", + version = tprop "owl:versionInfo", + category = tprop "vamp:category", + inputDomain = inputDomainOf store pluginNode, + infoURL = + (case iriProperty store pluginNode "foaf:page" of + IRI iri: iri; + None (): + case libraryNodeFor store pluginNode of + None (): ""; + Some n: + case iriProperty store n "foaf:page" of + IRI iri: iri; + None (): ""; + esac; + esac; + esac), + outputs = + (matches = store.match { s = Known pluginNode, + p = Known (store.expand "vamp:output"), + o = Wildcard () }; + array (map do t: + case t.o of + IRI iri: outputDescriptor store (IRI iri); + Blank n: outputDescriptor store (Blank n); + esac + done matches)), + }); + +pluginDataByKey store key = + case pluginNodesByKey store key of + node::others: Some (pluginDataByNode store node); + _: None () + esac; + +{ +loadSystemVampRdf, +loadGlobalVampRdf, +allPluginNodes, +allLibraryNodes, +pluginNodesByKey, +pluginDataByNode, +pluginDataByKey, +} +