2014-01-03 16:41:00 +01:00
|
|
|
AudioIO.jl
|
|
|
|
==========
|
2013-12-13 08:48:52 +01:00
|
|
|
|
2014-08-22 12:15:42 +02:00
|
|
|
[![Build Status](https://travis-ci.org/ssfrr/AudioIO.jl.png?branch=master)](https://travis-ci.org/ssfrr/AudioIO.jl)
|
2014-08-29 19:30:33 +02:00
|
|
|
[![Pkgs Status](http://pkg.julialang.org/badges/AudioIO_release.svg)](http://pkg.julialang.org/?pkg=AudioIO&ver=release)
|
2014-08-22 12:15:42 +02:00
|
|
|
[![Coverage Status](https://coveralls.io/repos/ssfrr/AudioIO.jl/badge.png?branch=master)](https://coveralls.io/r/ssfrr/AudioIO.jl?branch=master)
|
|
|
|
|
|
|
|
AudioIO interfaces to audio streams, including real-time recording, audio
|
|
|
|
processing, and playback through your sound card using PortAudio. It also
|
|
|
|
supports reading and writing audio files in a variety of formats. It is under
|
|
|
|
active development and the low-level API could change, but the basic
|
|
|
|
functionality (reading and writing files, the `play` function, etc.) should be
|
|
|
|
stable and usable by the general Julia community.
|
|
|
|
|
|
|
|
File I/O
|
|
|
|
--------
|
|
|
|
|
|
|
|
File I/O is handled by [libsndfile](http://www.mega-nerd.com/libsndfile/), so
|
|
|
|
we can support a wide variety of file and sample formats. Use the
|
|
|
|
`AudioIO.open` function to open a file. It has the same API as the built-in
|
|
|
|
Base.open, but returns an `AudioFile` type. Opening an audio file and reading
|
|
|
|
its contents into an array is as simple as:
|
|
|
|
|
|
|
|
```julia
|
|
|
|
f = AudioIO.open("data/never_gonna_give_you_up.wav")
|
|
|
|
data = read(f)
|
|
|
|
close(f)
|
|
|
|
```
|
|
|
|
|
|
|
|
Or to hand closing the file automatically (including in the case of unexpected
|
|
|
|
exceptions), we support the `do` block syntax:
|
|
|
|
|
|
|
|
```julia
|
|
|
|
data = AudioIO.open("data/never_gonna_let_you_down.wav") do f
|
|
|
|
read(f)
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
By default the returned array will be in whatever format the original audio file is
|
|
|
|
(Float32, UInt16, etc.). We also support automatic conversion by supplying a type:
|
|
|
|
|
|
|
|
```julia
|
|
|
|
data = AudioIO.open("data/never_gonna_run_around.wav") do f
|
|
|
|
read(f, Float32)
|
|
|
|
end
|
|
|
|
```
|
2013-12-13 08:48:52 +01:00
|
|
|
|
2013-12-30 12:29:43 +01:00
|
|
|
Basic Array Playback
|
|
|
|
--------------------
|
2013-12-13 08:48:52 +01:00
|
|
|
|
2013-12-30 12:29:43 +01:00
|
|
|
Arrays in various formats can be played through your soundcard. Currently the
|
2013-12-30 12:33:00 +01:00
|
|
|
native format that is delivered to the PortAudio backend is Float32 in the
|
|
|
|
range of [-1, 1]. Arrays in other sizes of float are converted. Arrays
|
2013-12-30 12:29:43 +01:00
|
|
|
in Signed or Unsigned Integer types are scaled so that the full range is
|
2013-12-30 12:33:00 +01:00
|
|
|
mapped to [-1, 1] floating point values.
|
2013-12-30 12:29:43 +01:00
|
|
|
|
|
|
|
To play a 1-second burst of noise:
|
|
|
|
|
2014-08-22 12:15:42 +02:00
|
|
|
```julia
|
|
|
|
julia> v = rand(44100) * 0.1
|
|
|
|
julia> play(v)
|
|
|
|
```
|
2013-12-30 12:29:43 +01:00
|
|
|
|
|
|
|
AudioNodes
|
|
|
|
----------
|
|
|
|
|
|
|
|
In addition to the basic `play` function you can create more complex networks
|
2013-12-30 12:33:00 +01:00
|
|
|
of AudioNodes in a render chain. In fact, when using the basic `play` to play
|
|
|
|
an Array, behind the scenes an instance of the ArrayPlayer type is created
|
2014-01-06 05:00:50 +01:00
|
|
|
and added to the master AudioMixer inputs. Audionodes also implement a `stop`
|
|
|
|
function, which will remove them from the render graph. When an implicit
|
|
|
|
AudioNode is created automatically, such as when using `play` on an Array, the
|
|
|
|
`play` function should return the audio node that is playing the Array, so it
|
|
|
|
can be stopped if desired.
|
2013-12-30 12:29:43 +01:00
|
|
|
|
|
|
|
To explictly do the same as above:
|
|
|
|
|
2014-08-22 12:15:42 +02:00
|
|
|
```julia
|
|
|
|
julia> v = rand(44100) * 0.1
|
|
|
|
julia> player = ArrayPlayer(v)
|
|
|
|
julia> play(player)
|
|
|
|
```
|
2013-12-30 12:29:43 +01:00
|
|
|
|
|
|
|
To generate 2 sin tones:
|
|
|
|
|
2014-08-22 12:15:42 +02:00
|
|
|
```julia
|
|
|
|
julia> osc1 = SinOsc(440)
|
|
|
|
julia> osc2 = SinOsc(660)
|
|
|
|
julia> play(osc1)
|
|
|
|
julia> play(osc2)
|
|
|
|
julia> stop(osc1)
|
|
|
|
julia> stop(osc2)
|
|
|
|
```
|
2013-12-30 12:29:43 +01:00
|
|
|
|
2014-01-06 05:00:50 +01:00
|
|
|
All AudioNodes must implement a `render` function that can be called to
|
2013-12-30 12:29:43 +01:00
|
|
|
retreive the next block of audio.
|
|
|
|
|
|
|
|
AudioStreams
|
|
|
|
------------
|
|
|
|
|
2014-01-06 05:00:50 +01:00
|
|
|
AudioStreams represent an external source or destination for audio, such as the
|
|
|
|
sound card. The `play` function attaches AudioNodes to the default stream
|
|
|
|
unless a stream is given as the 2nd argument.
|
2013-12-30 12:29:43 +01:00
|
|
|
|
|
|
|
AudioStream is an abstract type, which currently has a PortAudioStream subtype
|
|
|
|
that writes to the sound card, and a TestAudioStream that is used in the unit
|
|
|
|
tests.
|
|
|
|
|
|
|
|
Currently only 1 stream at a time is supported so there's no reason to provide
|
|
|
|
an explicit stream to the `play` function. The stream has a root mixer field
|
2013-12-30 12:33:00 +01:00
|
|
|
which is an instance of the AudioMixer type, so that multiple AudioNodes
|
2013-12-30 12:29:43 +01:00
|
|
|
can be heard at the same time. Whenever a new frame of audio is needed by the
|
|
|
|
sound card, the stream calls the `render` method on the root audio mixer, which
|
2013-12-30 12:33:00 +01:00
|
|
|
will in turn call the `render` methods on any input AudioNodes that are set
|
2013-12-30 12:29:43 +01:00
|
|
|
up as inputs.
|
2014-08-22 12:15:42 +02:00
|
|
|
|
|
|
|
Installation
|
|
|
|
------------
|
|
|
|
|
|
|
|
To install the latest release version, simply run
|
|
|
|
|
|
|
|
```julia
|
|
|
|
julia> Pkg.add("AudioIO")
|
|
|
|
```
|
|
|
|
|
|
|
|
If you want to install the lastest master, it's almost as easy:
|
|
|
|
|
|
|
|
```julia
|
|
|
|
julia> Pkg.clone("AudioIO")
|
|
|
|
julia> Pkg.build("AudioIO")
|
|
|
|
```
|
|
|
|
|