ALSA Sequencer connections.

This commit is contained in:
Robin E. R. Davies
2025-06-29 07:44:39 -04:00
parent 862d5b6315
commit a81056a657
19 changed files with 613 additions and 161 deletions
+12 -3
View File
@@ -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)
+2
View File
@@ -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;
+4 -2
View File
@@ -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_;
}
+49
View File
@@ -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)
{
{
+7
View File
@@ -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();
+21
View File
@@ -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
View File
@@ -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);
+15
View File
@@ -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 &currentPreset);
bool RestoreCurrentPreset(CurrentPreset*pResult);
void SetAlsaSequencerConfiguration(const AlsaSequencerConfiguration &alsaSequencerConfiguration);
AlsaSequencerConfiguration GetAlsaSequencerConfiguration() const;
//std::string MapPropertyFileName(Lv2PluginInfo*pluginInfo, const std::string&path);
private: