ALSA Sequencer connections.
This commit is contained in:
+12
-3
@@ -532,7 +532,7 @@ private:
|
||||
|
||||
std::string GetAtomObjectType(uint8_t *pData)
|
||||
{
|
||||
LV2_Atom_Object *pAtom = (LV2_Atom_Object *)pData;
|
||||
LV2_Atom_Object *pAtom = (LV2_Atom_Object *)pData;
|
||||
if (pAtom->atom.type != uris.atom_Object)
|
||||
{
|
||||
throw std::invalid_argument("Not an Lv2 Object");
|
||||
@@ -602,7 +602,6 @@ private:
|
||||
this->outputRingBuffer.reset();
|
||||
|
||||
audioDriver = nullptr;
|
||||
alsaSequencer = nullptr;
|
||||
}
|
||||
|
||||
void ZeroBuffer(float *buffer, size_t nframes)
|
||||
@@ -1259,6 +1258,7 @@ public:
|
||||
Close();
|
||||
CleanRestartThreads(true);
|
||||
audioDriver = nullptr;
|
||||
this->alsaSequencer = nullptr;
|
||||
}
|
||||
|
||||
virtual JackConfiguration GetServerConfiguration()
|
||||
@@ -1642,7 +1642,6 @@ public:
|
||||
{
|
||||
this->isDummyAudioDriver = true;
|
||||
this->audioDriver = std::unique_ptr<AudioDriver>(CreateDummyAudioDriver(this, jackServerSettings.GetAlsaInputDevice()));
|
||||
this->audioDriver->SetAlsaSequencer(this->alsaSequencer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1820,6 +1819,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration) override;
|
||||
|
||||
|
||||
void OnNotifyPathPatchPropertyReceived(
|
||||
int64_t instanceId,
|
||||
const std::string &pathPatchPropertyUri,
|
||||
@@ -2267,6 +2269,13 @@ void AudioHostImpl::OnWritePatchPropertyBuffer(
|
||||
this->realtimeWriter.SendPathPropertyBuffer(buffer);
|
||||
}
|
||||
|
||||
void AudioHostImpl::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration)
|
||||
{
|
||||
this->alsaSequencer->SetConfiguration(alsaSequencerConfiguration);
|
||||
}
|
||||
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(JackHostStatus)
|
||||
JSON_MAP_REFERENCE(JackHostStatus, active)
|
||||
JSON_MAP_REFERENCE(JackHostStatus, errorMessage)
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace pipedal
|
||||
struct RealtimeNextMidiProgramRequest;
|
||||
class PluginHost;
|
||||
class Pedalboard;
|
||||
class AlsaSequencerConfiguration;
|
||||
|
||||
using PortMonitorCallback = std::function<void(int64_t handle, float value)>;
|
||||
|
||||
@@ -225,6 +226,7 @@ namespace pipedal
|
||||
virtual void Open(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual void SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration) = 0;
|
||||
virtual uint32_t GetSampleRate() = 0;
|
||||
|
||||
virtual JackConfiguration GetServerConfiguration() = 0;
|
||||
|
||||
@@ -107,11 +107,13 @@ namespace pipedal
|
||||
return outputAudioPorts_;
|
||||
}
|
||||
|
||||
const std::vector<AlsaMidiDeviceInfo>& GetInputMidiDevices() const
|
||||
// replaced with AlsaSequencerConfiguration
|
||||
const std::vector<AlsaMidiDeviceInfo>& LegacyGetInputMidiDevices() const
|
||||
{
|
||||
return inputMidiDevices_;
|
||||
}
|
||||
std::vector<AlsaMidiDeviceInfo>& GetInputMidiDevices()
|
||||
// replaced with AlsaSequencerConfiguration
|
||||
std::vector<AlsaMidiDeviceInfo>& LegacyGetInputMidiDevices()
|
||||
{
|
||||
return inputMidiDevices_;
|
||||
}
|
||||
|
||||
@@ -292,10 +292,16 @@ void PiPedalModel::Load()
|
||||
|
||||
this->audioHost->SetNotificationCallbacks(this);
|
||||
|
||||
|
||||
|
||||
this->systemMidiBindings = storage.GetSystemMidiBindings();
|
||||
|
||||
this->audioHost->SetSystemMidiBindings(this->systemMidiBindings);
|
||||
|
||||
audioHost->SetAlsaSequencerConfiguration(storage.GetAlsaSequencerConfiguration());
|
||||
|
||||
|
||||
|
||||
if (configuration.GetMLock())
|
||||
{
|
||||
#ifndef NO_MLOCK
|
||||
@@ -1400,6 +1406,49 @@ void PiPedalModel::RestartAudio(bool useDummyAudioDriver)
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
|
||||
// reset midi connections even if the configuration hasn't changed.
|
||||
this->audioHost->SetAlsaSequencerConfiguration(alsaSequencerConfiguration);
|
||||
|
||||
auto current = storage.GetAlsaSequencerConfiguration();
|
||||
if (alsaSequencerConfiguration != current)
|
||||
{
|
||||
this->storage.SetAlsaSequencerConfiguration(alsaSequencerConfiguration);
|
||||
// notify subscribers.
|
||||
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
||||
for (auto &subscriber : t)
|
||||
{
|
||||
subscriber->OnAlsaSequencerConfigurationChanged(alsaSequencerConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
AlsaSequencerConfiguration PiPedalModel::GetAlsaSequencerConfiguration()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
return this->storage.GetAlsaSequencerConfiguration();
|
||||
}
|
||||
|
||||
std::vector<AlsaSequencerPortSelection> PiPedalModel::GetAlsaSequencerPorts()
|
||||
{
|
||||
auto ports = AlsaSequencer::EnumeratePorts();
|
||||
std::vector<AlsaSequencerPortSelection> result;
|
||||
for (auto &port : ports)
|
||||
{
|
||||
result.push_back(AlsaSequencerPortSelection{
|
||||
port.id,
|
||||
port.name,
|
||||
port.displaySortOrder
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||
{
|
||||
{
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace pipedal
|
||||
|
||||
virtual void OnNetworkChanging(bool hotspotConnected) = 0;
|
||||
virtual void OnHasWifiChanged(bool hasWifi) = 0;
|
||||
virtual void OnAlsaSequencerConfigurationChanged(const AlsaSequencerConfiguration &alsaSequencerConfiguration) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
};
|
||||
@@ -168,6 +169,7 @@ namespace pipedal
|
||||
std::vector<AtomOutputListener> atomOutputListeners;
|
||||
|
||||
JackServerSettings jackServerSettings;
|
||||
|
||||
PluginHost pluginHost;
|
||||
AtomConverter atomConverter; // must be AFTER pluginHost!
|
||||
|
||||
@@ -387,6 +389,11 @@ namespace pipedal
|
||||
void SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection);
|
||||
JackChannelSelection GetJackChannelSelection();
|
||||
|
||||
void SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration);
|
||||
AlsaSequencerConfiguration GetAlsaSequencerConfiguration();
|
||||
|
||||
std::vector<AlsaSequencerPortSelection> GetAlsaSequencerPorts();
|
||||
|
||||
void SetShowStatusMonitor(bool show);
|
||||
bool GetShowStatusMonitor();
|
||||
|
||||
|
||||
@@ -1730,6 +1730,22 @@ public:
|
||||
{
|
||||
auto regulatoryDomains = this->model.GetWifiRegulatoryDomains();
|
||||
this->Reply(replyTo, "getWifiRegulatoryDomains", regulatoryDomains);
|
||||
} else if (message == "setAlsaSequencerConfiguration")
|
||||
{
|
||||
AlsaSequencerConfiguration config;
|
||||
pReader->read(&config);
|
||||
this->model.SetAlsaSequencerConfiguration(config);
|
||||
this->Reply(replyTo, "setAlsaSequencerConfiguration");
|
||||
}
|
||||
else if (message == "getAlsaSequencerConfiguration")
|
||||
{
|
||||
AlsaSequencerConfiguration config = this->model.GetAlsaSequencerConfiguration();
|
||||
this->Reply(replyTo, "getAlsaSequencerConfiguration", config);
|
||||
}
|
||||
else if (message == "getAlsaSequencerPorts")
|
||||
{
|
||||
std::vector<AlsaSequencerPortSelection> result = model.GetAlsaSequencerPorts();
|
||||
this->Reply(replyTo,"getAlsaSequencerPorts", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1831,6 +1847,11 @@ private:
|
||||
Flush();
|
||||
}
|
||||
|
||||
virtual void OnAlsaSequencerConfigurationChanged(const AlsaSequencerConfiguration &alsaSequencerConfiguration) override
|
||||
{
|
||||
Send("onAlsaSequencerConfigurationChanged", alsaSequencerConfiguration);
|
||||
}
|
||||
|
||||
virtual void OnNetworkChanging(bool hotspotConnected) override
|
||||
{
|
||||
try
|
||||
|
||||
+79
-18
@@ -261,6 +261,8 @@ void Storage::Initialize()
|
||||
catch (const std::exception &)
|
||||
{
|
||||
}
|
||||
LoadAlsaSequencerConfiguration();
|
||||
|
||||
LoadWifiConfigSettings();
|
||||
LoadWifiDirectConfigSettings();
|
||||
LoadUserSettings();
|
||||
@@ -313,6 +315,10 @@ std::filesystem::path Storage::GetChannelSelectionFileName()
|
||||
{
|
||||
return this->dataRoot / "JackChannelSelection.json";
|
||||
}
|
||||
std::filesystem::path Storage::GetAlsaSequencerConfigurationFileName()
|
||||
{
|
||||
return this->dataRoot / "MidiDevices.json";
|
||||
}
|
||||
std::filesystem::path Storage::GetIndexFileName() const
|
||||
{
|
||||
return this->GetPresetsDirectory() / BANKS_FILENAME;
|
||||
@@ -736,46 +742,100 @@ JackChannelSelection Storage::GetJackChannelSelection(const JackConfiguration &j
|
||||
}
|
||||
|
||||
|
||||
static void MigrateRawMidiToAlsaSequencer(JackChannelSelection &channelSelection)
|
||||
static AlsaSequencerConfiguration MigrateRawMidiToAlsaSequencer(std::vector<AlsaMidiDeviceInfo> &selectedDevices)
|
||||
{
|
||||
AlsaSequencerConfiguration result;
|
||||
try {
|
||||
auto sequencerPorts = AlsaSequencer::EnumeratePorts();
|
||||
|
||||
// Migrate raw MIDI devices to ALSA sequencer ports.
|
||||
std::vector<AlsaMidiDeviceInfo>& selectedDevices = channelSelection.GetInputMidiDevices();
|
||||
// Prepare Migrate raw MIDI devices to ALSA sequencer ports.
|
||||
|
||||
for (auto i = selectedDevices.begin(); i != selectedDevices.end(); ++i)
|
||||
{
|
||||
if (i->name_.starts_with("hw:")) {
|
||||
bool migrated = false;
|
||||
for (const auto &port: sequencerPorts)
|
||||
{
|
||||
if (i->name_ == port.rawMidiDevice)
|
||||
{
|
||||
// Found a matching sequencer port.
|
||||
i->name_ = port.rawMidiDevice;
|
||||
i->description_ = port.name;
|
||||
migrated = true;
|
||||
result.connections().push_back(
|
||||
AlsaSequencerPortSelection(port.id, port.name,port.displaySortOrder)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!migrated) {
|
||||
i = selectedDevices.erase(i);
|
||||
if (i == selectedDevices.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception&e) {
|
||||
Lv2Log::error(SS("Failed to migrate MIDI settings. " << e.what()));
|
||||
// ick.
|
||||
channelSelection.GetInputMidiDevices().clear();
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void Storage::LoadAlsaSequencerConfiguration()
|
||||
{
|
||||
auto fileName = this->GetAlsaSequencerConfigurationFileName();
|
||||
|
||||
if (std::filesystem::exists(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ifstream s(fileName);
|
||||
json_reader reader(s);
|
||||
AlsaSequencerConfiguration result;
|
||||
reader.read(&result);
|
||||
this->alsaSequencerConfiguration = result;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error("I/O error reading %s: %s", fileName.c_str(), e.what());
|
||||
}
|
||||
} else {
|
||||
|
||||
// migrate legacy settings from JackConfiguration?
|
||||
if (this->isJackChannelSelectionValid)
|
||||
{
|
||||
this->alsaSequencerConfiguration =
|
||||
MigrateRawMidiToAlsaSequencer(
|
||||
this->jackChannelSelection.LegacyGetInputMidiDevices());
|
||||
this->jackChannelSelection.LegacyGetInputMidiDevices().clear(); // let them be clear, the next it gets updated.
|
||||
|
||||
} else {
|
||||
// no legacy settings, so just create a default configuration.
|
||||
this->alsaSequencerConfiguration = AlsaSequencerConfiguration();
|
||||
}
|
||||
SaveAlsaSequencerConfiguration();
|
||||
}
|
||||
|
||||
}
|
||||
void Storage::SaveAlsaSequencerConfiguration()
|
||||
{
|
||||
auto fileName = this->GetAlsaSequencerConfigurationFileName();
|
||||
|
||||
try
|
||||
{
|
||||
pipedal::ofstream_synced s(fileName);
|
||||
json_writer writer(s);
|
||||
writer.write(this->alsaSequencerConfiguration);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error("I/O error writing %s: %s", fileName.c_str(), e.what());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Storage::SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration)
|
||||
{
|
||||
this->alsaSequencerConfiguration = alsaSequencerConfiguration;
|
||||
SaveAlsaSequencerConfiguration();
|
||||
}
|
||||
|
||||
AlsaSequencerConfiguration Storage::GetAlsaSequencerConfiguration() const
|
||||
{
|
||||
return this->alsaSequencerConfiguration;
|
||||
}
|
||||
|
||||
|
||||
void Storage::LoadChannelSelection()
|
||||
{
|
||||
@@ -788,7 +848,6 @@ void Storage::LoadChannelSelection()
|
||||
json_reader reader(s);
|
||||
reader.read(&this->jackChannelSelection);
|
||||
this->isJackChannelSelectionValid = true;
|
||||
MigrateRawMidiToAlsaSequencer(this->jackChannelSelection);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -801,6 +860,8 @@ void Storage::SaveChannelSelection()
|
||||
auto fileName = this->GetChannelSelectionFileName();
|
||||
try
|
||||
{
|
||||
// replaced with AlsaSequencerConfiguration. Delete legacy data.
|
||||
this->jackChannelSelection.LegacyGetInputMidiDevices().clear();
|
||||
pipedal::ofstream_synced s(fileName);
|
||||
json_writer writer(s, false);
|
||||
writer.write(this->jackChannelSelection);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "FileEntry.hpp"
|
||||
#include <map>
|
||||
#include "FilePropertyDirectoryTree.hpp"
|
||||
#include "AlsaSequencer.hpp"
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
@@ -84,6 +85,7 @@ private:
|
||||
std::filesystem::path GetIndexFileName() const;
|
||||
std::filesystem::path GetBankFileName(const std::string & name) const;
|
||||
std::filesystem::path GetChannelSelectionFileName();
|
||||
std::filesystem::path GetAlsaSequencerConfigurationFileName();
|
||||
std::filesystem::path GetCurrentPresetPath() const;
|
||||
|
||||
void LoadBankIndex();
|
||||
@@ -94,11 +96,19 @@ private:
|
||||
|
||||
void LoadChannelSelection();
|
||||
void SaveChannelSelection();
|
||||
|
||||
void LoadAlsaSequencerConfiguration();
|
||||
void SaveAlsaSequencerConfiguration();
|
||||
|
||||
|
||||
void SaveBankFile(const std::string& name,const BankFile&bankFile);
|
||||
void LoadBankFile(const std::string &name,BankFile *pBank);
|
||||
std::string GetPresetCopyName(const std::string &name);
|
||||
bool isJackChannelSelectionValid = false;
|
||||
JackChannelSelection jackChannelSelection;
|
||||
|
||||
AlsaSequencerConfiguration alsaSequencerConfiguration;;
|
||||
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
WifiDirectConfigSettings wifiDirectConfigSettings;
|
||||
|
||||
@@ -126,6 +136,7 @@ public:
|
||||
void LoadWifiDirectConfigSettings();
|
||||
void LoadUserSettings();
|
||||
void SaveUserSettings();
|
||||
|
||||
void LoadBank(int64_t instanceId);
|
||||
int64_t GetBankByMidiBankNumber(uint8_t bankNumber);
|
||||
const Pedalboard& GetCurrentPreset();
|
||||
@@ -181,6 +192,10 @@ public:
|
||||
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
||||
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
||||
|
||||
void SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration);
|
||||
AlsaSequencerConfiguration GetAlsaSequencerConfiguration() const;
|
||||
|
||||
|
||||
//std::string MapPropertyFileName(Lv2PluginInfo*pluginInfo, const std::string&path);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user