mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Bela: Drop support
This commit is contained in:
parent
d64b9e7782
commit
9a7ac1f743
8 changed files with 12 additions and 651 deletions
|
|
@ -331,7 +331,6 @@ void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>&
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio());
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela());
|
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());
|
||||||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe());
|
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe());
|
||||||
|
|
|
||||||
|
|
@ -106,12 +106,6 @@ void AudioIODeviceType::callDeviceChangeListeners()
|
||||||
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK() { return nullptr; }
|
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK() { return nullptr; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if JUCE_LINUX && JUCE_BELA
|
|
||||||
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Bela() { return new BelaAudioIODeviceType(); }
|
|
||||||
#else
|
|
||||||
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Bela() { return nullptr; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if JUCE_ANDROID
|
#if JUCE_ANDROID
|
||||||
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Android()
|
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Android()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -176,8 +176,6 @@ public:
|
||||||
static AudioIODeviceType* createAudioIODeviceType_OpenSLES();
|
static AudioIODeviceType* createAudioIODeviceType_OpenSLES();
|
||||||
/** Creates an Oboe device type if it's available on this platform, or returns null. */
|
/** Creates an Oboe device type if it's available on this platform, or returns null. */
|
||||||
static AudioIODeviceType* createAudioIODeviceType_Oboe();
|
static AudioIODeviceType* createAudioIODeviceType_Oboe();
|
||||||
/** Creates a Bela device type if it's available on this platform, or returns null. */
|
|
||||||
static AudioIODeviceType* createAudioIODeviceType_Bela();
|
|
||||||
|
|
||||||
/** @cond */
|
/** @cond */
|
||||||
[[deprecated ("You should call the method which takes a WASAPIDeviceMode instead.")]]
|
[[deprecated ("You should call the method which takes a WASAPIDeviceMode instead.")]]
|
||||||
|
|
|
||||||
|
|
@ -176,23 +176,23 @@
|
||||||
#include "native/juce_ALSA_linux.cpp"
|
#include "native/juce_ALSA_linux.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (JUCE_LINUX && JUCE_BELA)
|
#if JUCE_JACK
|
||||||
/* Got an include error here? If so, you've either not got the bela headers
|
/* Got an include error here? If so, you've either not got jack-audio-connection-kit
|
||||||
installed, or you've not got your paths set up correctly to find its header
|
installed, or you've not got your paths set up correctly to find its header files.
|
||||||
files.
|
|
||||||
|
The package you need to install to get JACK support is "libjack-dev".
|
||||||
|
|
||||||
|
If you don't have the jack-audio-connection-kit library and don't want to build
|
||||||
|
JUCE with low latency audio support, just set the JUCE_JACK flag to 0.
|
||||||
*/
|
*/
|
||||||
#include <Bela.h>
|
#include <jack/jack.h>
|
||||||
#include <Midi.h>
|
#include "native/juce_JackAudio_linux.cpp"
|
||||||
#include <juce_audio_basics/midi/juce_MidiDataConcatenator.h>
|
|
||||||
#include "native/juce_Bela_linux.cpp"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef SIZEOF
|
#undef SIZEOF
|
||||||
|
|
||||||
#if ! JUCE_BELA
|
#include <juce_audio_basics/midi/juce_MidiDataConcatenator.h>
|
||||||
#include <juce_audio_basics/midi/juce_MidiDataConcatenator.h>
|
#include "native/juce_Midi_linux.cpp"
|
||||||
#include "native/juce_Midi_linux.cpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
#elif JUCE_ANDROID
|
#elif JUCE_ANDROID
|
||||||
|
|
|
||||||
|
|
@ -127,13 +127,6 @@
|
||||||
#define JUCE_JACK 0
|
#define JUCE_JACK 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Config: JUCE_BELA
|
|
||||||
Enables Bela audio devices on Bela boards.
|
|
||||||
*/
|
|
||||||
#ifndef JUCE_BELA
|
|
||||||
#define JUCE_BELA 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Config: JUCE_USE_ANDROID_OBOE
|
/** Config: JUCE_USE_ANDROID_OBOE
|
||||||
Enables Oboe devices (Android only).
|
Enables Oboe devices (Android only).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,612 +0,0 @@
|
||||||
/*
|
|
||||||
==============================================================================
|
|
||||||
|
|
||||||
This file is part of the JUCE framework.
|
|
||||||
Copyright (c) Raw Material Software Limited
|
|
||||||
|
|
||||||
JUCE is an open source framework subject to commercial or open source
|
|
||||||
licensing.
|
|
||||||
|
|
||||||
By downloading, installing, or using the JUCE framework, or combining the
|
|
||||||
JUCE framework with any other source code, object code, content or any other
|
|
||||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
|
||||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
|
||||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
|
||||||
do not agree to the terms of these agreements, we will not license the JUCE
|
|
||||||
framework to you, and you must discontinue the installation or download
|
|
||||||
process and cease use of the JUCE framework.
|
|
||||||
|
|
||||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
|
||||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
|
||||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
|
||||||
|
|
||||||
Or:
|
|
||||||
|
|
||||||
You may also use this code under the terms of the AGPLv3:
|
|
||||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
||||||
|
|
||||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
|
||||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
|
||||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace juce
|
|
||||||
{
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
class MidiInput::Pimpl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static Array<Pimpl*> midiInputs;
|
|
||||||
|
|
||||||
Pimpl (const String& port, MidiInput* input, MidiInputCallback* callback)
|
|
||||||
: midiInput (input), midiPort (port), midiCallback (callback)
|
|
||||||
{
|
|
||||||
jassert (midiCallback != nullptr);
|
|
||||||
midiInputs.add (this);
|
|
||||||
|
|
||||||
buffer.resize (32);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Pimpl()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
midiInputs.removeAllInstancesOf (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
midi.readFrom (midiPort.toRawUTF8());
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop()
|
|
||||||
{
|
|
||||||
midi.enableParser (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void poll()
|
|
||||||
{
|
|
||||||
size_t receivedBytes = 0;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
auto data = midi.getInput();
|
|
||||||
|
|
||||||
if (data < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
buffer[receivedBytes] = (uint8) data;
|
|
||||||
receivedBytes++;
|
|
||||||
|
|
||||||
if (receivedBytes == buffer.size())
|
|
||||||
{
|
|
||||||
pushMidiData (static_cast<int> (receivedBytes));
|
|
||||||
receivedBytes = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receivedBytes > 0)
|
|
||||||
pushMidiData ((int) receivedBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Array<MidiDeviceInfo> getDevices (bool input)
|
|
||||||
{
|
|
||||||
Array<MidiDeviceInfo> devices;
|
|
||||||
|
|
||||||
for (auto& card : findAllALSACardIDs())
|
|
||||||
findMidiDevices (devices, input, card);
|
|
||||||
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pushMidiMessage (juce::MidiMessage& message)
|
|
||||||
{
|
|
||||||
concatenator.pushMidiData (message.getRawData(), message.getRawDataSize(), Time::getMillisecondCounter() * 0.001, midiInput, *midiCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void pushMidiData (int length)
|
|
||||||
{
|
|
||||||
concatenator.pushMidiData (buffer.data(), length, Time::getMillisecondCounter() * 0.001, midiInput, *midiCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8> buffer;
|
|
||||||
|
|
||||||
static Array<int> findAllALSACardIDs()
|
|
||||||
{
|
|
||||||
Array<int> cards;
|
|
||||||
int card = -1;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
auto status = snd_card_next (&card);
|
|
||||||
|
|
||||||
if (status != 0 || card < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
cards.add (card);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cards;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds all midi devices to the devices array of the given input/output type on the given card
|
|
||||||
static void findMidiDevices (Array<MidiDeviceInfo>& devices, bool input, int cardNum)
|
|
||||||
{
|
|
||||||
snd_ctl_t* ctl = nullptr;
|
|
||||||
auto status = snd_ctl_open (&ctl, ("hw:" + String (cardNum)).toRawUTF8(), 0);
|
|
||||||
|
|
||||||
if (status < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int device = -1;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
status = snd_ctl_rawmidi_next_device (ctl, &device);
|
|
||||||
|
|
||||||
if (status < 0 || device < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
snd_rawmidi_info_t* info;
|
|
||||||
snd_rawmidi_info_alloca (&info);
|
|
||||||
|
|
||||||
snd_rawmidi_info_set_device (info, (unsigned int) device);
|
|
||||||
snd_rawmidi_info_set_stream (info, input ? SND_RAWMIDI_STREAM_INPUT
|
|
||||||
: SND_RAWMIDI_STREAM_OUTPUT);
|
|
||||||
|
|
||||||
snd_ctl_rawmidi_info (ctl, info);
|
|
||||||
|
|
||||||
auto subCount = snd_rawmidi_info_get_subdevices_count (info);
|
|
||||||
|
|
||||||
for (size_t sub = 0; sub < subCount; ++sub)
|
|
||||||
{
|
|
||||||
snd_rawmidi_info_set_subdevice (info, sub);
|
|
||||||
|
|
||||||
status = snd_ctl_rawmidi_info (ctl, info);
|
|
||||||
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
String deviceName ("hw:" + String (cardNum) + "," + String (device) + "," + String (sub));
|
|
||||||
devices.add (MidiDeviceInfo (deviceName, deviceName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_ctl_close (ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
MidiInput* const midiInput;
|
|
||||||
String midiPort;
|
|
||||||
MidiInputCallback* const midiCallback;
|
|
||||||
|
|
||||||
Midi midi;
|
|
||||||
MidiDataConcatenator concatenator { 512 };
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
|
||||||
};
|
|
||||||
|
|
||||||
Array<MidiInput::Pimpl*> MidiInput::Pimpl::midiInputs;
|
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
class BelaAudioIODevice final : public AudioIODevice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BelaAudioIODevice() : AudioIODevice (BelaAudioIODevice::belaTypeName,
|
|
||||||
BelaAudioIODevice::belaTypeName)
|
|
||||||
{
|
|
||||||
Bela_defaultSettings (&defaultSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
~BelaAudioIODevice()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
StringArray getOutputChannelNames() override
|
|
||||||
{
|
|
||||||
StringArray result;
|
|
||||||
|
|
||||||
for (int i = 1; i <= actualNumberOfOutputs; i++)
|
|
||||||
result.add ("Out #" + std::to_string (i));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringArray getInputChannelNames() override
|
|
||||||
{
|
|
||||||
StringArray result;
|
|
||||||
|
|
||||||
for (int i = 1; i <= actualNumberOfInputs; i++)
|
|
||||||
result.add ("In #" + std::to_string (i));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array<double> getAvailableSampleRates() override { return { 44100.0 }; }
|
|
||||||
Array<int> getAvailableBufferSizes() override { /* TODO: */ return { getDefaultBufferSize() }; }
|
|
||||||
int getDefaultBufferSize() override { return defaultSettings.periodSize; }
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
String open (const BigInteger& inputChannels,
|
|
||||||
const BigInteger& outputChannels,
|
|
||||||
double sampleRate,
|
|
||||||
int bufferSizeSamples) override
|
|
||||||
{
|
|
||||||
if (sampleRate != 44100.0 && sampleRate != 0.0)
|
|
||||||
{
|
|
||||||
lastError = "Bela audio outputs only support 44.1 kHz sample rate";
|
|
||||||
return lastError;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings = defaultSettings;
|
|
||||||
|
|
||||||
auto numIns = getNumContiguousSetBits (inputChannels);
|
|
||||||
auto numOuts = getNumContiguousSetBits (outputChannels);
|
|
||||||
|
|
||||||
// Input and Output channels are numbered as follows
|
|
||||||
//
|
|
||||||
// 0 .. 1 - audio
|
|
||||||
// 2 .. 9 - analog
|
|
||||||
|
|
||||||
if (numIns > 2 || numOuts > 2)
|
|
||||||
{
|
|
||||||
settings.useAnalog = true;
|
|
||||||
settings.numAnalogInChannels = std::max (numIns - 2, 8);
|
|
||||||
settings.numAnalogOutChannels = std::max (numOuts - 2, 8);
|
|
||||||
settings.uniformSampleRate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.numAudioInChannels = std::max (numIns, 2);
|
|
||||||
settings.numAudioOutChannels = std::max (numOuts, 2);
|
|
||||||
|
|
||||||
settings.detectUnderruns = 1;
|
|
||||||
settings.setup = setupCallback;
|
|
||||||
settings.render = renderCallback;
|
|
||||||
settings.cleanup = cleanupCallback;
|
|
||||||
settings.interleave = 0;
|
|
||||||
|
|
||||||
if (bufferSizeSamples > 0)
|
|
||||||
settings.periodSize = bufferSizeSamples;
|
|
||||||
|
|
||||||
isBelaOpen = false;
|
|
||||||
isRunning = false;
|
|
||||||
callback = nullptr;
|
|
||||||
underruns = 0;
|
|
||||||
|
|
||||||
if (Bela_initAudio (&settings, this) != 0 || ! isBelaOpen)
|
|
||||||
{
|
|
||||||
lastError = "Bela_initAutio failed";
|
|
||||||
return lastError;
|
|
||||||
}
|
|
||||||
|
|
||||||
actualNumberOfInputs = jmin (numIns, actualNumberOfInputs);
|
|
||||||
actualNumberOfOutputs = jmin (numOuts, actualNumberOfOutputs);
|
|
||||||
|
|
||||||
channelInBuffer.calloc (actualNumberOfInputs);
|
|
||||||
channelOutBuffer.calloc (actualNumberOfOutputs);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() override
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
|
|
||||||
if (isBelaOpen)
|
|
||||||
{
|
|
||||||
Bela_cleanupAudio();
|
|
||||||
|
|
||||||
isBelaOpen = false;
|
|
||||||
callback = nullptr;
|
|
||||||
underruns = 0;
|
|
||||||
|
|
||||||
actualBufferSize = 0;
|
|
||||||
actualNumberOfInputs = 0;
|
|
||||||
actualNumberOfOutputs = 0;
|
|
||||||
|
|
||||||
channelInBuffer.free();
|
|
||||||
channelOutBuffer.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isOpen() override { return isBelaOpen; }
|
|
||||||
|
|
||||||
void start (AudioIODeviceCallback* newCallback) override
|
|
||||||
{
|
|
||||||
if (! isBelaOpen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isRunning)
|
|
||||||
{
|
|
||||||
if (newCallback != callback)
|
|
||||||
{
|
|
||||||
if (newCallback != nullptr)
|
|
||||||
newCallback->audioDeviceAboutToStart (this);
|
|
||||||
|
|
||||||
{
|
|
||||||
ScopedLock lock (callbackLock);
|
|
||||||
std::swap (callback, newCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newCallback != nullptr)
|
|
||||||
newCallback->audioDeviceStopped();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callback = newCallback;
|
|
||||||
isRunning = (Bela_startAudio() == 0);
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
{
|
|
||||||
if (isRunning)
|
|
||||||
{
|
|
||||||
callback->audioDeviceAboutToStart (this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lastError = "Bela_StartAudio failed";
|
|
||||||
callback->audioDeviceError (lastError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop() override
|
|
||||||
{
|
|
||||||
AudioIODeviceCallback* oldCallback = nullptr;
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
{
|
|
||||||
ScopedLock lock (callbackLock);
|
|
||||||
std::swap (callback, oldCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
Bela_stopAudio();
|
|
||||||
|
|
||||||
if (oldCallback != nullptr)
|
|
||||||
oldCallback->audioDeviceStopped();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPlaying() override { return isRunning; }
|
|
||||||
String getLastError() override { return lastError; }
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
int getCurrentBufferSizeSamples() override { return (int) actualBufferSize; }
|
|
||||||
double getCurrentSampleRate() override { return 44100.0; }
|
|
||||||
int getCurrentBitDepth() override { return 16; }
|
|
||||||
BigInteger getActiveOutputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfOutputs, true); return b; }
|
|
||||||
BigInteger getActiveInputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfInputs, true); return b; }
|
|
||||||
int getOutputLatencyInSamples() override { /* TODO */ return 0; }
|
|
||||||
int getInputLatencyInSamples() override { /* TODO */ return 0; }
|
|
||||||
int getXRunCount() const noexcept override { return underruns; }
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
static const char* const belaTypeName;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
bool setup (BelaContext& context)
|
|
||||||
{
|
|
||||||
actualBufferSize = context.audioFrames;
|
|
||||||
actualNumberOfInputs = (int) (context.audioInChannels + context.analogInChannels);
|
|
||||||
actualNumberOfOutputs = (int) (context.audioOutChannels + context.analogOutChannels);
|
|
||||||
isBelaOpen = true;
|
|
||||||
firstCallback = true;
|
|
||||||
|
|
||||||
ScopedLock lock (callbackLock);
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
callback->audioDeviceAboutToStart (this);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render (BelaContext& context)
|
|
||||||
{
|
|
||||||
// check for xruns
|
|
||||||
calculateXruns (context.audioFramesElapsed, context.audioFrames);
|
|
||||||
|
|
||||||
ScopedLock lock (callbackLock);
|
|
||||||
|
|
||||||
// Check for and process and midi
|
|
||||||
for (auto midiInput : MidiInput::Pimpl::midiInputs)
|
|
||||||
midiInput->poll();
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
{
|
|
||||||
jassert (context.audioFrames <= actualBufferSize);
|
|
||||||
jassert ((context.flags & BELA_FLAG_INTERLEAVED) == 0);
|
|
||||||
|
|
||||||
using Frames = decltype (context.audioFrames);
|
|
||||||
|
|
||||||
// Setup channelInBuffers
|
|
||||||
for (int ch = 0; ch < actualNumberOfInputs; ++ch)
|
|
||||||
{
|
|
||||||
if (ch < analogChannelStart)
|
|
||||||
channelInBuffer[ch] = &context.audioIn[(Frames) ch * context.audioFrames];
|
|
||||||
else
|
|
||||||
channelInBuffer[ch] = &context.analogIn[(Frames) (ch - analogChannelStart) * context.analogFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup channelOutBuffers
|
|
||||||
for (int ch = 0; ch < actualNumberOfOutputs; ++ch)
|
|
||||||
{
|
|
||||||
if (ch < analogChannelStart)
|
|
||||||
channelOutBuffer[ch] = &context.audioOut[(Frames) ch * context.audioFrames];
|
|
||||||
else
|
|
||||||
channelOutBuffer[ch] = &context.analogOut[(Frames) (ch - analogChannelStart) * context.audioFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->audioDeviceIOCallbackWithContext (channelInBuffer.getData(),
|
|
||||||
actualNumberOfInputs,
|
|
||||||
channelOutBuffer.getData(),
|
|
||||||
actualNumberOfOutputs,
|
|
||||||
(int) context.audioFrames,
|
|
||||||
{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup (BelaContext&)
|
|
||||||
{
|
|
||||||
ScopedLock lock (callbackLock);
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
callback->audioDeviceStopped();
|
|
||||||
}
|
|
||||||
|
|
||||||
const int analogChannelStart = 2;
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
uint64_t expectedElapsedAudioSamples = 0;
|
|
||||||
int underruns = 0;
|
|
||||||
bool firstCallback = false;
|
|
||||||
|
|
||||||
void calculateXruns (uint64_t audioFramesElapsed, uint32_t numSamples)
|
|
||||||
{
|
|
||||||
if (audioFramesElapsed > expectedElapsedAudioSamples && ! firstCallback)
|
|
||||||
++underruns;
|
|
||||||
|
|
||||||
firstCallback = false;
|
|
||||||
expectedElapsedAudioSamples = audioFramesElapsed + numSamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
static int getNumContiguousSetBits (const BigInteger& value) noexcept
|
|
||||||
{
|
|
||||||
int bit = 0;
|
|
||||||
|
|
||||||
while (value[bit])
|
|
||||||
++bit;
|
|
||||||
|
|
||||||
return bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
static bool setupCallback (BelaContext* context, void* userData) noexcept { return static_cast<BelaAudioIODevice*> (userData)->setup (*context); }
|
|
||||||
static void renderCallback (BelaContext* context, void* userData) noexcept { static_cast<BelaAudioIODevice*> (userData)->render (*context); }
|
|
||||||
static void cleanupCallback (BelaContext* context, void* userData) noexcept { static_cast<BelaAudioIODevice*> (userData)->cleanup (*context); }
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
BelaInitSettings defaultSettings, settings;
|
|
||||||
bool isBelaOpen = false, isRunning = false;
|
|
||||||
|
|
||||||
CriticalSection callbackLock;
|
|
||||||
AudioIODeviceCallback* callback = nullptr;
|
|
||||||
|
|
||||||
String lastError;
|
|
||||||
uint32_t actualBufferSize = 0;
|
|
||||||
int actualNumberOfInputs = 0, actualNumberOfOutputs = 0;
|
|
||||||
|
|
||||||
HeapBlock<const float*> channelInBuffer;
|
|
||||||
HeapBlock<float*> channelOutBuffer;
|
|
||||||
|
|
||||||
bool includeAnalogSupport;
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BelaAudioIODevice)
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* const BelaAudioIODevice::belaTypeName = "Bela Analog";
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
struct BelaAudioIODeviceType final : public AudioIODeviceType
|
|
||||||
{
|
|
||||||
BelaAudioIODeviceType() : AudioIODeviceType ("Bela") {}
|
|
||||||
|
|
||||||
StringArray getDeviceNames (bool) const override { return StringArray (BelaAudioIODevice::belaTypeName); }
|
|
||||||
void scanForDevices() override {}
|
|
||||||
int getDefaultDeviceIndex (bool) const override { return 0; }
|
|
||||||
int getIndexOfDevice (AudioIODevice* device, bool) const override { return device != nullptr ? 0 : -1; }
|
|
||||||
bool hasSeparateInputsAndOutputs() const override { return false; }
|
|
||||||
|
|
||||||
AudioIODevice* createDevice (const String& outputName, const String& inputName) override
|
|
||||||
{
|
|
||||||
// TODO: switching whether to support analog/digital with possible multiple Bela device types?
|
|
||||||
if (outputName == BelaAudioIODevice::belaTypeName || inputName == BelaAudioIODevice::belaTypeName)
|
|
||||||
return new BelaAudioIODevice();
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BelaAudioIODeviceType)
|
|
||||||
};
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
MidiInput::MidiInput (const String& deviceName, const String& deviceID)
|
|
||||||
: deviceInfo (deviceName, deviceID)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MidiInput::~MidiInput() = default;
|
|
||||||
void MidiInput::start() { internal->start(); }
|
|
||||||
void MidiInput::stop() { internal->stop(); }
|
|
||||||
|
|
||||||
Array<MidiDeviceInfo> MidiInput::getAvailableDevices()
|
|
||||||
{
|
|
||||||
return Pimpl::getDevices (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
MidiDeviceInfo MidiInput::getDefaultDevice()
|
|
||||||
{
|
|
||||||
return getAvailableDevices().getFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<MidiInput> MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback)
|
|
||||||
{
|
|
||||||
if (deviceIdentifier.isEmpty())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::unique_ptr<MidiInput> midiInput (new MidiInput (deviceIdentifier, deviceIdentifier));
|
|
||||||
midiInput->internal = std::make_unique<Pimpl> (deviceIdentifier, midiInput.get(), callback);
|
|
||||||
|
|
||||||
return midiInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<MidiInput> MidiInput::createNewDevice (const String&, MidiInputCallback*)
|
|
||||||
{
|
|
||||||
// N/A on Bela
|
|
||||||
jassertfalse;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
StringArray MidiInput::getDevices()
|
|
||||||
{
|
|
||||||
StringArray deviceNames;
|
|
||||||
|
|
||||||
for (auto& d : getAvailableDevices())
|
|
||||||
deviceNames.add (d.name);
|
|
||||||
|
|
||||||
return deviceNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MidiInput::getDefaultDeviceIndex()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<MidiInput> MidiInput::openDevice (int index, MidiInputCallback* callback)
|
|
||||||
{
|
|
||||||
return openDevice (getAvailableDevices()[index].identifier, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
// TODO: Add Bela MidiOutput support
|
|
||||||
class MidiOutput::Pimpl {};
|
|
||||||
MidiOutput::~MidiOutput() = default;
|
|
||||||
void MidiOutput::sendMessageNow (const MidiMessage&) {}
|
|
||||||
Array<MidiDeviceInfo> MidiOutput::getAvailableDevices() { return {}; }
|
|
||||||
MidiDeviceInfo MidiOutput::getDefaultDevice() { return {}; }
|
|
||||||
std::unique_ptr<MidiOutput> MidiOutput::openDevice (const String&) { return {}; }
|
|
||||||
std::unique_ptr<MidiOutput> MidiOutput::createNewDevice (const String&) { return {}; }
|
|
||||||
StringArray MidiOutput::getDevices() { return {}; }
|
|
||||||
int MidiOutput::getDefaultDeviceIndex() { return 0;}
|
|
||||||
std::unique_ptr<MidiOutput> MidiOutput::openDevice (int) { return {}; }
|
|
||||||
|
|
||||||
} // namespace juce
|
|
||||||
|
|
@ -32,10 +32,6 @@
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if JUCE_BELA
|
|
||||||
extern "C" int cobalt_thread_mode();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace juce
|
namespace juce
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -384,14 +380,7 @@ int64 Time::getHighResolutionTicks() noexcept
|
||||||
{
|
{
|
||||||
timespec t;
|
timespec t;
|
||||||
|
|
||||||
#if JUCE_BELA
|
|
||||||
if (cobalt_thread_mode() == 0x200 /*XNRELAX*/)
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
|
||||||
else
|
|
||||||
__wrap_clock_gettime (CLOCK_MONOTONIC, &t);
|
|
||||||
#else
|
|
||||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
#endif
|
|
||||||
|
|
||||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue