Closed freesig closed 6 years ago
On further investigation it appears ASIO will only ever call a single buffer_switch
function. On top of that all input and output buffers should actually be allocated at the exact same time via
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferI nfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
Any subsequent calls to this function actually overwrite old calls.
This is going to require a decent rewrite. I also don't think it will be possible to have mutiple input and output streams.
TL/DR I made the assumption that calls to ASIO were independently associated with an input or an output but it seems they use a one big global call for everything approach 👎
ASIOCreateBuffers() // Allocates new memory
ASIOCreateBuffers() // Allocates new memory
// First memory is still allocated and won't be free'd so we have a memory leak
I'm thinking we need an approach where each call to prepare_input/output_stream()
cleans up all previous buffers.
So:
This means there is no way to have multiple streams to an ASIO driver. Infact it doesn't really make sense. We basically have zero or one input and zero or one output.
I'm not sure how we make this clear to the user of CPAL though because they could call build_output_stream()
twice and it will implicitly destroy the first stream
I think to clarify this a bit more we can look at what a stream is in CPAL vs ASIO. CPAL A stream is
ASIO A stream is
For example:
let asio_stream = Vec<ASIOBufferInfo>;
struct ASIOBufferInfo {
input: bool
channel_index: usize,
double_buffer: *mut [f32; 2],
}
Note here that the asio_stream is a mixture of input and output buffers where as the cpal has a seperate stream for input and output. CPAL also supports multiple streams where ASIO only supports a single stream of combined input and output
ProblemThis is no longer relevant due to the comments bellowWhen constructing an
AsioStream
ASIO takes a pointer to the buffer_switch function:Note this can't be a closure. However we need a buffer_switch per stream. They access the
buffer_callback
via a static like this:The reason for this is that cpal needs access to the buffer_callback so that it can set it. But ASIO also needs access to it via the function
buffer_switch
callback so that it can call it each tick.I can't think of anyway to change this to be a Vec instead of an array because you need a
buffer_switch
function for eachbuffer_callback
. Thebuffer_switch
needs to be hard coded to call the rightbuffer_callback
. Note the 0 in this line:I can't use a closure to capture which index it is because closure can't be plain function pointers (required by ASIO).
I can imagine that this could be possible using a macro to generate all the buffer_switch functions. I think this would need to happen at compile time and therefor we would need to have some sort of upper_limit on the amount of streams.
AsioStreams
I should clarify here that an AsioStream will contain all of your channels for an input or an output. For example with a single ASIO device there would be no way to create multiple output streams to the same device because each time you create a new output stream the buffers would get reallocated and the old ones would be dropped. The same is true for input. However if you were trying to connect to multiple different ASIO devices then this issue would limit you to a single device.