Mercurial > hg > may
view yetilab/stream/audiofile.yeti @ 219:ff97765b1d1b matrix_opaque_immutable
More block -> vector
author | Chris Cannam |
---|---|
date | Sat, 11 May 2013 12:07:21 +0100 |
parents | a7f4eb1cdd72 |
children | 77c6a81c577f |
line wrap: on
line source
module yetilab.stream.audiofile; load yetilab.stream.streamtype; import javax.sound.sampled: AudioSystem, AudioInputStream, AudioFormat, AudioFormat$Encoding, UnsupportedAudioFileException; import java.io: File, IOException; import java.nio: ByteBuffer, ByteOrder; ch = load yetilab.stream.channels; vec = load yetilab.block.vector; 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, aistream is ~AudioInputStream } nframes = (channels = format#getChannels(); bytesPerSample = format#getSampleSizeInBits() / 8; bytes = new byte[nframes * channels * bytesPerSample]; bytesRead = aistream#read(bytes); if bytesRead <= 0 then vec.zeros 0; else n = int(bytesRead / bytesPerSample); doubles = new double[n]; decode { format } bytes doubles n; vec.vector doubles; fi; ); read' { format is ~AudioFormat, aistream is ~AudioInputStream } n = (b = readInterleaved' { format, aistream } n; channels = format#getChannels(); ch.deinterleaved channels b; ); readMono' { format is ~AudioFormat, aistream is ~AudioInputStream } n = (b = readInterleaved' { format, aistream } n; channels = format#getChannels(); ch.deinterleaved 1 (ch.mixedDownFromInterleaved channels b); ); // Note, all this assumes aistream is non-blocking (i.e. available() // is to the end of file). Our stream interface does support // indefinite and infinite streams, but audiofile doesn't yet. available' { format is ~AudioFormat, aistream is ~AudioInputStream } = aistream#available() / ((format#getSampleSizeInBits() / 8) * format#getChannels()); close' { aistream is ~AudioInputStream } = aistream#close(); openWithReader reader ch name is 'a -> number -> string -> stream = (f = new File(name); aistream = AudioSystem#getAudioInputStream(f); format = aistream#getFormat(); len = available' { format, aistream }; // at start of stream { get position () = len - available' { aistream, format }, get channels () = if ch == 0 then format#getChannels() else ch fi, get sampleRate () = format#getSampleRate(), get available () = Known (available' { aistream, format }), get finished? () = not (aistream#available() > 0), read = reader { aistream, format }, close () = close' { aistream }, }); open = openWithReader read' 0; openMono = openWithReader readMono' 1; { open, openMono } as { open is string -> stream, openMono is string -> stream }