Giter Site home page Giter Site logo

portaudio.jl's Introduction

PortAudio.jl

Dev Tests codecov

PortAudio.jl is a wrapper for libportaudio, which gives cross-platform access to audio devices. It is compatible with the types defined in SampledSignals.jl. It provides a PortAudioStream type, which can be read from and written to.

Opening a stream

The easiest way to open a source or sink is with the default PortAudioStream() constructor, which will open a 2-in, 2-out stream to your system's default device(s). The constructor can also take the input and output channel counts as positional arguments, or a variety of other keyword arguments. If named keyword arguments latency or samplerate are unspecified, then PortAudio will use device defaults.

PortAudioStream(inchans=2, outchans=2; eltype=Float32, samplerate=48000, latency=0.1)

You can open a specific device by adding it as the first argument, either as a PortAudioDevice instance or by name. You can also give separate names or devices if you want different input and output devices

PortAudioStream(device::PortAudioDevice, args...; kwargs...)
PortAudioStream(devname::AbstractString, args...; kwargs...)

You can get a list of your system's devices with the PortAudio.devices() function:

julia> PortAudio.devices()
14-element Vector{PortAudio.PortAudioDevice}:
 "sof-hda-dsp: - (hw:0,0)" 22
 "sof-hda-dsp: - (hw:0,3)" 02
 "sof-hda-dsp: - (hw:0,4)" 02
 "sof-hda-dsp: - (hw:0,5)" 02
 
 "upmix" 88
 "vdownmix" 66
 "dmix" 02
 "default" 3232

Reading and Writing

The PortAudioStream type has source and sink fields which are of type PortAudioSource <: SampleSource and PortAudioSink <: SampleSink, respectively. are subtypes of SampleSource and SampleSink, respectively (from SampledSignals.jl). This means they support all the stream and buffer features defined there. For example, if you load SampledSignals with using SampledSignals you can read 5 seconds to a buffer with buf = read(stream.source, 5s), regardless of the sample rate of the device.

PortAudio.jl also provides convenience wrappers around the PortAudioStream type so you can read and write to it directly, e.g. write(stream, stream) will set up a loopback that will read from the input and play it back on the output.

Debugging

If you are experiencing issues and wish to view detailed logging and debug information, set

ENV["JULIA_DEBUG"] = :PortAudio

before using the package.

Examples

Set up an audio pass-through from microphone to speaker

stream = PortAudioStream(2, 2)
try
    # cancel with Ctrl-C
    write(stream, stream)
finally
    close(stream)
end

Use do syntax to auto-close the stream

PortAudioStream(2, 2) do stream
    write(stream, stream)
end

Open your built-in microphone and speaker by name

PortAudioStream("default", "default") do stream
    write(stream, stream)
end

Record 10 seconds of audio and save to an ogg file

julia> import LibSndFile # must be in Manifest for FileIO.save to work

julia> using PortAudio: PortAudioStream

julia> using SampledSignals: s

julia> using FileIO: save

julia> stream = PortAudioStream(1, 0) # default input (e.g., built-in microphone)
PortAudioStream{Float32}
  Samplerate: 44100.0Hz
  2 channel source: "default"

julia> buf = read(stream, 10s)
480000-frame, 2-channel SampleBuf{Float32, 2, SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}
10.0 s at 48000 s⁻¹
▁▄▂▃▅▃▂▄▃▂▂▁▁▂▂▁▁▄▃▁▁▄▂▁▁▁▄▃▁▁▃▃▁▁▁▁▁▁▁▁▄▄▄▄▄▂▂▂▁▃▃▁▃▄▂▁▁▁▁▃▃▂▁▁▁▁▁▁▃▃▂▂▁▃▃▃▁▁▁▁
▁▄▂▃▅▃▂▄▃▂▂▁▁▂▂▁▁▄▃▁▁▄▂▁▁▁▄▃▁▁▃▃▁▁▁▁▁▁▁▁▄▄▄▄▄▂▂▂▁▃▃▁▃▄▂▁▁▁▁▃▃▂▁▁▁▁▁▁▃▃▂▂▁▃▃▃▁▁▁▁

julia> close(stream)

julia> save(joinpath(homedir(), "Desktop", "myvoice.ogg"), buf)

Play an audio signal through the default sound output device

using PortAudio, SampledSignals
S = 8192 # sampling rate (samples / second)
x = cos.(2pi*(1:2S)*440/S) # A440 tone for 2 seconds
PortAudioStream(0, 2; samplerate=S) do stream
    write(stream, x)
end

portaudio.jl's People

Contributors

abhayap avatar bauglir avatar bramtayl avatar calder avatar github-actions[bot] avatar goretkin avatar jakubwro avatar jefffessler avatar jg-854 avatar jpsamaroo avatar mroavi avatar rob-luke avatar ssfrr avatar staticfloat avatar tkelman avatar wherrera10 avatar wookay avatar zhemao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

portaudio.jl's Issues

Building the shim library?

Hi there,

I just noticed this section in README.md talking about the shim library, but there's no deps/src directory to be found. Just wondering if this is still necessary? If not, I'm curious how else you're handling callbacks from other threads.

Thanks!
Oliver

Problems when doing multi-threading

I'm trying to use PortAudio.jl in an application where the running audio code control parameters have to be updated in real-time, like with a GTK base GUI, or an OSC controller (or even possibly both at the same time).

The PA template code is here: https://github.com/grame-cncm/faust/blob/master-dev/architecture/julia/audio/portaudio.jl

And I have a OSC controller here: https://github.com/grame-cncm/faust/blob/master-dev/architecture/julia/gui/OSCUI.jl

PortAudio not found in registry for Julia 1.4.1

Hello team:
It is not PortAudio avaible in the repositories for julia 1.4.1?
I get the message:


(@v1.4) pkg> add PortAudio
ERROR: The following package names could not be resolved:
 * PortAudio (not found in project, manifest or registry)

, even after updating registry.

Simultaneous write and read

Hi @ssfrr

How would you recommend playing a sound while simultaneously recording? (Not a duplex stream, I’m not trying to play what is being recorded, I’m trying to play a predefined sound)

Thanks

Remove circular type definition

The circular type definition for PortAudioStream and PortAudioSource/Sink is clever but less inferable and not strictly necessary:

Instead, we could have a nested structure:

  • Portal (or some other name) would would contain a PortAudioDevice, buffer, and number of channels
  • PortAudioStream would contain input and output portals and the pointer to the stream
  • PortAudioSource/Sink would be trivial wrappers over PortAudioStream to show what context to use the stream in

Get sound working on more CI platforms

The core functionality of the package, that is, playing sounds, isn't included in routine CI. It's nice to have runtests_local.jl to run locally, but I think we should make it a priority to figure out a way to run it as part of CI. I'll do a bit of googling, there must be someone else who tests a sound package using CI.

Info about upcoming removal of packages in the General registry

As described in https://discourse.julialang.org/t/ann-plans-for-removing-packages-that-do-not-yet-support-1-0-from-the-general-registry/ we are planning on removing packages that do not support 1.0 from the General registry. This package has been detected to not support 1.0 and is thus slated to be removed. The removal of packages from the registry will happen approximately a month after this issue is open.

To transition to the new Pkg system using Project.toml, see https://github.com/JuliaRegistries/Registrator.jl#transitioning-from-require-to-projecttoml.
To then tag a new version of the package, see https://github.com/JuliaRegistries/Registrator.jl#via-the-github-app.

If you believe this package has erroneously been detected as not supporting 1.0 or have any other questions, don't hesitate to discuss it here or in the thread linked at the top of this post.

MIDI support?

Sorry for the triple issue file! I don't see any reference to MIDI, so just wondering if it's in the scope of either PortAudio.jl or JACKAudio.jl, or if there's another package that's recommended for dealing with midi.

Thanks!
Oliver

flush stale audio on read

If a stream hasn't been read from in a while (for as long as it takes for the buffer to fill up), the beginning of the next read will have stale audio in it. We should set a flag when the buffer overflows, and the next read should flush the buffer before reading.

JACK support?

I see a few references to JACK in the README and code, but when I run PortAudio.devices(), only my ALSA devices are showing up, even though my JACK server is running and accessible to other programs.

On a related note, I see that JACKAudio.jl has severely atrophied over the last few years. I'm wondering if it's worth resurrecting, or whether the same functionality is/should be available through this package.

Thanks!
Oliver

Support for PulseAudio

See #40 for some more context, but I figured it would be good to track this in a separate issue.

Currently PortAudio fails to load any plugins, which means it can't access PulseAudio devices.

I think we'll need to add the alsa-plugins tarball to the alsa_jll builder and bundle them together. I have a feeling this will require getting libpulse to build as well. This still leaves the question of how to get ALSA to look in the right place at runtime - apparently the library search path is set at build time (I believe with the --with-plugindir configure option). There's some more info and even a patch for ALSA here. A comment seems to indicate that we may be able to set the plugin path in a config file - so maybe we can bundle the config as well, we just need to get ALSA to load that.

It looks like as of 2013 (version 1.0.27.1) they set ALSA to stop searching ld.so.conf directories and instead rely on ALSA_PLUGIN_DIR. Bummer.

It looks like the snap folks may have a solution. This approach seems to completely ignore the system configuration and sets things up to route all ALSA sound through pulseaudio rather than exposing any direct ALSA hardware. I don't think that's the way to go for PortAudio.jl, but at least might have some good examples of how to configure things. There's an overview of the ALSA config system here

So I think these are the steps to resolve this:

  • Get alsa-plugins building as part of alsa_jll
  • See if --with-plugindir will take a relative path (to find the plugins relative to libasound.so
  • if that doesn't work, review the config docs and try including a config file that will set the plugin paths at runtime. This could either be in __init__() or a build.jl so it just happens once

PortAudio not working on Windows

Does PortAudio currently work on Windows? I have not been able to get it to work:

C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin>julia
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.4.7 (2016-09-18 16:17 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-w64-mingw32

julia> using PortAudio

julia> s = PortAudio.PortAudioStream("Microphone (2- USB camera)",1,0)

Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x653059e7 -- utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown
line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
utf8proc_NFKC at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
jl_generate_fptr at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
jl_trampoline at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
show at show.jl:168
print at strings/io.jl:8
jlcall_print_1548 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
print at strings/io.jl:18
show at show.jl:137
show at show.jl:105
jlcall_show_1542 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
print at strings/io.jl:8
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
print at strings/io.jl:18
show at C:\Users\Jeremy\.julia\v0.4\PortAudio\src\PortAudio.jl:218
jlcall_show_1535 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
anonymous at show.jl:1301
with_output_limit at show.jl:1278
showlimited at show.jl:1300
writemime at replutil.jl:4
jlcall_writemime_1533 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
display at REPL.jl:114
jlcall_display_1531 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
display at REPL.jl:117
jlcall_display_1529 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
display at multimedia.jl:151
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
print_response at REPL.jl:134
jlcall_print_response_1453 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
print_response at REPL.jl:121
jlcall_print_response_1452 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
anonymous at REPL.jl:624
run_interface at LineEdit.jl:1610
jlcall_run_interface_1073 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
run_frontend at REPL.jl:863
run_repl at REPL.jl:167
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
_start at client.jl:420
jlcall__start_505 at  (unknown line)
jl_apply_generic at C:\Users\Jeremy\AppData\Local\Julia-0.4.7\bin\libjulia.dll (unknown line)
unknown function (ip: 00000000004018D0)
unknown function (ip: 00000000004028AB)
unknown function (ip: 000000000040140C)
unknown function (ip: 000000000040153B)
BaseThreadInitThunk at C:\Windows\system32\kernel32.dll (unknown line)
RtlUserThreadStart at C:\Windows\SYSTEM32\ntdll.dll (unknown line)

Note: I edited my post because some output was not directly relevant to the crash.

Get sound working on more CI platforms

The main issue is that there aren't any audio devices on the Travis machines, so we can't even try reading and writing. Even if we could, there's no way to simulate input or output, so we can't really check that the right data is going in.

One option would be to put together a fake libportaudio with the same API but some additional mocking functionality. We'd only have to fake the subset of the library that we're actually using.

error on using Julia v.6 PortAudio from RPi3 / ARM

I'm aware this is a slight corner case. I am happy to upload some results of a build so that others don't have to do this manually.. but unsure how.

I can see the following instructions when attempting to using PortAudio

or perhaps the Julia on ARM support requires v0.7.0+??

julia> Pkg.update()
INFO: Updating METADATA...
INFO: Computing changes...
INFO: No packages to install, update or remove

julia> using PortAudio
INFO: Precompiling module PortAudio.

WARNING: deprecated syntax "typealias UnitQuantity{T} SIQuantity{T,0,0,0,0,0,0,0,0,0}" at /home/pi/.julia/v0.6/SIUnits/src/SIUnits.jl:15.
Use "UnitQuantity{T} = SIQuantity{T,0,0,0,0,0,0,0,0,0}" instead.

WARNING: deprecated syntax "abstract SIRanges{T,m,kg,s,A,K,mol,cd,rad,sr}<:Range{SIQuantity{T,m,kg,s,A,K,mol,cd,rad,sr}}" at /home/pi/.julia/v0.6/SIUnits/src/SIUnits.jl:27.
Use "abstract type SIRanges{T,m,kg,s,A,K,mol,cd,rad,sr}<:Range{SIQuantity{T,m,kg,s,A,K,mol,cd,rad,sr}} end" instead.

WARNING: deprecated syntax "typealias UnitTuple NTuple{9,Int}" at /home/pi/.julia/v0.6/SIUnits/src/SIUnits.jl:33.
Use "const UnitTuple = NTuple{9,Int}" instead.

WARNING: deprecated syntax "function .+(...)".
Use "function Base.broadcast(::typeof(+), ...)" instead.

WARNING: deprecated syntax "function .+(...)".
Use "function Base.broadcast(::typeof(+), ...)" instead.

WARNING: deprecated syntax "function .-(...)".
Use "function Base.broadcast(::typeof(-), ...)" instead.

WARNING: deprecated syntax "function .-(...)".
Use "function Base.broadcast(::typeof(-), ...)" instead.

WARNING: deprecated syntax "function ./(...)".
Use "function Base.broadcast(::typeof(/), ...)" instead.

WARNING: deprecated syntax "function .*(...)".
Use "function Base.broadcast(::typeof(*), ...)" instead.

WARNING: deprecated syntax "function .*(...)".
Use "function Base.broadcast(::typeof(*), ...)" instead.
ERROR: LoadError: InitError: Unsupported platform arm-linux-gnueabihf. You can build your own library by running `make` from /home/pi/.julia/v0.6/RingBuffers/src/pa_ringbuffer.jl/../deps/src
during initialization of module RingBuffers
while loading /home/pi/.julia/v0.6/PortAudio/src/PortAudio.jl, in expression starting on line 6

signal (11): Segmentation fault
while loading no file, in expression starting on line 0
Segmentation fault

Needs windows testing

I haven't had time to test the latest JLL-based version (now on master) on Windows yet, which I definitely want to do before I release. (Unless someone else gets a chance to try it out and can report back here) 😉

Segfault with input-only stream

I'm not sure where this bug is yet. Googling around hasn't turned up anything obvious. I'll need to debug it with gdb to see if I can figure out what's going on. Unfortunately I'm not going to have time to do that for the next couple weeks probably.

If anyone has some cycles to look into this it would be great. This was part of my runtests_local.jl test suite so it definitely wasn't happening before. Not sure if it's because of a different ALSA version, different PortAudio version, or what.

julia> using PortAudio
[ Info: Precompiling PortAudio [80ea8bcb-4634-5cb3-8ee8-a132660d1d2d]

julia> stream = PortAudioStream(0, 2)
PortAudioStream{Float32}
  Samplerate: 44100.0Hz

  2 channel sink: "HDA Intel PCH: ALC295 Analog (hw:0,0)"

julia> close(stream)

julia> stream = PortAudioStream(2, 0)

signal (11): Segmentation fault
in expression starting at REPL[5]:1
snd_pcm_avail_update at /workspace/srcdir/alsa-lib-1.2.1.1/src/pcm/pcm.c:2926
unknown function (ip: 0x7f6b628f4b3f)
Allocations: 8713990 (Pool: 8711901; Big: 2089); GC: 6
[1]    4775 segmentation fault (core dumped)  julia --color=yes

Plot example not working in MacOS

Ran the following with a fresh install of Julia v0.6.4 via JuliaPro

Pkg.add("WAV")
Pkg.add("DSP")
Pkg.add("PyPlot")

using DSP, WAV, PyPlot # "using" makes the listed modules available for the
                       # user, like "import" in other languages

# Loading and plotting an audio signal
s, fs = wavread("test.wav")

plot(0:1/fs:(length(s)-1)/fs, s)
xlabel("Time [s]")

Get's an error and nothing is plotted

INFO: METADATA is out-of-date — you may not have the latest version of PyPlot
INFO: Use `Pkg.update()` to get the latest versions of your packages
ERROR: LoadError: PyError (ccall(@pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, PyPtr), o, arg, C_NULL)) <type 'exceptions.ValueError'>
ValueError(u'x and y must have same first dimension, but have shapes (26439345,) and (13219673, 2)',)
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/pyplot.py", line 3317, in plot
    ret = ax.plot(*args, **kwargs)
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/__init__.py", line 1898, in inner
    return func(ax, *args, **kwargs)
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/axes/_axes.py", line 1406, in plot
    for line in self._get_lines(*args, **kwargs):
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/axes/_base.py", line 407, in _grab_next_args
    for seg in self._plot_args(remaining, kwargs):
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/axes/_base.py", line 385, in _plot_args
    x, y = self._xy_from_xy(x, y)
  File "/Users/emcp/Library/Python/2.7/lib/python/site-packages/matplotlib/axes/_base.py", line 244, in _xy_from_xy
    "have shapes {} and {}".format(x.shape, y.shape))

Stacktrace:
 [1] pyerr_check at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/exception.jl:60 [inlined]
 [2] pyerr_check at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/exception.jl:64 [inlined]
 [3] macro expansion at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/exception.jl:84 [inlined]
 [4] #_pycall#86(::Array{Any,1}, ::Function, ::PyCall.PyObject, ::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/PyCall.jl:709
 [5] _pycall(::PyCall.PyObject, ::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/PyCall.jl:697
 [6] #pycall#90(::Array{Any,1}, ::Function, ::PyCall.PyObject, ::Type{PyCall.PyAny}, ::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/PyCall.jl:731
 [7] pycall(::PyCall.PyObject, ::Type{PyCall.PyAny}, ::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyCall/src/PyCall.jl:731
 [8] #plot#85(::Array{Any,1}, ::Function, ::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyPlot/src/PyPlot.jl:172
 [9] plot(::StepRangeLen{Float32,Base.TwicePrecision{Float32},Base.TwicePrecision{Float32}}, ::Vararg{Any,N} where N) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PyPlot/src/PyPlot.jl:169
 [10] include_string(::String, ::String) at ./loading.jl:522
 [11] include_string(::Module, ::String, ::String) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Compat/src/Compat.jl:88
 [12] (::Atom.##112#116{String,String})() at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Atom/src/eval.jl:109
 [13] withpath(::Atom.##112#116{String,String}, ::String) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/CodeTools/src/utils.jl:30
 [14] withpath(::Function, ::String) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Atom/src/eval.jl:38
 [15] hideprompt(::Atom.##111#115{String,String}) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Atom/src/repl.jl:67
 [16] macro expansion at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Atom/src/eval.jl:106 [inlined]
 [17] (::Atom.##110#114{Dict{String,Any}})() at ./task.jl:80
while loading /Users/emcp/Dev/git/EMCP/bootstrap-julia-audio-record/bootstrap-audio-mp3.jl, in expression starting on line 11

Error Using v1.0.0 Julia and Port Audio on RPi3

I know I have a separate issue for v0.6.0, thought it might be better to create a ticket for what I am seeing using the latest binary for ARM v7 Julia v1.0.0

Thankfully I got the binary working after a weekend of failed compilations.. and just discovered I need to set JULIA_HOME .. guessing this is a path to the install of the binary?

Import Pkg
Pkg.add("PortAudio")

result

┌ Error: Error building `PortAudio`: 
│ ERROR: LoadError: UndefVarError: JULIA_HOME not defined
│ Stacktrace:
│  [1] top-level scope at none:0
│  [2] include at ./boot.jl:317 [inlined]
│  [3] include_relative(::Module, ::String) at ./loading.jl:1038
│  [4] include(::Module, ::String) at ./sysimg.jl:29
│  [5] include(::String) at ./client.jl:388
│  [6] top-level scope at none:0
│ in expression starting at /home/pi/.julia/packages/PortAudio/LfjGt/deps/build.jl:5
└ @ Pkg.Operations /buildworker/worker/package_linuxarmv7l/build/usr/share/julia/stdlib/v1.0/Pkg/src/Operations.jl:1068

I could update the docs or maybe users know enough to deal with this without explicit explanation.. can PR if needed

in .bashrc

export JULIA_HOME=/path/to/julia-v1.0.0`

then do

julia

once inside Julia

import Pkg
Pkg.build("PortAudio")

but I still get

julia> Pkg.build("PortAudio")
...
  Building WinRPM ──────────→ `~/.julia/packages/WinRPM/rDDZz/deps/build.log`
  Building PortAudio ───────→ `~/.julia/packages/PortAudio/LfjGt/deps/build.log`
┌ Error: Error building `PortAudio`: 
│ ERROR: LoadError: UndefVarError: JULIA_HOME not defined
│ Stacktrace:
│  [1] top-level scope at none:0
│  [2] include at ./boot.jl:317 [inlined]
│  [3] include_relative(::Module, ::String) at ./loading.jl:1038
│  [4] include(::Module, ::String) at ./sysimg.jl:29
│  [5] include(::String) at ./client.jl:388
│  [6] top-level scope at none:0
│ in expression starting at /home/pi/.julia/packages/PortAudio/LfjGt/deps/build.jl:5
└ @ Pkg.Operations /buildworker/worker/package_linuxarmv7l/build/usr/share/julia/stdlib/v1.0/Pkg/src/Operations.jl:1068

julia> exit
exit (generic function with 2 methods)

julia> quit()
ERROR: UndefVarError: quit not defined
Stacktrace:
 [1] top-level scope at none:0

switch back to depending on Suppressor.jl

A while ago we copy/pasted some corrected Suppressor.jl code while waiting for a PR to be merged. I think that's fixed now so we should remove the code and just depend on Suppressor.jl

Pkg.build("Portaudio") install not working on Arch

Something seems to be funky about the way BinDeps is installing portaudio on ArchLinux.

LoadError: failed process: Process(`sudo pacman -S --needed portaudio`, ProcessExited(1)) [1]
while loading /home/sfr-dev/.julia/v0.6/PortAudio/deps/build.jl, in expression starting on line 26

Running the same command from the terminal works fine, though it does ask for confirmation, so maybe that's tripping BinDeps up.

Error buffer overflow handles accesses invalid `name` field

The error buffer overflow handler uses the stream's name field, which no longer exists. Seems to pop up when using a stream in a Jupyter notebook, possibly when it goes out of scope and gets GC'ed...

The error is:

ERROR (unhandled task failure): type PortAudioStream has no field name
Stacktrace:
[1] handle_errors(::PortAudio.PortAudioStream{Float32}) at /Users/srussell/.julia/v0.6/PortAudio/src/PortAu
dio.jl:261
[2] (::PortAudio.##10#12{PortAudio.PortAudioStream{Float32}})() at ./task.jl:335

here is the offending line

Add source build fallback to BinDeps config

When users are on systems that don't have root access or aren't on platforms we have explicit BinDeps package install support, we should also try to pull the source and build it as a fallback.

Low-level code uses `length` instead of `nframes`

(reported by @feima0011):

In the code here:

function Pa_ReadStream(stream::PaStream, buf::Array, frames::Integer=length(buf),
show_warnings::Bool=true)
frames <= length(buf) || error("Need a buffer at least $frames long")
err = ccall((:Pa_ReadStream, libportaudio), PaError,
(PaStream, Ptr{Void}, Culong),
stream, buf, frames)
handle_status(err, show_warnings)
buf
end
function Pa_WriteStream(stream::PaStream, buf::Array, frames::Integer=length(buf),
show_warnings::Bool=true)
frames <= length(buf) || error("Need a buffer at least $frames long")
err = ccall((:Pa_WriteStream, libportaudio), PaError,
(PaStream, Ptr{Void}, Culong),
stream, buf, frames)
handle_status(err, show_warnings)
nothing
end

we use length(buf) where we should be using nframes(buf. In general this code shouldn't be called by users and I'm not actually sure if this gets called by the user-facing code, but it would be good to fix nonetheless.

Register package?

Any reason it isn't registered? Waiting for version 1.0? That's not usually done...

So far I only tried to install (also in 1.5) and do:

(@v1.7) pkg> add https://github.com/JuliaAudio/PortAudio.jl

julia> @time @time using PortAudio
  2.997193 seconds (3.08 M allocations: 194.936 MiB, 5.83% gc time, 0.25% compilation time)
  3.079666 seconds (3.14 M allocations: 198.743 MiB, 5.67% gc time, 0.24% compilation time)

julia> @time @time using PortAudio
  1.079439 seconds (667.89 k allocations: 37.415 MiB, 1.93% gc time, 99.99% compilation time)
  1.079529 seconds (667.94 k allocations: 37.419 MiB, 1.93% gc time, 99.98% compilation time)

julia> @time using PortAudio
  0.000127 seconds (81 allocations: 6.062 KiB)

Support call-back functions?

At least according to the PortAudio documentation, using a call-back function to access buffers seems like it would be more performant

Pkg.add not enough to use library?

I see the instructions in the README.md call out to install portaudio.. I also noticed Homebrew doing a lot of installing when I Pkg.add("PortAudio")

everything was successful on adding, but when I goto use a basic call it fails.. do I need to do additional work outside of Pkg.add()?

julia> PortAudio.devices()
ERROR: UndefVarError: PortAudio not defined
Stacktrace:
 [1] macro expansion at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/Atom/src/repl.jl:118 [inlined]
 [2] anonymous at ./<missing>:?

julia> Pkg.status()
202 required packages:
 - ASTInterpreter2               0.1.1
 - AbstractFFTs                  0.3.2
...
 - Polynomials                   0.4.0
 - PooledArrays                  0.2.2
 - PortAudio                     1.0.0
 - PositiveFactorizations        0.1.0
 - Primes                        0.3.0
...
 - ZMQ                           0.6.2
 - ZipFile                       0.6.0
2 additional packages:
 - RingBuffers                   1.1.2
 - SampledSignals                1.1.2

julia>

Not supporting Julia 1.0

Unsatisfiable requirements detected for package PortAudio [80ea8bcb]:
PortAudio [80ea8bcb] log:
├─possible versions are: [0.2.1, 0.3.0, 0.4.0, 0.5.0, 1.0.0] or uninstalled
├─restricted to versions * by an explicit requirement, leaving only versions [0.2.1, 0.3.0, 0.4.0, 0.5.0, 1.0.0]
└─restricted by julia compatibility requirements to versions: uninstalled — no versions left
*unable to install

Cant add PortAudio?

I don't know why I can't add this package:


(@v1.4) pkg> add PortAudio   Updating registry at `~/.julia/registries/General`
   Updating git-repo `https://github.com/JuliaRegistries/General.git`
ERROR: The following package names could not be resolved:
 * PortAudio (not found in project, manifest or registry)

un-closed stream can segfault on julia quit

to reproduce:

using PortAudio

buf = cos.(2pi*220*linspace(0,1,48000)) * 0.2
str = PortAudioStream()
write(str, buf)
#close(str)

uncomment close and it won't segfault. Probably objects are getting finalized in an unexpected order.

Support Duplex Streams

(conversation with @seebk continued from seebk/PortAudio.jl#3)

I think that rather than PortAudioSink and PortAudioSource there will be a PortAudioStream with sink and source fields, so you can open a duplex stream but then use the same read/write API defined in SampleTypes. It probably also makes sense to define the read!, read, and write fields on PortAudioStream to reference the internal sink and source. So duplex processing would look like:

stream = PortAudioStream(Float32, 48kHz, 2, 2) # two in, two out
buf = SampleBuf(Float32, 48kHz, 1024, 2)
while true
    read!(stream, buf)
    # do your processing on buf
    write(stream, buf)
end

Does that seem like it would work for your use case?

I've also been talking to some of the PortAudio developers and I'm planning on re-working how I interface with PortAudio again to use the callback interface. This way we can be sure we never have underruns on the PortAudio side because the callback gets run in the high-priority audio thread. We have to be pretty careful to make sure we don't do anything non-threadsafe in the callback, but I think I've got it mostly worked out. I'm planning on doing the duplex stuff described above at the same time as this refactor.

BoundsError with large resampling

Some problem with bounds calculation when resampling with large scale factors. We really should just switch to using the resampling in DSP.jl.

stream = PortAudioStream()
write(stream, SinSource(eltype(stream), samplerate(stream)*0.5, [220Hz, 330Hz]), 3s)
write(stream, SinSource(eltype(stream), samplerate(stream)*1.5, [220Hz, 330Hz]), 3s)
flush(stream)
close(stream)

gives

Samplerate-converting writing: Error During Test
  Got an exception of type BoundsError outside of a @test
  BoundsError: attempt to access 4096×2 SampledSignals.SampleBuf{Float32,2,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}} at index [4097,1]
   in throw_boundserror(::SampledSignals.SampleBuf{Float32,2,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::Tuple{Int64,Int64}) at ./abstractarray.jl:265
   in checkbounds at ./abstractarray.jl:194 [inlined]
   in _getindex at ./abstractarray.jl:702 [inlined]
   in getindex at ./abstractarray.jl:669 [inlined]
   in unsafe_write(::SampledSignals.ResampleSink{PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}},SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0},SampledSignals.SampleBuf{Float32,2,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}},Array{Float32,1}}, ::SampledSignals.SampleBuf{Float32,2,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}) at /Users/srussell/.julia/v0.5/SampledSignals/src/SampleStream.jl:365
   in unsafe_write(::SampledSignals.ResampleSink{PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}},SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0},SampledSignals.SampleBuf{Float32,2,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}},Array{Float32,1}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::Int64, ::Int64) at /Users/srussell/.julia/v0.5/SampledSignals/src/SampleStream.jl:134
   in #write#2(::Int64, ::Function, ::PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::Int64) at /Users/srussell/.julia/v0.5/SampledSignals/src/SampleStream.jl:112
   in (::Base.#kw##write)(::Array{Any,1}, ::Base.#write, ::PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::Int64) at ./<missing>:0
   in #write#1(::Int64, ::Function, ::PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::SIUnits.SIQuantity{Int64,0,0,1,0,0,0,0,0,0}) at /Users/srussell/.julia/v0.5/SampledSignals/src/SampleStream.jl:73
   in write(::PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::SIUnits.SIQuantity{Int64,0,0,1,0,0,0,0,0,0}) at /Users/srussell/.julia/v0.5/SampledSignals/src/SampleStream.jl:67
   in write(::PortAudio.PortAudioStream{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}, ::SampledSignals.SinSource{Float32,SIUnits.SIQuantity{Float64,0,0,-1,0,0,0,0,0,0}}, ::SIUnits.SIQuantity{Int64,0,0,1,0,0,0,0,0,0}) at /Users/srussell/.julia/v0.5/PortAudio/src/PortAudio.jl:198
   in macro expansion; at /Users/srussell/.julia/v0.5/PortAudio/test/runtests.jl:120 [inlined]
   in macro expansion; at /Users/srussell/.julia/v0.5/BaseTestNext/src/BaseTestNext.jl:552 [inlined]
   in macro expansion; at /Users/srussell/.julia/v0.5/PortAudio/test/runtests.jl:118 [inlined]
   in macro expansion; at /Users/srussell/.julia/v0.5/BaseTestNext/src/BaseTestNext.jl:552 [inlined]
   in anonymous at ./<missing>:?
   in include_from_node1(::String) at ./loading.jl:426
   in process_options(::Base.JLOptions) at ./client.jl:262
   in _start() at ./client.jl:318

More frequent dropouts on Linux

So far I've tested using portaudio's ALSA backend to talk to PulseAudio, which is talking to my soundcard using ALSA, so it's going portaudio->alsa->pulseaudio->alsa->hardware. Not sure where the issue is but I'm getting dropouts.

Next troubleshooting step is to add some time_ns() calls to start to quantify the scheduling latency to see if that's causing a problem.

One possible issue with the various layers of audio systems is that something's causing the portaudio callback to get called back-to-back (e.g. if the underlying system wants 4096 samples and our portaudio blocksize is 2048 samples, it might be possible for our callback to be called twice in a row).

If this turns out to be the problem, one solution would be to make sure that our buffer size is at least as large as the underlying library.

The other would be to implement a ringbuffer running in the audio context, similar to what we do in JACKAudio.jl. The problem is that libportaudio doesn't include a lockfree ringbuffer implementation, so we'd either need to implement our own in Julia or find a way to distribute the JACK, portaudio, or soundio ringbuffer implementations in C.

UPDATE:
There's more good info on portaudio latency / buffering here.
Also, it looks like it would be better to give a buffer size of 0 so that portaudio can choose the best buffer size without doing any intermediate re-buffering, and use the suggested latency field when we open the stream to choose whether we want higher or lower latency. The issue then becomes somehow communicating from the callback how big the transfer buffers should be, and synchronizing the creation of new buffers if the buffer size changes.

Update Readme

Hello, thanks for this package (and for the others too!).

I tried the "Record 10 seconds of audio and save to an ogg file" example and it seems to be missing using FileIO or something like that so save is defined. Otherwise I got ERROR: UndefVarError: save not defined.

Also it seems the last section about the shim library is outdated? I saw that was in the master branch but not anymore. Maybe you are aware of this but I'd rather say it.

error on package when running Pkg.update()

seeing this when updating on OSX inside juliapro

julia> Pkg.update()
INFO: Updating METADATA...
INFO: Updating cache of Polynomials...
INFO: Updating cache of RangeArrays...
ERROR (unhandled task failure): type PortAudioStream has no field name
Stacktrace:
 [1] handle_errors(::PortAudio.PortAudioStream{Float32}) at /Applications/JuliaPro-0.6.4.1.app/Contents/Resources/pkgs-0.6.4.1/v0.6/PortAudio/src/PortAudio.jl:261
 [2] (::PortAudio.##10#12{PortAudio.PortAudioStream{Float32}})() at ./task.jl:335
INFO: Updating cache of CategoricalArrays...
INFO: Updating cache of MbedTLS...
INFO: Updating cache of BinDeps...
INFO: Updating cache of StatsBase...
INFO: Updating cache of MacroTools...
INFO: Updating cache of DataValues...
INFO: Updating cache of DataFrames...
INFO: Updating cache of Distributions...

unsure if this is something I did or the package itself

some strange buffer issues

I'm seeing some strange behavior where it sounds like chunks are being played out of order, or skipped, or something. Not sure if this is related to a recent change in my code or what. Possibly (but not likely) due to Julia changes somewhere around 1.1, as I haven't been using this much lately.
Currently on master of RingBuffers and the julia1 branch of PortAudio
MWE:

freq = range(0.05, 0.5, length=48000)
phase = cumsum(freq)
sig = cos.(phase)
PortAudioStream(; blocksize=4096*8) do io
    write(io, sig * 0.05)
    write(io, sig * 0.05)
    write(io, sig * 0.05)
    write(io, sig * 0.05)
    write(io, sig * 0.05)
    write(io, sig * 0.05)
end

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

Add tests to compare requested read time to elapsed time and/or samplebuf length

So this was inspired by a problem in an LED effects program I'm working on in Julia. Basically, the largest bug with that program is that its CPU usage spikes to ~4-6x normal during and after silent times from the audio card. Since I've already checked 80+% of my code for type stability, I decided to look into what was coming out of PortAudio during times of intermittent silence. Let's just say things got stranger.

As you can see below, PortAudio.jl is not sampling for nearly as long as it should be in a lot of circumstances. I'm not sure why this is happening, but I could see a scenario where this would cause the havoc I'm seeing further up the stack. This is off Ubuntu 17.04 running on the default PortAudio device (pretty sure that ends up being pulse).

Any ideas about why PortAudio might be doing this would be much appreciated (or other thoughts on escalating CPU usage!).

julia> @time @sync begin test = read(stream, 5.0s) end
  2.346361 seconds (8.79 k allocations: 3.764 MiB)
220500-frame, 2-channel SampleBuf{Float32, 2}
5.0s sampled at 44100.0Hz
▄▆▆▁▁▁▁▁▁▁▁▁▁▁▃▆▆▁▁▁▆▄▁▆▂▆▅▃▃▁▃▆▆▆▆▁▁▁▆▂▁▁▁▁▁▁▁▁▁▁▆▅▆▂▁▁▆▅▆▆▄▆▄▃▆▆▃▁▁▁▆▃▁▁▁▅▆▆▆▂
▄▆▆▁▁▁▁▁▁▁▁▁▁▁▃▆▆▁▁▁▆▄▁▆▂▆▅▃▃▁▃▆▆▆▆▁▁▁▆▂▁▁▁▁▁▁▁▁▁▁▆▅▆▂▁▁▆▅▆▆▄▆▄▃▆▆▃▁▁▁▆▃▁▁▁▅▆▆▆▂

julia> @time @sync begin test = read(stream, 5.0*48000) end
ERROR: MethodError: no method matching read(::PortAudio.PortAudioSource{Float32}, ::Float64)
Closest candidates are:
  read(::AbstractString, ::Any...) at io.jl:160
  read(::IO, ::Any) at io.jl:528
  read(::RingBuffers.RingBuffer{T}, ::Any) where T at /home/murphyj/.julia/v0.6/RingBuffers/src/RingBuffers.jl:257
  ...
Stacktrace:
 [1] read(::PortAudio.PortAudioStream{Float32}, ::Float64) at /home/murphyj/.julia/v0.6/PortAudio/src/PortAudio.jl:231

julia> @time @sync begin test = read(stream, 5*48000) end
  2.291248 seconds (9.65 k allocations: 4.103 MiB)
240000-frame, 2-channel SampleBuf{Float32, 2}
5.442176870748299s sampled at 44100.0Hz
▁▁▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▆▄▁▆▁▁▂▆▁▁▁▆▅▅▆▆▄▁▁▆▂▆▆▃▆▆▆▆▆▆▂▁▆▆▅▄▆▆▄▁▁▆▆▄▆▆▆▁▁▁▁▆▆▄▆▆▃▃▆▆
▁▁▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▆▄▁▆▁▁▂▆▁▁▁▆▅▅▆▆▄▁▁▆▂▆▆▃▆▆▆▆▆▆▂▁▆▆▅▄▆▆▄▁▁▆▆▄▆▆▆▁▁▁▁▆▆▄▆▆▃▃▆▆

julia> @time begin @sync begin test = read(stream, 5*48000) end end
  5.320691 seconds (9.51 k allocations: 4.094 MiB)
240000-frame, 2-channel SampleBuf{Float32, 2}
5.442176870748299s sampled at 44100.0Hz
▅▆▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
▅▆▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

julia> @time begin @sync begin test = read(stream, 5.0s) end end
  4.728189 seconds (8.79 k allocations: 3.765 MiB, 0.15% gc time)
220500-frame, 2-channel SampleBuf{Float32, 2}
5.0s sampled at 44100.0Hz
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

julia> @time begin @sync begin test = read(stream, 44100*5) end end
  3.151310 seconds (8.74 k allocations: 3.762 MiB)
220500-frame, 2-channel SampleBuf{Float32, 2}
5.0s sampled at 44100.0Hz
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▃▆▁▁▁▁▁▃▆▆▆▃▁▁▆▆▆▂▆▅▁▁▁▁▁▁▁▁▁▁▁▁▆▂▁▄▆▁▁▆▂▁▁▁▆▂▁▁▆▅▁
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▃▆▁▁▁▁▁▃▆▆▆▃▁▁▆▆▆▂▆▅▁▁▁▁▁▁▁▁▁▁▁▁▆▂▁▄▆▁▁▆▂▁▁▁▆▂▁▁▆▅▁

julia> @time begin @sync begin test = read(stream, 48000*5) end end
  2.979866 seconds (9.50 k allocations: 4.094 MiB)
240000-frame, 2-channel SampleBuf{Float32, 2}
5.442176870748299s sampled at 44100.0Hz
▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▆▆▁▆▁▆▆▃▁▁▁▁▁▁▁▆▆▆▄▂▄▆▆▃▃▁▁▁▁▁▆▆▆▆▆▁▁▁▄▆▁▆▆▄▁▁▁▁▆▃▃
▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▆▆▆▆▁▆▁▆▆▃▁▁▁▁▁▁▁▆▆▆▄▂▄▆▆▃▃▁▁▁▁▁▆▆▆▆▆▁▁▁▄▆▁▆▆▄▁▁▁▁▆▃▃

julia>

Provide more information about unanticipated host errors

Can't get sound stream from audio input (mic), tried on several machines running Windows 10:

using PortAudio
devices = PortAudio.devices()
for d in devices
    try
        stream = PortAudioStream(d.name, 2, 0) # same errors with 4, 0
        @show stream
    catch err
        @error err
    end
end

Any ideas?

underrun can cause stream to drop using ALSA

@SimonDanisch reported an issue where he got an underrun and it cause the stream to block indefinitely (on a read! call).

The error he got was:

ALSA lib pcm.c:7963:(snd_pcm_recover) underrun occurred
Expression 'err' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3355
Expression 'ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3881
Expression 'PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 425

I'm guessing what happened is that his system was busy doing something else when the portaudio callback happened so it didn't get scheduled quickly enough and didn't make its deadline, so ALSA dropped the stream. We should see if we can catch this condition and re-build the ALSA stream if it drops.

Additional options for lower latency / realtime use

(reported by @feima0011 in #16)

In my project, I do some real time audio signal processing.
I determine at each time what write to the speaker, according
to the data I received from the microphones.

PortAudio C program offers two methods for communicating audio data:
(1) an asynchronous callback interface, where PortAudio calls a user
defined callback function when new audio data is available or required, and
(2) synchronous read and write functions which can be used in a blocking or
non-blocking manner.

The Portaudio.jl provided the blocking API, but internally use the asynchronous
callback interface provided by the C program. That cause some problems to me.
I want to
(1) control the time when data are received, and the time when the data are output.
(2) the latency between the read and write process.
(3) the blocking API provided by Portaudio C program directly.

The advantage of ASIO api over the other audio api on Windows,
is its low latency feature.

I my project, I have to make sure that the latency of a read-and-write process is as
small as possible.

Trying to reach computers audio before it goes to speakers..

I am on a Mac, have Julia working and PortAudio working.. successfully ran a microphone example.. however what I am looking to do is record the audio coming from applications on my mac.

I wonder if I need to route the audio using another piece of software like https://rogueamoeba.com/loopback/ .. in order to record what's playing on the mac .. via PortAudio.jl

Or do I just need to read the output properly.. below is my attempt to reading speaker output.. the code never seems to complete 20 seconds and I am forced to close it.

Pkg.add("PortAudio")
Pkg.add("LibSndFile")

using PortAudio, SampledSignals, LibSndFile

PortAudio.devices()

stream = PortAudioStream("Built-in Output", 0, 2)

print("Starting...20seconds")
buf = read(stream, 20s)
print("Buffer closed") . // never reaches here
save(joinpath(pwd(), "Data", "output.ogg" ), buf)

Cannot compile on Raspberry Pi / armv8

Trying to use Port Audio on a Raspberry Pi 3A+ running Raspberry Pi OS. It fails to compile, errors below. These lines in expression starting at /home/pi/.julia/packages/FFMPEG_jll/xCSqL/src/wrappers/armv7l-linux-gnueabihf.jl:9 and in expression starting at /home/pi/.julia/packages/alsa_plugins_jll/hnVoe/src/wrappers/armv7l-linux-gnueabihf.jl:4 make me thing it's might be something to do with the arm version (Pi 3A+ is armv8), although I thought it was backwards compatible so armv7 should be fine.

Any ideas how to fix this?

julia> using PortAudio
[ Info: Precompiling PortAudio [80ea8bcb-4634-5cb3-8ee8-a132660d1d2d]
ERROR: LoadError: LoadError: Failed to precompile libvorbis_jll [f27f6e37-5d2b-51aa-960f-b287f2bc3b7a] to /home/pi/.julia/compiled/v1.6/libvorbis_jll/jl_DUodEy.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::Base.TTY, internal_stdout::Base.TTY, ignore_loaded_modules::Bool)
    @ Base ./loading.jl:1385
  [3] compilecache(pkg::Base.PkgId, path::String)
    @ Base ./loading.jl:1329
  [4] _require(pkg::Base.PkgId)
    @ Base ./loading.jl:1043
  [5] require(uuidkey::Base.PkgId)
    @ Base ./loading.jl:936
  [6] require(into::Module, mod::Symbol)
    @ Base ./loading.jl:923
  [7] include(mod::Module, _path::String)
    @ Base ./Base.jl:386
  [8] top-level scope
    @ ~/.julia/packages/JLLWrappers/bkwIo/src/toplevel_generators.jl:170
  [9] include
    @ ./Base.jl:386 [inlined]
 [10] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::String)
    @ Base ./loading.jl:1235
 [11] top-level scope
    @ none:1
 [12] eval
    @ ./boot.jl:360 [inlined]
 [13] eval(x::Expr)
    @ Base.MainInclude ./client.jl:446
 [14] top-level scope
    @ none:1
in expression starting at /home/pi/.julia/packages/FFMPEG_jll/xCSqL/src/wrappers/armv7l-linux-gnueabihf.jl:9
in expression starting at /home/pi/.julia/packages/FFMPEG_jll/xCSqL/src/FFMPEG_jll.jl:2
ERROR: LoadError: LoadError: Failed to precompile FFMPEG_jll [b22a6f82-2f65-5046-a5b2-351ab43fb4e5] to /home/pi/.julia/compiled/v1.6/FFMPEG_jll/jl_hBvL2U.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::Base.TTY, internal_stdout::Base.TTY, ignore_loaded_modules::Bool)
    @ Base ./loading.jl:1385
  [3] compilecache(pkg::Base.PkgId, path::String)
    @ Base ./loading.jl:1329
  [4] _require(pkg::Base.PkgId)
    @ Base ./loading.jl:1043
  [5] require(uuidkey::Base.PkgId)
    @ Base ./loading.jl:936
  [6] require(into::Module, mod::Symbol)
    @ Base ./loading.jl:923
  [7] include(mod::Module, _path::String)
    @ Base ./Base.jl:386
  [8] top-level scope
    @ ~/.julia/packages/JLLWrappers/bkwIo/src/toplevel_generators.jl:170
  [9] include
    @ ./Base.jl:386 [inlined]
 [10] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::String)
    @ Base ./loading.jl:1235
 [11] top-level scope
    @ none:1
 [12] eval
    @ ./boot.jl:360 [inlined]
 [13] eval(x::Expr)
    @ Base.MainInclude ./client.jl:446
 [14] top-level scope
    @ none:1
in expression starting at /home/pi/.julia/packages/alsa_plugins_jll/hnVoe/src/wrappers/armv7l-linux-gnueabihf.jl:4
in expression starting at /home/pi/.julia/packages/alsa_plugins_jll/hnVoe/src/alsa_plugins_jll.jl:2
ERROR: LoadError: Failed to precompile alsa_plugins_jll [5ac2f6bb-493e-5871-9171-112d4c21a6e7] to /home/pi/.julia/compiled/v1.6/alsa_plugins_jll/jl_2eiURx.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::Base.TTY, internal_stdout::Base.TTY, ignore_loaded_modules::Bool)
    @ Base ./loading.jl:1385
  [3] compilecache(pkg::Base.PkgId, path::String)
    @ Base ./loading.jl:1329
  [4] _require(pkg::Base.PkgId)
    @ Base ./loading.jl:1043
  [5] require(uuidkey::Base.PkgId)
    @ Base ./loading.jl:936
  [6] require(into::Module, mod::Symbol)
    @ Base ./loading.jl:923
  [7] include
    @ ./Base.jl:386 [inlined]
  [8] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::Nothing)
    @ Base ./loading.jl:1235
  [9] top-level scope
    @ none:1
 [10] eval
    @ ./boot.jl:360 [inlined]
 [11] eval(x::Expr)
    @ Base.MainInclude ./client.jl:446
 [12] top-level scope
    @ none:1
in expression starting at /home/pi/.julia/packages/PortAudio/iJ74y/src/PortAudio.jl:1
ERROR: Failed to precompile PortAudio [80ea8bcb-4634-5cb3-8ee8-a132660d1d2d] to /home/pi/.julia/compiled/v1.6/PortAudio/jl_vZ5E35.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::Base.TTY, internal_stdout::Base.TTY, ignore_loaded_modules::Bool)
   @ Base ./loading.jl:1385
 [3] compilecache(pkg::Base.PkgId, path::String)
   @ Base ./loading.jl:1329
 [4] _require(pkg::Base.PkgId)
   @ Base ./loading.jl:1043
 [5] require(uuidkey::Base.PkgId)
   @ Base ./loading.jl:936
 [6] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:923

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.