pax_global_header00006660000000000000000000000064135464170550014524gustar00rootroot0000000000000052 comment=2859872c49049771aef72112288d74ea0c32f477 libeXaDrums-0.4.2/000077500000000000000000000000001354641705500137465ustar00rootroot00000000000000libeXaDrums-0.4.2/.gitignore000066400000000000000000000004211354641705500157330ustar00rootroot00000000000000*.m4 m4* *.log config.h.in Makefile.in *.o *.Po .dirstamp *~ autom4te.cache/* *.swp config.h config.status missing stamp-h1 depcomp configure install-sh Makefile *.la *.so* .libs *.lo *.Plo ar-lib compile config.guess config.sub exadrums.pc libtool ltmain.sh Api/Version.h libeXaDrums-0.4.2/Api/000077500000000000000000000000001354641705500144575ustar00rootroot00000000000000libeXaDrums-0.4.2/Api/Config/000077500000000000000000000000001354641705500156645ustar00rootroot00000000000000libeXaDrums-0.4.2/Api/Config/AlsaParams_api.h000066400000000000000000000026351354641705500207200ustar00rootroot00000000000000/* * AlsaParams_api.h * * Created on: 7 Oct 2017 * Author: jeremy */ #ifndef SOURCE_API_CONFIG_ALSAPARAMS_API_H_ #define SOURCE_API_CONFIG_ALSAPARAMS_API_H_ #include "../../Sound/Alsa/AlsaParams.h" #include namespace eXaDrumsApi { struct AlsaParamsApi { AlsaParamsApi() noexcept { *this = Sound::AlsaParams(); } explicit AlsaParamsApi(const Sound::AlsaParams& alsaparams) noexcept { *this = alsaparams; } explicit operator Sound::AlsaParams() const noexcept { Sound::AlsaParams alsaParams; alsaParams.capture = this->capture; alsaParams.sampleRate = this->sampleRate; alsaParams.nChannels = this->nChannels; alsaParams.bufferTime = this->bufferTime; alsaParams.periodTime = this->periodTime; alsaParams.device = this->device; return alsaParams; } AlsaParamsApi& operator=(const Sound::AlsaParams& alsaparams) noexcept { this->capture = alsaparams.capture; this->sampleRate = alsaparams.sampleRate; this->nChannels = alsaparams.nChannels; this->bufferTime = alsaparams.bufferTime; this->periodTime = alsaparams.periodTime; std::snprintf(this->device, sizeof this->device, "%s", alsaparams.device.data()); return *this; } bool capture; unsigned int sampleRate; unsigned int nChannels; unsigned int bufferTime; unsigned int periodTime; char device[64]; }; } #endif /* SOURCE_API_CONFIG_ALSAPARAMS_API_H_ */ libeXaDrums-0.4.2/Api/Config/Config_api.cpp000066400000000000000000000236161354641705500204360ustar00rootroot00000000000000/* * Config_api.cpp * * Created on: 2 Mar 2017 * Author: jeremy */ #include "Config_api.h" #include "TriggerParameters_api.h" #include "../../DrumKit/DrumModule/Module.h" #include "../../DrumKit/Triggers/TriggerManager.h" #include "../../Util/Enums.h" #include "../../Util/ErrorHandling.h" #include "../../Sound/Alsa/Alsa.h" #include "../../Sound/Alsa/AlsaParameters.h" #include "../eXaDrums.h" #include #include using namespace Util; namespace eXaDrumsApi { Config::Config(eXaDrums& drums) noexcept : drumKit(drums), module(*drums.drumModule.get()) { RefreshSensorsConfig(); return; } void Config::RefreshSensorsConfig() noexcept { this->sensorsConfig = module.GetSensorsConfig(); return; } // Private Methods error Config::SaveSensorsConfig_() { std::string dir; module.GetDirectory(dir); return ExceptionToError([&] { DrumKit::TriggerManager::SaveSensorsConfig(dir, sensorsConfig); RestartModule(); }); } error Config::SaveTriggersConfig_() { std::string dir; module.GetDirectory(dir); // Conversion to internal type std::vector trigsParams(triggersParameters.size()); std::transform(triggersParameters.begin(), triggersParameters.end(), trigsParams.begin(), [](auto& tp) { return static_cast(tp); }); return ExceptionToError([&] { DrumKit::TriggerManager::SaveTriggersConfig(dir, trigsParams); RestartModule(); }); } error Config::LoadTriggersConfig_() const { std::string dir; module.GetDirectory(dir); // Load sensors config first IO::SensorsConfig sensorConfig; std::vector trigsParams; return ExceptionToError([&] { DrumKit::TriggerManager::LoadSensorsConfig(dir, sensorConfig); DrumKit::TriggerManager::LoadTriggersConfig(dir, sensorConfig, trigsParams); // Conversion and copy of the triggers parameters this->triggersParameters.clear(); this->triggersParameters.resize(trigsParams.size()); std::transform(trigsParams.begin(), trigsParams.end(), triggersParameters.begin(), [](auto& tp) { return static_cast(tp); }); }); } error Config::SaveCurrentAudioDeviceConfig_() const { Sound::AlsaParams params; params.device = alsaParams.device; params.sampleRate = alsaParams.sampleRate; params.nChannels = alsaParams.nChannels; params.capture = alsaParams.capture; params.bufferTime = alsaParams.bufferTime; params.periodTime = alsaParams.periodTime; return ExceptionToError([&] { Sound::AlsaParameters::SaveAlsaParameters(drumKit.GetDataLocation() + eXaDrums::alsaConfigFile, params); }); } error Config::SaveAudioDeviceConfig_(const AlsaParamsApi& params) { auto err = SetAudioDeviceParameters_(params); if(err.type!= error_type_success) { return err; } return SaveCurrentAudioDeviceConfig_(); } error Config::ResetAudioDevice_() { return ExceptionToError([&] { this->drumKit.alsa.reset(); // Load alsa parameters Sound::AlsaParams alsaParams; Sound::AlsaParameters::LoadAlsaParameters(drumKit.GetDataLocation() + eXaDrums::alsaConfigFile, alsaParams); // Create mixer and alsa this->drumKit.alsa = std::make_unique(alsaParams, this->drumKit.mixer); }); } error Config::AddTrigger_(const TriggerParameters& params) { // Reload triggers config auto err = LoadTriggersConfig_(); if(err.type!= error_type_success) { return err; } // Add trigger this->triggersParameters.push_back(params); // Save trigger config if(update_error(err, SaveTriggersConfig_()) != error_type_success) { return err; } // Restart module RestartModule(); return err; } error Config::DeleteTrigger_(int sensorId) { // Reload triggers config auto err = LoadTriggersConfig_(); if(err.type!= error_type_success) { return err; } // Remove trigger auto it = std::remove_if(triggersParameters.begin(), triggersParameters.end(), [&](const auto& tp) { return tp.sensorId == sensorId; }); if(it != end(triggersParameters)) { triggersParameters.erase(it); } else { return make_error("Could not delete trigger, as it does not exist.", error_type_warning); } // Save triggers config err = SaveTriggersConfig_(); if(err.type!= error_type_success) { return err; } RestartModule(); return make_error("", error_type_success); } void Config::SetSensorsType_(const char* type) { sensorsConfig.sensorType = Enums::ToElement(std::string(type)); return; } void Config::SetSensorsDataFolder_(const char* folder) noexcept { sensorsConfig.hddDataFolder = std::string(folder); return; } void Config::SetTriggersParameters_(const TriggerParameters* params, unsigned int size) noexcept { std::vector trigParams(params, params + size); this->triggersParameters.clear(); this->triggersParameters = trigParams; return; } error Config::SetAudioDeviceParameters_(const AlsaParamsApi& params) { this->alsaParams = params; std::string deviceName(params.device); // Replace device name by device id auto itDev = std::find_if(audioDevices.begin(), audioDevices.end(), [&](const auto& dev) { return deviceName == dev.first; }); if(itDev != audioDevices.end()) { std::strcpy(this->alsaParams.device, itDev->second.data()); } else { return make_error(("Error: audio device " + deviceName + " not found.").data(), error_type_error); } return make_error("", error_type_success); } Util::error Config::GetNbTriggers_(size_t& nb) const { auto error = this->LoadTriggersConfig_(); if(error.type != error_type_success) { return error; } nb = static_cast(triggersParameters.size()); return make_error("", error_type_success); } void Config::RestartModule() { bool isRestart = false; if(drumKit.isStarted.load()) { ErrorToException([&] { return drumKit.Stop_(); }); isRestart = true; } int kitId = module.GetKitId(); module.ReloadTriggers(); module.ReloadKits(); module.SelectKit(kitId); if(isRestart) { ErrorToException([&] { return drumKit.Start_(); }); } return; } void Config::SetTriggerParameters_(int triggerId, const TriggerParameters& params) { const auto triggerParams = static_cast(params); module.SetTriggerParameters(triggerId, triggerParams); } void Config::GetSensorsTypes_(const char** types, unsigned int& size) { if(types == nullptr) { size = Enums::GetEnumVector().size(); return; } const std::vector& vec = Enums::GetEnumVector(); this->sensorsTypes.clear(); this->sensorsTypes.resize(vec.size()); std::transform(vec.cbegin(), vec.cend(), this->sensorsTypes.begin(), [](const IO::SensorType& t) { return Enums::ToString(t); }); unsigned int numElements = std::min(size, sensorsTypes.size()); for(unsigned int i = 0; i < numElements; i++) { types[i] = sensorsTypes[i].c_str(); } return; } void Config::GetTriggersTypes_(const char** types, unsigned int& size) { if(types == nullptr) { size = Enums::GetEnumVector().size(); return; } const std::vector& vec = Enums::GetEnumVector(); this->triggersTypes.clear(); this->triggersTypes.resize(vec.size()); std::transform(vec.cbegin(), vec.cend(), this->triggersTypes.begin(), [](const DrumKit::TriggerType& t) { return Enums::ToString(t); }); unsigned int numElements = std::min(size, triggersTypes.size()); for(unsigned int i = 0; i < numElements; i++) { types[i] = triggersTypes[i].c_str(); } return; } void Config::GetTriggersResponses_(const char** responses, unsigned int& size) { if(responses == nullptr) { size = Enums::GetEnumVector().size(); return; } const std::vector& vec = Enums::GetEnumVector(); this->triggersResponses.clear(); this->triggersResponses.resize(vec.size()); std::transform(vec.cbegin(), vec.cend(), this->triggersResponses.begin(), [](const DrumKit::CurveType& r) { return Enums::ToString(r); }); unsigned int numElements = std::min(size, triggersResponses.size()); for(unsigned int i = 0; i < numElements; i++) { responses[i] = triggersResponses[i].c_str(); } return; } void Config::GetAudioDevicesNames_(const char** dev, unsigned int& size) { const auto devices = Sound::Alsa::GetDevices(); if(dev == nullptr) { size = devices.size(); return; } this->audioDevices.clear(); this->audioDevices.resize(devices.size()); std::copy(devices.begin(), devices.end(), this->audioDevices.begin()); unsigned int numElements = std::min(size, audioDevices.size()); for(unsigned int i = 0; i < numElements; i++) { dev[i] = audioDevices[i].first.data(); } } void Config::GetTriggersParameters_(TriggerParameters* const triggers, unsigned int& size) const { const std::vector& trigsParams = this->module.GetTriggersParameters(); if(triggers == nullptr) { size = trigsParams.size(); return; } if(size != trigsParams.size()) { throw -1; } std::copy(trigsParams.cbegin(), trigsParams.cend(), triggers); return; } const char* Config::GetSensorsType_() { this->sensorType = Enums::ToString(this->sensorsConfig.sensorType); return this->sensorType.c_str(); } const char* Config::GetSensorsDataFolder_() const noexcept { return this->sensorsConfig.hddDataFolder.c_str(); } const char* Config::GetAudioDeviceName_() const noexcept { this->audioDeviceName = this->drumKit.GetAudioDeviceName(); return this->audioDeviceName.data(); } AlsaParamsApi Config::GetAudioDeviceParams_() const noexcept { AlsaParamsApi alsaParameters = static_cast(this->drumKit.alsa->GetParameters()); return alsaParameters; } } libeXaDrums-0.4.2/Api/Config/Config_api.h000066400000000000000000000100471354641705500200750ustar00rootroot00000000000000/* * Config_api.h * * Created on: 2 Mar 2017 * Author: jeremy */ #ifndef SOURCE_API_CONFIG_CONFIG_API_H_ #define SOURCE_API_CONFIG_CONFIG_API_H_ #include "../../IO/SensorsConfig.h" #include "../../Util/ErrorHandling.h" #include "AlsaParams_api.h" #include #include namespace DrumKit { class Module; } namespace eXaDrumsApi{ class eXaDrums; struct TriggerParameters; } namespace eXaDrumsApi { class Config { public: explicit Config(eXaDrums& drums) noexcept; ~Config() = default; void RefreshSensorsConfig() noexcept; void SaveSensorsConfig(); void SaveTriggersConfig(); void LoadTriggersConfig() const; void SaveCurrentAudioDeviceConfig() const; void SaveAudioDeviceConfig(const AlsaParamsApi& params); void ResetAudioDevice(); // Triggers void AddTrigger(const TriggerParameters& params); void DeleteTrigger(int sensorId); std::size_t GetNbTriggers() const; // Mutators void SetSensorsSamplingRate(int sRate) noexcept { sensorsConfig.samplingRate = sRate; } void SetSensorsResolution(int res) noexcept { sensorsConfig.resolution = res; } void SetSensorsType(const std::string& type); void SetSensorsDataFolder(const std::string& folder) noexcept; void SetAudioDeviceParameters(const AlsaParamsApi& params); void SetTriggersParameters(const std::vector& params); void SetTriggerParameters(int triggerId, const TriggerParameters& params); // Accessors std::vector GetSensorsTypes(); std::vector GetTriggersTypes(); std::vector GetTriggersResponses(); std::vector GetAudioDevicesNames(); std::vector GetTriggersParameters() const; std::string GetSensorsType(); std::string GetSensorsDataFolder() const noexcept; std::string GetAudioDeviceName() const noexcept; AlsaParamsApi GetAudioDeviceParams() const noexcept; int GetSensorsSamplingRate() const noexcept { return sensorsConfig.samplingRate; } int GetSensorsResolution() const noexcept { return sensorsConfig.resolution; } private: Util::error SaveSensorsConfig_(); Util::error SaveTriggersConfig_(); Util::error LoadTriggersConfig_() const; Util::error SaveCurrentAudioDeviceConfig_() const; Util::error SaveAudioDeviceConfig_(const AlsaParamsApi& params); Util::error ResetAudioDevice_(); Util::error AddTrigger_(const TriggerParameters& params); Util::error DeleteTrigger_(int sensorId); Util::error SetAudioDeviceParameters_(const AlsaParamsApi& params); Util::error GetNbTriggers_(size_t& nb) const; void RestartModule(); void SetSensorsType_(const char* type); void SetSensorsDataFolder_(const char* folder) noexcept; void SetAudioDeviceParameters_(const char* name); void SetTriggersParameters_(const TriggerParameters* params, unsigned int size) noexcept; void SetTriggerParameters_(int triggerId, const TriggerParameters& params); const char* GetSensorsType_(); const char* GetSensorsDataFolder_() const noexcept; const char* GetAudioDeviceName_() const noexcept; AlsaParamsApi GetAudioDeviceParams_() const noexcept; void GetSensorsTypes_(const char** types, unsigned int& size); void GetTriggersTypes_(const char** types, unsigned int& size); void GetTriggersResponses_(const char** responses, unsigned int& size); void GetAudioDevicesNames_(const char** devices, unsigned int& size); void GetTriggersParameters_(TriggerParameters* const triggers, unsigned int& size) const; eXaDrums& drumKit; DrumKit::Module& module; // Alsa config mutable AlsaParamsApi alsaParams; // Sensors config IO::SensorsConfig sensorsConfig; // Triggers config mutable std::vector triggersParameters; // Local copies of items std::string sensorType; mutable std::string audioDeviceName; // Local copies of enums std::vector sensorsTypes; std::vector triggersTypes; std::vector triggersResponses; std::vector> audioDevices; }; } #include "Config_api.hpp" #endif /* SOURCE_API_CONFIG_CONFIG_API_H_ */ libeXaDrums-0.4.2/Api/Config/Config_api.hpp000066400000000000000000000101671354641705500204400ustar00rootroot00000000000000/* * Config_api.hpp * * Created on: 2 Mar 2017 * Author: jeremy */ #ifndef SOURCE_API_CONFIG_CONFIG_API_HPP_ #define SOURCE_API_CONFIG_CONFIG_API_HPP_ #include "Config_api.h" #include "TriggerParameters_api.h" namespace eXaDrumsApi { inline void Config::SaveSensorsConfig() { Util::ErrorToException([&] { return this->SaveSensorsConfig_(); }); } inline void Config::SaveTriggersConfig() { Util::ErrorToException([&] { return this->SaveTriggersConfig_(); }); } inline void Config::LoadTriggersConfig() const { Util::ErrorToException([&] { return this->LoadTriggersConfig_(); }); } inline void Config::SaveCurrentAudioDeviceConfig() const { Util::ErrorToException([&] { return this->SaveCurrentAudioDeviceConfig_(); }); } inline void Config::SaveAudioDeviceConfig(const AlsaParamsApi& params) { Util::ErrorToException([&] { return this->SaveAudioDeviceConfig_(params); }); } inline void Config::ResetAudioDevice() { Util::ErrorToException([&] { return this->ResetAudioDevice_(); }); } inline void Config::AddTrigger(const TriggerParameters& params) { Util::ErrorToException([&] { return this->AddTrigger_(params); }); } inline void Config::DeleteTrigger(int sensorId) { Util::ErrorToException([&] { return this->DeleteTrigger_(sensorId); }); } inline std::size_t Config::GetNbTriggers() const { size_t nb = 0; this->GetNbTriggers_(nb); return nb; } inline void Config::SetSensorsType(const std::string& type) { SetSensorsType_(type.c_str()); return; } inline void Config::SetSensorsDataFolder(const std::string& folder) noexcept { SetSensorsDataFolder_(folder.c_str()); return; } inline void Config::SetAudioDeviceParameters(const AlsaParamsApi& params) { Util::ErrorToException([&] { return SetAudioDeviceParameters_(params); }); return; } inline void Config::SetTriggersParameters(const std::vector& params) { SetTriggersParameters_(params.data(), params.size()); return; } inline void Config::SetTriggerParameters(int triggerId, const TriggerParameters& params) { SetTriggerParameters_(triggerId, params); } inline std::vector Config::GetSensorsTypes() { unsigned int size = 0; GetSensorsTypes_(nullptr, size); std::vector data(size); GetSensorsTypes_(data.data(), size); std::vector vec(size); std::copy(data.cbegin(), data.cend(), vec.begin()); return vec; } inline std::vector Config::GetTriggersTypes() { unsigned int size = 0; GetTriggersTypes_(nullptr, size); std::vector data(size); GetTriggersTypes_(data.data(), size); std::vector vec(size); std::copy(data.cbegin(), data.cend(), vec.begin()); return vec; } inline std::vector Config::GetTriggersResponses() { unsigned int size = 0; GetTriggersResponses_(nullptr, size); std::vector data(size); GetTriggersResponses_(data.data(), size); std::vector vec(size); std::copy(data.cbegin(), data.cend(), vec.begin()); return vec; } inline std::vector Config::GetAudioDevicesNames() { unsigned int size = 0; GetAudioDevicesNames_(nullptr, size); std::vector data(size); GetAudioDevicesNames_(data.data(), size); std::vector vec(size); std::copy(data.cbegin(), data.cend(), vec.begin()); return vec; } inline std::vector Config::GetTriggersParameters() const { unsigned int size = 0; GetTriggersParameters_(nullptr, size); std::vector vec(size); GetTriggersParameters_(vec.data(), size); return vec; } inline AlsaParamsApi Config::GetAudioDeviceParams() const noexcept { return GetAudioDeviceParams_(); } inline std::string Config::GetSensorsType() { return std::string(GetSensorsType_()); } inline std::string Config::GetSensorsDataFolder() const noexcept { return std::string(GetSensorsDataFolder_()); } inline std::string Config::GetAudioDeviceName() const noexcept { return std::string(GetAudioDeviceName_()); } } // namespace eXaDrumsApi #endif /* SOURCE_API_CONFIG_CONFIG_API_HPP_ */ libeXaDrums-0.4.2/Api/Config/TriggerParameters_api.cpp000066400000000000000000000030601354641705500226470ustar00rootroot00000000000000/* * TriggerParameters.cpp * * Created on: 14 Mar 2017 * Author: jeremy */ #include "TriggerParameters_api.h" #include "../../DrumKit/Triggers/TriggerParameters.h" #include "../../Util/Enums.h" #include #include using namespace Util; namespace eXaDrumsApi { TriggerParameters::TriggerParameters() noexcept { *this = DrumKit::TriggerParameters(); return; } TriggerParameters::TriggerParameters(const DrumKit::TriggerParameters& parameters) noexcept { *this = parameters; return; } TriggerParameters& TriggerParameters::operator=(const DrumKit::TriggerParameters& parameters) noexcept { std::string typeStr = Enums::ToString(parameters.type); std::string responseStr = Enums::ToString(parameters.response); std::snprintf(this->type, sizeof this->type, "%s", typeStr.data()); std::snprintf(this->response, sizeof this->response, "%s", responseStr.data()); this->maskTime = parameters.maskTime; this->scanTime = parameters.scanTime; this->sensorId = parameters.sensorId; this->threshold = parameters.threshold; return *this; } TriggerParameters::operator DrumKit::TriggerParameters() const { DrumKit::TriggerParameters parameters; parameters.type = Enums::ToElement(std::string(this->type)); parameters.response = Enums::ToElement(std::string(this->response)); parameters.maskTime = this->maskTime; parameters.scanTime = this->scanTime; parameters.sensorId = this->sensorId; parameters.threshold = this->threshold; return parameters; } } libeXaDrums-0.4.2/Api/Config/TriggerParameters_api.h000066400000000000000000000014021354641705500223120ustar00rootroot00000000000000/* * TriggerParameters.h * * Created on: 14 Mar 2017 * Author: jeremy */ #ifndef SOURCE_API_CONFIG_TRIGGERPARAMETERS_API_H_ #define SOURCE_API_CONFIG_TRIGGERPARAMETERS_API_H_ namespace DrumKit { struct TriggerParameters; } namespace eXaDrumsApi { struct TriggerParameters { TriggerParameters() noexcept; // Conversion to internal type explicit TriggerParameters(const DrumKit::TriggerParameters& parameters) noexcept; TriggerParameters& operator=(const DrumKit::TriggerParameters& parameters) noexcept; explicit operator DrumKit::TriggerParameters() const; int sensorId; unsigned int scanTime; short threshold; int maskTime; char type[64]; char response[64]; }; } #endif /* SOURCE_API_CONFIG_TRIGGERPARAMETERS_API_H_ */ libeXaDrums-0.4.2/Api/KitCreator/000077500000000000000000000000001354641705500165265ustar00rootroot00000000000000libeXaDrums-0.4.2/Api/KitCreator/KitCreator_api.cpp000066400000000000000000000206031354641705500221330ustar00rootroot00000000000000/* * KitCreator.cpp * * Created on: 22 Nov 2016 * Author: jeremy */ #include "KitCreator_api.h" #include #include using namespace Util; namespace eXaDrumsApi { KitCreator::KitCreator(const char* dataLocation) : controller(dataLocation) { return; } KitCreator::~KitCreator() { return; } // Kit void KitCreator::CreateNewKit() noexcept { controller.CreateNewKit(); return; } int KitCreator::GetNumInstruments() const noexcept { return controller.GetNumInstruments(); } void KitCreator::SetKitName(const char* name) noexcept { controller.SetKitName(std::string(name)); return; } // Instrument void KitCreator::CreateNewInstrument() noexcept { controller.CreateNewInstrument(); return; } void KitCreator::RemoveInstrument(std::size_t i) noexcept { controller.RemoveInstrument(i); return; } void KitCreator::RemoveLastInstrument() noexcept { controller.RemoveLastInstrument(); return; } void KitCreator::AddInstrumentToKit() noexcept { controller.AddInstrumentToKit(); return; } void KitCreator::SetInstrumentType(int id, const char* type) { controller.SetInstrumentType(id, std::string(type)); return; } void KitCreator::SetInstrumentType(const char* type) { controller.SetInstrumentType(std::string(type)); return; } void KitCreator::SetInstrumentVolume(const float volume) noexcept { controller.SetInstrumentVolume(volume); return; } void KitCreator::AddInstrumentSound(const char* file, const char* type) { controller.AddInstrumentSound(std::string(file), std::string(type)); return; } void KitCreator::AddInstrumentTrigger(const int id, const char* location) { controller.AddInstrumentTrigger(id, std::string(location)); return; } // Private Methods error KitCreator::CreateFromModel_(const char* loc) { return ExceptionToError([&] { controller.CreateFromModel(std::string(loc)); }); } error KitCreator::SaveKit_(const char* file) const { return ExceptionToError([&] { controller.SaveKit(std::string(file)); }); } error KitCreator::SaveKit_() const { return ExceptionToError([&] { controller.SaveKit(); }); } error KitCreator::SetInstrumentName_(const char* name) { std::string nameStr = std::string(name); if(nameStr.empty()) { return make_error("Instrument name cannot be empty.", error_type_error); } controller.SetInstrumentName(nameStr); return make_error("", error_type_success); } error KitCreator::SetInstrumentName_(int id, const char* name) { std::string nameStr = std::string(name); if(nameStr.empty()) { return make_error("Instrument name cannot be empty.", error_type_error); } controller.SetInstrumentName(id, nameStr); return make_error("", error_type_success); } void KitCreator::SetInstrumentTriggersIdsAndLocs_(int id, int* ids, const char** locs, unsigned int size) { std::vector trigsIds(ids, ids + size); std::vector trigsLocs(locs, locs + size); std::vector> trigs; for(std::size_t i = 0; i < size; i++) { trigs.push_back({trigsIds[i], trigsLocs[i]}); } controller.SetInstrumentTriggersIdsAndLocs(id, trigs); return; } void KitCreator::SetInstrumentSoundsTypesAndLocs_(int id, const char** types, const char** locs, unsigned int size) { std::vector sndTypes(types, types + size); std::vector sndLocs(locs, locs + size); std::vector> sounds; for(std::size_t i = 0; i < size; i++) { sounds.push_back({sndTypes[i], sndLocs[i]}); } controller.SetInstrumentSoundsTypesAndLocs(id, sounds); return; } const char* KitCreator::GetInstrumentType_(int i) { this->instrumentType = controller.GetInstrumentType(i); return this->instrumentType.c_str(); } void KitCreator::GetInstrumentTriggersIds_(int i, int* data, unsigned int& size) const { if(data == nullptr) { size = controller.GetInstrumentsTriggersIds(i).size(); return; } std::vector trigsIds = controller.GetInstrumentsTriggersIds(i); std::copy(trigsIds.cbegin(), trigsIds.cend(), data); size = trigsIds.size(); return; } void KitCreator::GetTriggersIds_(int* data, unsigned int& size) const { if(data == nullptr) { size = controller.GetTriggersIds().size(); return; } std::vector trigsIds = controller.GetTriggersIds(); std::copy(trigsIds.cbegin(), trigsIds.cend(), data); size = trigsIds.size(); return; } void KitCreator::GetInstrumentTriggersLocations_(int i, const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetInstrumentTriggersLocations(i).size(); return; } this->instrumentTriggersLocations.clear(); this->instrumentTriggersLocations = controller.GetInstrumentTriggersLocations(i); unsigned int numElements = std::min(size, instrumentTriggersLocations.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentTriggersLocations[i].c_str(); } return; } void KitCreator::GetInstrumentSoundsTypes_(int i, const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetInstrumentSoundsTypes(i).size(); return; } this->instrumentSoundsTypes.clear(); this->instrumentSoundsTypes = controller.GetInstrumentSoundsTypes(i); unsigned int numElements = std::min(size, instrumentSoundsTypes.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentSoundsTypes[i].c_str(); } return; } void KitCreator::GetSoundTypes_(const char* instrumentType, const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetSoundTypes(std::string(instrumentType)).size(); return; } this->soundsTypes.clear(); this->soundsTypes = controller.GetSoundTypes(std::string(instrumentType)); unsigned int numElements = std::min(size, soundsTypes.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = soundsTypes[i].c_str(); } return; } void KitCreator::GetInstrumentSoundsLocs_(int i, const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetInstrumentSoundsLocs(i).size(); return; } this->instrumentSoundsLocs.clear(); this->instrumentSoundsLocs = controller.GetInstrumentSoundsLocs(i); unsigned int numElements = std::min(size, instrumentSoundsLocs.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentSoundsLocs[i].c_str(); } return; } /*void KitCreator::GetSoundFiles_(const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetSoundFiles().size(); return; } this->soundsFiles.clear(); this->soundsFiles = controller.GetSoundFiles(); unsigned int numElements = std::min(size, soundsFiles.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = soundsFiles[i].c_str(); } return; }*/ void KitCreator::GetInstrumentsTypes_(const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetInstrumentsTypes().size(); return; } this->instrumentsTypes.clear(); this->instrumentsTypes = controller.GetInstrumentsTypes(); unsigned int numElements = std::min(size, instrumentsTypes.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentsTypes[i].c_str(); } return; } void KitCreator::GetInstrumentsNames_(const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetInstrumentsNames().size(); return; } this->instrumentsNames.clear(); this->instrumentsNames = controller.GetInstrumentsNames(); unsigned int numElements = std::min(size, instrumentsNames.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentsNames[i].c_str(); } return; } void KitCreator::GetTriggersLocations_(const char* instrumentType, const char** data, unsigned int& size) { if(data == nullptr) { size = controller.GetTriggersLocations(std::string(instrumentType)).size(); return; } this->triggersLocations.clear(); this->triggersLocations = controller.GetTriggersLocations(std::string(instrumentType)); unsigned int numElements = std::min(size, triggersLocations.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = triggersLocations[i].c_str(); } return; } } /* namespace eXaDrumsApi */ libeXaDrums-0.4.2/Api/KitCreator/KitCreator_api.h000066400000000000000000000077631354641705500216140ustar00rootroot00000000000000/* * KitCreator.h * * Created on: 22 Nov 2016 * Author: jeremy */ #ifndef SOURCE_API_KITCREATOR_KITCREATOR_API_H_ #define SOURCE_API_KITCREATOR_KITCREATOR_API_H_ #include "../../Util/ErrorHandling.h" #include "../../DrumKit/Kits/KitCreator.h" #include #include #include namespace eXaDrumsApi { class KitCreator { public: explicit KitCreator(const char* dataLocation); ~KitCreator(); // Kit void CreateNewKit() noexcept; void CreateFromModel(const char* loc); int GetNumInstruments() const noexcept; void SetKitName(const char* name) noexcept; void SaveKit(const char* file) const; void SaveKit() const; // Instrument void CreateNewInstrument() noexcept; void RemoveInstrument(std::size_t i) noexcept; void RemoveLastInstrument() noexcept; void AddInstrumentToKit() noexcept; void SetInstrumentName(const char* name); void SetInstrumentType(const char* type); void SetInstrumentVolume(const float volume) noexcept; void AddInstrumentSound(const char* file, const char* type); void AddInstrumentTrigger(const int id, const char* location); void SetInstrumentName(int id, const char* name); void SetInstrumentType(int id, const char* type); void SetInstrumentTriggersIdsAndLocs(int id, const std::vector>& trigsIdsAndLocs); void SetInstrumentSoundsTypesAndLocs(int id, const std::vector>& sndTypesAndLocs); std::string GetInstrumentType(int i); std::vector GetInstrumentTriggersIds(int i) const; std::vector GetInstrumentTriggersLocations(int i); std::vector GetInstrumentSoundsTypes(int i); std::vector GetInstrumentSoundsLocs(int i); // Enums // Instruments std::vector GetInstrumentsTypes(); std::vector GetInstrumentsNames(); // Triggers std::vector GetTriggersIds() const; std::vector GetTriggersLocations(const std::string& instrumentType); // Sounds //std::vector GetSoundsFiles(); std::vector GetSoundsTypes(const std::string& instrumentType); private: Util::error CreateFromModel_(const char* loc); Util::error SaveKit_(const char* file) const; Util::error SaveKit_() const; Util::error SetInstrumentName_(const char* name); Util::error SetInstrumentName_(int id, const char* name); void SetInstrumentTriggersIdsAndLocs_(int id, int* ids, const char** locs, unsigned int size); void SetInstrumentSoundsTypesAndLocs_(int id, const char** types, const char** locs, unsigned int size); const char* GetInstrumentType_(int i); void GetInstrumentTriggersIds_(int i, int* data, unsigned int& size) const; void GetTriggersIds_(int* data, unsigned int& size) const; void GetInstrumentTriggersLocations_(int i, const char** data, unsigned int& size); void GetTriggersLocations_(const char* instrumentType, const char** data, unsigned int& size); void GetInstrumentSoundsTypes_(int i, const char** data, unsigned int& size); void GetSoundTypes_(const char* instrumentType, const char** data, unsigned int& size); void GetInstrumentSoundsLocs_(int i, const char** data, unsigned int& size); //void GetSoundFiles_(const char** data, unsigned int& size); void GetInstrumentsTypes_(const char** data, unsigned int& size); void GetInstrumentsNames_(const char** data, unsigned int& size); // Local copies of all the strings std::string instrumentType; // Local copies of all the enums std::vector soundsFiles; std::vector soundsTypes; std::vector instrumentsTypes; std::vector triggersLocations; std::vector instrumentsNames; std::vector instrumentTriggersLocations; std::vector instrumentSoundsTypes; std::vector instrumentSoundsLocs; // Controller DrumKit::KitCreator controller; }; } /* namespace eXaDrumsApi */ #include "KitCreator_api.hpp" #endif /* SOURCE_API_KITCREATOR_KITCREATOR_API_H_ */ libeXaDrums-0.4.2/Api/KitCreator/KitCreator_api.hpp000066400000000000000000000143721354641705500221460ustar00rootroot00000000000000/* * KitCreator_api.hpp * * Created on: 14 Dec 2016 * Author: jeremy */ #ifndef SOURCE_API_KITCREATOR_KITCREATOR_API_HPP_ #define SOURCE_API_KITCREATOR_KITCREATOR_API_HPP_ #include "KitCreator_api.h" #include #include namespace eXaDrumsApi { inline void KitCreator::CreateFromModel(const char* loc) { Util::ErrorToException([&] { return this->CreateFromModel_(loc); }); } inline void KitCreator::SaveKit(const char* file) const { Util::ErrorToException([&] { return this->SaveKit_(file); }); } inline void KitCreator::SaveKit() const { Util::ErrorToException([&] { return this->SaveKit_(); }); } inline void KitCreator::SetInstrumentName(const char* name) { Util::ErrorToException([&] { return this->SetInstrumentName_(name); }); } inline void KitCreator::SetInstrumentName(int id, const char* name) { Util::ErrorToException([&] { return this->SetInstrumentName_(id, name); }); } inline void KitCreator::SetInstrumentTriggersIdsAndLocs(int id, const std::vector>& trigsIdsAndLocs) { // Retrieve triggers ids std::vector ids; std::transform(trigsIdsAndLocs.cbegin(), trigsIdsAndLocs.cend(), std::back_inserter(ids), [](const std::pair& p) { return p.first; }); // Retrieve triggers locations std::vector trigsLocs; std::transform(trigsIdsAndLocs.cbegin(), trigsIdsAndLocs.cend(), std::back_inserter(trigsLocs), [](const std::pair& p) { return p.second; }); // Create trigger locations pointers std::vector locs(trigsLocs.size()); std::transform(trigsLocs.cbegin(), trigsLocs.cend(), locs.begin(), [](const std::string& s) { return s.c_str();}); SetInstrumentTriggersIdsAndLocs_(id, ids.data(), locs.data(), trigsIdsAndLocs.size()); return; } inline void KitCreator::SetInstrumentSoundsTypesAndLocs(int id, const std::vector>& sndTypesAndLocs) { // Retrieve sounds types std::vector sndTypes; std::transform(sndTypesAndLocs.cbegin(), sndTypesAndLocs.cend(), std::back_inserter(sndTypes), [](const std::pair& p){ return p.first; }); // Retrieve sounds locations std::vector sndLocs; std::transform(sndTypesAndLocs.cbegin(), sndTypesAndLocs.cend(), std::back_inserter(sndLocs), [](const std::pair& p){ return p.second; }); // Create sound types pointers std::vector types(sndTypes.size()); std::transform(sndTypes.cbegin(), sndTypes.cend(), types.begin(), [](const std::string& s) { return s.c_str(); }); // Create sound locations pointers std::vector locs(sndLocs.size()); std::transform(sndLocs.cbegin(), sndLocs.cend(), locs.begin(), [](const std::string& s) { return s.c_str(); }); SetInstrumentSoundsTypesAndLocs_(id, types.data(), locs.data(), sndTypesAndLocs.size()); return; } inline std::string KitCreator::GetInstrumentType(int i) { return std::string(GetInstrumentType_(i)); } inline std::vector KitCreator::GetInstrumentTriggersIds(int i) const { unsigned int size; GetInstrumentTriggersIds_(i, nullptr, size); std::vector trigsIds(size); GetInstrumentTriggersIds_(i, trigsIds.data(), size); return trigsIds; } inline std::vector KitCreator::GetTriggersIds() const { unsigned int size; GetTriggersIds_(nullptr, size); std::vector trigsIds(size); GetTriggersIds_(trigsIds.data(), size); return trigsIds; } inline std::vector KitCreator::GetInstrumentTriggersLocations(int i) { unsigned int size; GetInstrumentTriggersLocations_(i, nullptr, size); std::vector data(size); GetInstrumentTriggersLocations_(i, data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector KitCreator::GetInstrumentSoundsTypes(int i) { unsigned int size; GetInstrumentSoundsTypes_(i, nullptr, size); std::vector data(size); GetInstrumentSoundsTypes_(i, data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector KitCreator::GetInstrumentSoundsLocs(int i) { unsigned int size; GetInstrumentSoundsLocs_(i, nullptr, size); std::vector data(size); GetInstrumentSoundsLocs_(i, data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } /*inline std::vector KitCreator::GetSoundsFiles() { unsigned int size; GetSoundFiles_(nullptr, size); std::vector data(size); GetSoundFiles_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; }*/ inline std::vector KitCreator::GetSoundsTypes(const std::string& instrumentType) { unsigned int size; GetSoundTypes_(instrumentType.c_str(), nullptr, size); std::vector data(size); GetSoundTypes_(instrumentType.c_str(), data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector KitCreator::GetInstrumentsTypes() { unsigned int size; GetInstrumentsTypes_(nullptr, size); std::vector data(size); GetInstrumentsTypes_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector KitCreator::GetInstrumentsNames() { unsigned int size; GetInstrumentsNames_(nullptr, size); std::vector data(size); GetInstrumentsNames_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector KitCreator::GetTriggersLocations(const std::string& instrumentType) { unsigned int size; GetTriggersLocations_(instrumentType.c_str(), nullptr, size); std::vector data(size); GetTriggersLocations_(instrumentType.c_str(), data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } } #endif /* SOURCE_API_KITCREATOR_KITCREATOR_API_HPP_ */ libeXaDrums-0.4.2/Api/Version.h.in000066400000000000000000000002761354641705500166670ustar00rootroot00000000000000#ifndef LIBEXADRUMS_SOURCE_API_VERSION_H_ #define LIBEXADRUMS_SOURCE_API_VERSION_H_ namespace eXaDrumsApi { inline constexpr auto LIBEXADRUMS_VERSION = "@PACKAGE_VERSION@"; } #endif libeXaDrums-0.4.2/Api/eXaDrums.cpp000066400000000000000000000234041354641705500167160ustar00rootroot00000000000000/* * eXaDrumsApi.cpp * * Created on: 8 Sep 2015 * Author: jeremy */ #include "eXaDrums.h" #include "../Util/ErrorHandling.h" #include "../DrumKit/DrumModule/Module.h" #include "../Metronome/Metronome.h" #include "../Sound/Alsa/Alsa.h" #include "../Sound/Alsa/AlsaParameters.h" #include "../Sound/Mixer/Mixer.h" #include "../Util/Enums.h" #include #include using namespace Sound; using namespace DrumKit; using namespace Util; /** * eXaDrums API namespace */ namespace eXaDrumsApi { const std::string eXaDrums::metronomeConfigFile = "metronomeConfig.xml"; const std::string eXaDrums::alsaConfigFile = "alsaConfig.xml"; /** * Create an instance of a drum module * @param dataLoc Path to the configuration files */ eXaDrums::eXaDrums(const char* dataLoc) noexcept : isStarted(false) { this->init_error = ExceptionToError([&] { this->dataLocation = std::string{dataLoc} + "/"; // Load alsa parameters AlsaParams alsaParams; AlsaParameters::LoadAlsaParameters(dataLocation + alsaConfigFile, alsaParams); // Create mixer and alsa this->mixer = std::make_shared(); this->alsa = std::make_unique(alsaParams, this->mixer); // Load metronome parameters MetronomeParameters metronomeParams; Metronome::LoadConfig(dataLocation + metronomeConfigFile, metronomeParams); this->metronome = std::make_shared(alsaParams, metronomeParams); // Create drum module this->drumModule = std::make_unique(dataLocation, alsaParams, this->mixer, this->metronome); }); return; } eXaDrums::~eXaDrums() { } // Module error eXaDrums::Start_() { try { this->alsa->Start(); this->drumModule->Start(); } catch(const Exception&) { return ExceptionToError([&] { throw; }); } catch(...) { return make_error("Could not start module.", error_type_error); } isStarted.store(true); return make_error("", error_type_success); } error eXaDrums::Stop_() { try { this->alsa->Stop(); this->drumModule->Stop(); } catch(const std::exception& e) { return make_error("Could not stop module.", error_type_error); } isStarted.store(false); return make_error("", error_type_success); } error eXaDrums::EnableRecording_(bool enable) { try { this->drumModule->EnableRecording(enable); } catch(const std::exception& e) { return make_error("Could not enable/disable recording.", error_type_warning); } return make_error("", error_type_success); } error eXaDrums::RecorderExport_(const char* fileName) { try { this->drumModule->RecorderExport(std::string{fileName}); } catch(const std::exception& e) { return make_error("Could not export track.", error_type_warning); } return make_error("", error_type_success); } void eXaDrums::GetInstrumentTriggersIds_(int instrumentId, int* data, unsigned int& size) const { if(data == nullptr) { size = drumModule->GetInstrumentTriggersIds(instrumentId).size(); return; } std::vector trigsIds = drumModule->GetInstrumentTriggersIds(instrumentId); std::copy(trigsIds.cbegin(), trigsIds.cend(), data); size = trigsIds.size(); } // Metronome void eXaDrums::EnableMetronome(bool enable) const { drumModule->EnableMetronome(enable); return; } void eXaDrums::RestartMetronome() const { drumModule->RestartMetronome(); return; } void eXaDrums::ChangeTempo(std::size_t tempo) const { drumModule->ChangeTempo(tempo); return; } void eXaDrums::ChangeVolume(std::size_t volume) const { drumModule->ChangeVolume(volume); return; } std::size_t eXaDrums::GetTempo() const noexcept { return metronome->GetTempo(); } std::size_t eXaDrums::GetClickVolume() const noexcept { return std::size_t(drumModule->GetClickVolume() * 100.0f); } void eXaDrums::SaveMetronomeConfig() const { metronome->SaveConfig(dataLocation + metronomeConfigFile, metronome->GetParameters()); return; } void eXaDrums::SetClickType(std::size_t id) { const auto types = Enums::GetEnumVector(); if(id >= types.size()) { ClickType type = types.back(); metronome->SetClickType(type); } else { ClickType type = types[id]; metronome->SetClickType(type); } return; } std::size_t eXaDrums::GetClickTypeId() const { ClickType clickType = metronome->GetClickType(); const std::vector& clickTypes = Enums::GetEnumVector(); auto it = std::find(clickTypes.cbegin(), clickTypes.cend(), clickType); std::size_t index = std::distance(clickTypes.cbegin(), it); return index; } std::size_t eXaDrums::GetRhythm() const noexcept { return this->metronome->GetRhythm(); } void eXaDrums::SetRhythm(std::size_t rhythm) noexcept { this->metronome->SetRhythm(rhythm); } std::size_t eXaDrums::GetBpmeas() const noexcept { return this->metronome->GetBpmeas(); } void eXaDrums::SetBpmeas(std::size_t bpmeas) noexcept { this->metronome->SetBpmeas(bpmeas); return; } error eXaDrums::SelectKit_(int id) { return ExceptionToError([&] { this->drumModule->SelectKit(id); }); } error eXaDrums::SaveKitConfig_(std::size_t id) const { return ExceptionToError([&] { drumModule->SaveKitConfig(id); }); } error eXaDrums::DeleteKit_(int id) { if(drumModule->DeleteKit(id)) { return make_error("", error_type_success); } else { return make_error("Could not delete kit.", error_type_error); } } void eXaDrums::ReloadKits() { drumModule->ReloadKits(); return; } std::size_t eXaDrums::GetNumKits() const noexcept { return drumModule->GetNumKits(); } error eXaDrums::SetInstrumentVolume_(std::size_t id, std::size_t volume) { float vol = float(volume) / 100.0f; return ExceptionToError([&] { drumModule->SetInstrumentVolume(id, vol); }); } std::size_t eXaDrums::GetInstrumentVolume(std::size_t id) const { auto volume = (std::size_t) std::floor( 100.0f * drumModule->GetInstrumentVolume(id)); return volume; } long long eXaDrums::GetLastTrigTime() const noexcept { return drumModule->GetLastTrigTime(); } std::size_t eXaDrums::GetLastTrigValue() const noexcept { return drumModule->GetLastTrigValue(); } /** * @brief Set external trigger's data (error handling's responsability is left to the user) * * @param id trigger id * @param channel * @param data trigger's output value */ void eXaDrums::SetTriggerSensorValue(std::size_t id, char channel, short data) { this->drumModule->SetTriggerSensorValue(id, channel, data); } std::size_t eXaDrums::GetSensorsResolution() const noexcept { return this->drumModule->GetSensorsConfig().resolution; } bool eXaDrums::IsSensorVirtual() const noexcept { return this->drumModule->GetSensorsConfig().sensorType == IO::SensorType::Virtual; } bool eXaDrums::IsSensorSpi() const noexcept { return this->drumModule->GetSensorsConfig().sensorType == IO::SensorType::Spi; } std::string eXaDrums::GetAudioDeviceName() const noexcept { return this->alsa->GetDeviceName(); } // Private Methods const char* eXaDrums::GetDataLocation_() const noexcept { return this->dataLocation.c_str(); } const char* eXaDrums::GetKitDataFileName_() { try { std::string kitLocation = this->drumModule->GetKitLocation(); std::size_t pos = kitLocation.find_last_of("/"); this->kitDataFileName = kitLocation.substr(pos + 1, std::string::npos); } catch(...) { return nullptr; } return this->kitDataFileName.c_str(); } void eXaDrums::GetClicksTypes_(const char** data, unsigned int& size) { if(data == nullptr) { size = Enums::GetEnumVector().size(); return; } this->clicksTypes.clear(); { std::vector types = Enums::GetEnumVector(); std::transform(types.cbegin(), types.cend(), std::back_inserter(clicksTypes), [](const ClickType& t) { return Enums::ToString(t); }); } unsigned int numElements = std::min(size, clicksTypes.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = clicksTypes[i].c_str(); } return; } void eXaDrums::GetRhythms_(int* data, unsigned int& size) const { if(data == nullptr) { size = this->metronome->GetRhythmList().size(); return; } std::vector rhythms = this->metronome->GetRhythmList(); std::copy(rhythms.cbegin(), rhythms.cend(), data); size = rhythms.size(); return; } void eXaDrums::GetBpms_(int* data, unsigned int& size) const { if(data == nullptr) { size = this->metronome->GetBpmeasList().size(); return; } std::vector bpms = this->metronome->GetBpmeasList(); std::copy(bpms.cbegin(), bpms.cend(), data); size = bpms.size(); return; } void eXaDrums::GetKitsNames_(const char** data, unsigned int& size) { if(data == nullptr) { size = drumModule->GetKitsNames().size(); return; } this->kitsNames.clear(); this->kitsNames = drumModule->GetKitsNames(); unsigned int numElements = std::min(size, kitsNames.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = kitsNames[i].c_str(); } return; } void eXaDrums::GetInstrumentsNames_(const char** data, unsigned int& size) { if(data == nullptr) { size = drumModule->GetInstrumentsNames().size(); return; } this->instrumentsNames.clear(); this->instrumentsNames = drumModule->GetInstrumentsNames(); unsigned int numElements = std::min(size, instrumentsNames.size()); for(unsigned int i = 0; i < numElements; i++) { data[i] = instrumentsNames[i].c_str(); } return; } double eXaDrums::GetClickPosition() const noexcept { return drumModule->GetClickPosition(); } long long eXaDrums::GetLastClickTime() const noexcept { return drumModule->GetLastClickTime(); } } libeXaDrums-0.4.2/Api/eXaDrums.h000066400000000000000000000077231354641705500163710ustar00rootroot00000000000000/* * eXaDrumsApi.h * * Created on: 8 Sep 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_API_EXADRUMKIT_H_ #define LIBEXADRUMS_SOURCE_API_EXADRUMKIT_H_ #include "Version.h" #include "../Util/ErrorHandling.h" #include #include #include #include #include namespace DrumKit { class Module; class Metronome; } namespace Sound { class Alsa; class Mixer;} namespace eXaDrumsApi { class eXaDrums { friend class Config; public: explicit eXaDrums(const char* dataLocation) noexcept; virtual ~eXaDrums(); // eXaDrums bool IsStarted() const noexcept { return isStarted.load(); } std::string GetDataLocation() const noexcept; // Module void Start(); void Stop(); void EnableRecording(bool enable); void RecorderExport(const std::string& fileName); // Metronome void EnableMetronome(bool enable) const; void RestartMetronome() const; void ChangeTempo(std::size_t tempo) const; void ChangeVolume(std::size_t volume) const; std::size_t GetTempo() const noexcept; std::size_t GetClickVolume() const noexcept; void SaveMetronomeConfig() const; double GetClickPosition() const noexcept; long long GetLastClickTime() const noexcept; std::vector GetClicksTypes(); void SetClickType(std::size_t id); std::size_t GetClickTypeId() const; std::vector GetRhythms() const; std::size_t GetRhythm() const noexcept; void SetRhythm(std::size_t rhythm) noexcept; std::vector GetBpms() const; std::size_t GetBpmeas() const noexcept; void SetBpmeas(std::size_t bpmeas) noexcept; // Kits void SelectKit(std::size_t id); void SaveKitConfig(std::size_t id) const; void DeleteKit(std::size_t id); void ReloadKits(); std::size_t GetNumKits() const noexcept; std::string GetKitDataFileName(); std::vector GetKitsNames(); // Instruments void SetInstrumentVolume(std::size_t id, std::size_t volume); std::size_t GetInstrumentVolume(std::size_t id) const; std::vector GetInstrumentsNames(); std::vector GetInstrumentTriggersIds(std::size_t instrumentId) const; // Triggers long long GetLastTrigTime() const noexcept; std::size_t GetLastTrigValue() const noexcept; void SetTriggerSensorValue(std::size_t id, char channel, short data); // Sensors std::size_t GetSensorsResolution() const noexcept; bool IsSensorVirtual() const noexcept; bool IsSensorSpi() const noexcept; // Sound std::string GetAudioDeviceName() const noexcept; Util::error GetInitError() const { return this->init_error; } private: Util::error Start_(); Util::error Stop_(); Util::error EnableRecording_(bool enable); Util::error SelectKit_(int id); Util::error DeleteKit_(int id); Util::error SaveKitConfig_(std::size_t id) const; Util::error SetInstrumentVolume_(std::size_t id, std::size_t volume); const char* GetDataLocation_() const noexcept; const char* GetKitDataFileName_(); void GetClicksTypes_(const char** data, unsigned int& size); void GetRhythms_(int* data, unsigned int& size) const; void GetBpms_(int* data, unsigned int& size) const; void GetKitsNames_(const char** data, unsigned int& size); void GetInstrumentsNames_(const char** data, unsigned int& size); Util::error RecorderExport_(const char* fileName); void GetInstrumentTriggersIds_(int instrumentId, int* data, unsigned int& size) const; static const std::string metronomeConfigFile; static const std::string alsaConfigFile; std::string dataLocation; std::string kitDataFileName; std::unique_ptr drumModule; std::unique_ptr alsa; std::shared_ptr mixer; std::shared_ptr metronome; std::atomic isStarted; // Local copies of all the enums std::vector clicksTypes; std::vector kitsNames; std::vector instrumentsNames; Util::error init_error; }; } #include "eXaDrums.hpp" #endif /* LIBEXADRUMS_SOURCE_API_EXADRUMKIT_H_ */ libeXaDrums-0.4.2/Api/eXaDrums.hpp000066400000000000000000000062461354641705500167300ustar00rootroot00000000000000/* * eXaDrums.hpp * * Created on: 18 Dec 2016 * Author: jeremy */ #ifndef SOURCE_API_EXADRUMS_HPP_ #define SOURCE_API_EXADRUMS_HPP_ #include "eXaDrums.h" namespace eXaDrumsApi { inline void eXaDrums::Start() { Util::ErrorToException([&] { return this->Start_(); }); } inline void eXaDrums::Stop() { Util::ErrorToException([&] { return this->Stop_(); }); } inline void eXaDrums::EnableRecording(bool enable) { Util::ErrorToException([&] { return this->EnableRecording_(enable); }); } inline void eXaDrums::SelectKit(std::size_t id) { Util::ErrorToException([&] { return this->SelectKit_(id); }); } inline void eXaDrums::SaveKitConfig(std::size_t id) const { Util::ErrorToException([&] { return this->SaveKitConfig_(id); }); } inline void eXaDrums::DeleteKit(std::size_t id) { Util::ErrorToException([&] { return this->DeleteKit_(id); }); } inline std::string eXaDrums::GetDataLocation() const noexcept { return std::string(this->GetDataLocation_()); } inline std::string eXaDrums::GetKitDataFileName() { const char* str = this->GetKitDataFileName_(); if(str == nullptr) { throw Util::Exception("Selected kit's path could not be found.", Util::error_type_error); } return std::string(str); } inline void eXaDrums::RecorderExport(const std::string& fileName) { Util::ErrorToException([&]{ return RecorderExport_(fileName.data()); }); } inline std::vector eXaDrums::GetClicksTypes() { unsigned int size; GetClicksTypes_(nullptr, size); std::vector data(size); GetClicksTypes_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector eXaDrums::GetRhythms() const { unsigned int size; GetRhythms_(nullptr, size); std::vector rhythms(size); GetRhythms_(rhythms.data(), size); return rhythms; } inline std::vector eXaDrums::GetBpms() const { unsigned int size; GetBpms_(nullptr, size); std::vector bpms(size); GetBpms_(bpms.data(), size); return bpms; } inline std::vector eXaDrums::GetKitsNames() { unsigned int size; GetKitsNames_(nullptr, size); std::vector data(size); GetKitsNames_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } inline std::vector eXaDrums::GetInstrumentTriggersIds(std::size_t instrumentId) const { unsigned int size; GetInstrumentTriggersIds_(instrumentId, nullptr, size); std::vector trigsIds(size); GetInstrumentTriggersIds_(instrumentId, trigsIds.data(), size); return trigsIds; } inline void eXaDrums::SetInstrumentVolume(std::size_t id, std::size_t volume) { Util::ExceptionToError([&] { return this->SetInstrumentVolume_(id, volume); }); } inline std::vector eXaDrums::GetInstrumentsNames() { unsigned int size; GetInstrumentsNames_(nullptr, size); std::vector data(size); GetInstrumentsNames_(data.data(), size); std::vector v(size); std::copy(data.cbegin(), data.cend(), v.begin()); return v; } } #endif /* SOURCE_API_EXADRUMS_HPP_ */ libeXaDrums-0.4.2/DrumKit/000077500000000000000000000000001354641705500153255ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/DrumModule/000077500000000000000000000000001354641705500174025ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/DrumModule/Module.cpp000066400000000000000000000220561354641705500213400ustar00rootroot00000000000000/* * Drum.cpp * * Created on: 6 May 2015 * Author: jeremy */ #include "Module.h" #include "../../IO/Spi.h" #include "../../Util/ErrorHandling.h" #include "../../Util/Threading.h" #include "../Triggers/TriggerManager.h" #include "../Triggers/TriggerFactory.h" #include "../Kits/KitManager.h" #include "TrigSound.h" #include using namespace Sound; using namespace Util; namespace DrumKit { Module::Module(std::string dir, const AlsaParams& alsaParams, std::shared_ptr mixer, std::shared_ptr metro) : directory{dir}, kitManager{dir + "Kits/"}, kitId{0}, isPlay{false}, soundBank{std::make_shared(dir)}, mixer{mixer}, metronome{metro}, metronomeSoundId{-1}, isMetronomeEnabled{false}, recorder{soundBank.get(), alsaParams} { mixer->SetSoundBank(soundBank); // Load Triggers LoadTriggers(); // Load all drum kits LoadKits(); // Select current kit SelectKit(kitId); // Set recorder recorder.SetDirectory(dir); recorder.SetMetronomeTimeFunc([&]{ return GetLastClickTime(); }); return; } Module::~Module() { isPlay.store(false); // Join all threads if(playThread.joinable()) { playThread.join(); } } void Module::Start() { isPlay.store(true); playThread = std::thread(&Module::Run, this); // Set high priority to the thread // int maxPriority = sched_get_priority_max(SCHED_FIFO); // // if(maxPriority > 1) // { // maxPriority--; // } // // sched_param sch_params; // sch_params.sched_priority = maxPriority; // // pthread_setschedparam(playThread.native_handle(), SCHED_FIFO, &sch_params); Util::SetThreadPriority(playThread.native_handle(), 99); return; } void Module::Stop() { isPlay.store(false); playThread.join(); mixer->Clear(); return; } void Module::EnableRecording(bool record) { if(record) { recorder.Start(); } else { recorder.Stop(); } } void Module::RecorderExport(const std::string& fileName) { recorder.Export(fileName); } void Module::GetDirectory(std::string& dir) const noexcept { dir = this->directory; return; } void Module::SelectKit(std::size_t id) { if(id > kits.size()) { throw Util::Exception("This drum kit does not exist.", Util::errorType::error_type_error); } // Disable previous kit kits[kitId].Disable(); // Clear sound bank and mixer mixer->Clear(); soundBank->Clear(); // Update kit id kitId = id; // Enable new kit kits[kitId].Enable(); if(isMetronomeEnabled.load()) { EnableMetronome(true); } return; } std::vector Module::GetKitsNames() const noexcept { std::vector names; std::transform(kits.cbegin(), kits.cend(), std::back_inserter(names), [](const Kit& k) { return k.GetName(); }); return names; } std::vector Module::GetInstrumentsNames() const { const std::vector& instruments = kits[kitId].GetInstruments(); std::vector names; std::transform(instruments.cbegin(), instruments.cend(), std::back_inserter(names), [](const InstrumentPtr i) { return i->GetName(); }); return names; } void Module::SetInstrumentVolume(size_t id, float volume) { if(kitId >= kits.size()) { throw Exception("Could not set instrument volume: kit does not exist.", error_type_warning); } kits[kitId].SetInstrumentVolume(id, volume); } float Module::GetInstrumentVolume(int id) const { if(kitId >= kits.size()) { throw Exception("Could not get instrument volume: kit does not exist.", error_type_warning); } return kits[kitId].GetInstrumentVolume(id); } std::vector Module::GetInstrumentTriggersIds(int id) const { const std::vector& instruments = kits[kitId].GetInstruments(); auto const& instrument = instruments[id]; return instrument->GetTriggersIds(); } void Module::SaveKitConfig(std::size_t id) const { if(id < kits.size()) { kits[id].Save(); } else { throw Exception("Could not save kit configuration: this kit does not exist.", error_type_warning); } } std::string Module::GetKitLocation() const { if(kitId < kits.size()) { return kits[kitId].GetConfigFilePath(); } else { throw Exception("Selected kit's path could not be found.", error_type_error); } } bool Module::DeleteKit(const int& id) { bool isSuccess = kitManager.DeleteKit(id); if(isSuccess) { LoadKits(); } return isSuccess; } void Module::ReloadKits() { kitManager.ReScan(); LoadKits(); return; } void Module::ReloadTriggers() { LoadTriggers(); return; } void Module::EnableMetronome(bool enable) { if(enable) { metronome->GenerateClick(); std::vector data = metronome->GetData(); metronomeSoundId = soundBank->AddSound(data, 0.5f); soundBank->LoopSound(metronomeSoundId, true); mixer->PlaySound(metronomeSoundId, 1.0f); isMetronomeEnabled.store(true); } else { if(metronomeSoundId != -1) { // Stop metronome sound mixer->StopSound(metronomeSoundId); soundBank->DeleteSound(metronomeSoundId); } isMetronomeEnabled.store(false); } return; } void Module::ChangeTempo(int tempo) { metronome->SetTempo(tempo); RestartMetronome(); return; } void Module::ChangeVolume(int volume) { if(isMetronomeEnabled.load()) { soundBank->SetSoundVolume(metronomeSoundId, float(volume / 100.0f)); } return; } float Module::GetClickVolume() const noexcept { if(metronomeSoundId != -1) { return soundBank->GetSound(metronomeSoundId).GetVolume(); } else { return 0.0f; } } double Module::GetClickPosition() const noexcept { if(isMetronomeEnabled.load()) { unsigned long pos = soundBank->GetSound(metronomeSoundId).LoadIndex(); double relPos = double(pos) / double(soundBank->GetSound(metronomeSoundId).GetLength()); //fraction -= int(fraction); return relPos; } else { return 0.0f; } } int64_t Module::GetLastClickTime() const noexcept { if(isMetronomeEnabled.load()) { return soundBank->GetSound(metronomeSoundId).GetLastStartTime(); } else { return 0; } } void Module::RestartMetronome() { if(isMetronomeEnabled.load()) { EnableMetronome(false); EnableMetronome(true); } return; } // PRIVATE METHODS void Module::LoadKits() { // Clear kits list kits.clear(); // Get all kits locations std::vector kitsPaths = kitManager.GetKitsLocations(); std::transform(kitsPaths.cbegin(), kitsPaths.cend(), std::back_inserter(kits), [this](std::string const& kitPath) { KitParameters kitParams; KitManager::LoadKit(kitPath, kitParams); return Kit(kitParams, this->triggers, this->soundBank); }); return; } void Module::LoadTriggers() { // Update sensors configuration TriggerManager::LoadSensorsConfig(this->directory, this->sensorsConfig); if(sensorsConfig.sensorType == IO::SensorType::Spi) { IO::Spi::get().Close(); IO::Spi::get().Open(sensorsConfig.samplingRate, 0); } // Load triggers TriggerManager::LoadTriggersConfig(this->directory, sensorsConfig, this->triggersParameters); //TriggerManager::SaveTriggersConfig(this->directory, this->triggersParameters); // Create Triggers this->CreateTriggers(this->triggersParameters); return; } void Module::Run() { lastTrigTime.store(0, std::memory_order_relaxed); lastTrigValue.store(0, std::memory_order_relaxed); while(isPlay.load()) { // Refresh triggers std::for_each(triggers.begin(), triggers.end(), [](TriggerPtr& triggerPtr) { triggerPtr->Refresh(); }); // Get most recent hit auto it = std::max_element(triggers.cbegin(), triggers.cend(), [](const TriggerPtr& t1, const TriggerPtr& t2) { return t1->GetTriggerState().trigTime < t2->GetTriggerState().trigTime; }); int64_t trigTime = (*it)->GetTriggerState().trigTime; int64_t prevTrigTime = lastTrigTime.exchange(trigTime, std::memory_order_release); if(prevTrigTime != trigTime) { lastTrigValue.store(int((*it)->GetTriggerState().value * 100.0f), std::memory_order_release); //std::cout << double(trigTime - soundBank->GetSound(metronomeSoundId).GetLastStartTime()) / 1000. << std::endl; } // Check instruments triggers and send sounds to mixer if necessary const std::vector& instruments = kits[kitId].GetInstruments(); for(const InstrumentPtr& instrumentPtr : instruments) { bool isTriggerEvent = instrumentPtr->IsTriggerEvent(); if(isTriggerEvent) { int soundId = 0; float volume = 1.0f; instrumentPtr->GetSoundProps(soundId, volume); if(recorder.IsRecording(std::memory_order_relaxed)) { recorder.Push(TrigSound{instrumentPtr->GetId(), soundId, trigTime, volume}); } mixer->PlaySound(soundId, volume); } } } return; } void Module::CreateTriggers(const std::vector& triggersParameters) { triggers.clear(); for(const TriggerParameters& triggerParameters : triggersParameters) { TriggerPtr triggerPtr = TriggerFactory::CreateTrigger(triggerParameters); triggers.push_back(triggerPtr); } return; } } libeXaDrums-0.4.2/DrumKit/DrumModule/Module.h000066400000000000000000000065031354641705500210040ustar00rootroot00000000000000/* * Drum.h * * Created on: 6 May 2015 * Author: jeremy */ #ifndef RASPIDRUMS_SOURCE_DRUMKIT_MODULE_H_ #define RASPIDRUMS_SOURCE_DRUMKIT_MODULE_H_ #include "../../Metronome/Metronome.h" #include "../../IO/SensorsConfig.h" #include "../../Sound/Mixer/Mixer.h" #include "../../Sound/Alsa/AlsaParams.h" #include "../../Sound/SoundBank/SoundBank.h" #include "../../Util/SimpleSafeQueue.h" #include "../Kits/Kit.h" #include "Recorder.h" #include #include #include #include #include namespace DrumKit { class Module { public: Module(std::string dir, const Sound::AlsaParams& alsaParams, std::shared_ptr mixer, std::shared_ptr metro); virtual ~Module(); // Kit void SaveKitConfig(std::size_t id) const; std::string GetKitLocation() const; bool DeleteKit(const int& id); void SelectKit(std::size_t id); void ReloadKits(); std::size_t GetKitId() const noexcept { return kitId; } std::size_t GetNumKits() const noexcept { return kits.size(); }; std::vector GetKitsNames() const noexcept; std::vector GetInstrumentsNames() const; // Instrument void SetInstrumentVolume(size_t id, float volume); float GetInstrumentVolume(int id) const; int GetNumInstruments() const { return kits[kitId].GetNumInstruments(); }; std::vector GetInstrumentTriggersIds(int id) const; // Triggers void ReloadTriggers(); void SetTriggerParameters(int triggerId, const TriggerParameters& params) { triggers[triggerId]->SetParameters(params);} void SetTriggerSensorValue(int id, char channel, short data) { triggers[id]->SetSensorData(channel, data); } std::vector GetTriggersParameters() const { return this->triggersParameters; } unsigned long long GetLastTrigTime() const noexcept { return lastTrigTime.load(std::memory_order_acquire); } int GetLastTrigValue() const noexcept { return lastTrigValue.load(std::memory_order_acquire); } // Module void Start(); void Stop(); void EnableRecording(bool record); void RecorderExport(const std::string& fileName); void GetDirectory(std::string& dir) const noexcept; // Metronome void EnableMetronome(bool enable); void ChangeTempo(int tempo); void ChangeVolume(int volume); float GetClickVolume() const noexcept; void RestartMetronome(); double GetClickPosition() const noexcept; int64_t GetLastClickTime() const noexcept; // Config IO::SensorsConfig GetSensorsConfig() const noexcept { return sensorsConfig; } private: void LoadKits(); void LoadTriggers(); void Run(); void CreateTriggers(const std::vector& trigParams); bool IsMetronomeEnabled() const; // Module std::string directory; std::thread playThread; // Kits KitManager kitManager; std::size_t kitId; std::vector kits; std::atomic isPlay; // Triggers std::vector triggersParameters; std::vector triggers; std::atomic lastTrigTime; std::atomic lastTrigValue; IO::SensorsConfig sensorsConfig; // Sound std::shared_ptr soundBank; std::shared_ptr mixer; std::shared_ptr metronome; int metronomeSoundId; std::atomic isMetronomeEnabled; Recorder recorder; }; } #endif /* RASPIDRUMS_SOURCE_DRUMKIT_MODULE_H_ */ libeXaDrums-0.4.2/DrumKit/DrumModule/Recorder.cpp000066400000000000000000000134731354641705500216630ustar00rootroot00000000000000/* * Recorder.cpp * * Created on: 24 Feb 2018 * Author: jeremy */ #include "Recorder.h" #include "../../Util/Parsing.h" #include "../../Util/Misc.h" #include "../../Util/Xml.h" #include "../../Util/Time.h" #include "../../Util/Crypt.h" #include "../../Util/ErrorHandling.h" #include #include #include #include #include #if __has_include() #include namespace fs = std::filesystem; #else #include namespace fs = std::experimental::filesystem; #endif using namespace Sound; using namespace Util; namespace DrumKit { Recorder::Recorder(SoundBank* sndBankPtr, const AlsaParams& alsaParams) noexcept : isRecord{false}, soundBankPtr{sndBankPtr}, alsaParameters{alsaParams} { } Recorder::~Recorder() { isRecord.store(false, std::memory_order_relaxed); if(recordThread.joinable()) { recordThread.join(); } } void Recorder::Start() { isRecord.store(true, std::memory_order_release); recordThread = std::thread(&Recorder::Record, this); } void Recorder::Stop() { isRecord.store(false, std::memory_order_release); recordThread.join(); } void Recorder::Export(const std::string& fileName) { outputFile = fileName; ConvertFile(lastFile); } // PRIVATE Methods void Recorder::DumpBufferToFile() { while(!buffer.empty()) { TrigSound t = buffer.front(); buffer.pop(); file << t.instrumentId << ',' << t.soundId << ',' << t.timeStamp << ',' << t.volume << '\n'; } // Insert keyframe if the metronome is running auto lastClickTime = getLastClickTime(); if(lastClickTime > 0) { file << -1 << ',' << -1 << ',' << lastClickTime << ',' << 0.5f << '\n'; } file.flush(); }; void Recorder::Record() { using namespace Util; using namespace std::chrono_literals; using namespace std::chrono; using namespace std::this_thread; // Create new file const auto fileTimeStamp = duration_cast(system_clock::now().time_since_epoch()).count(); const std::string fileName = directory + std::to_string(fileTimeStamp) + ".csv"; file.open(fileName); while(isRecord.load(std::memory_order_acquire)) { TrigSound trigSound; while(recordQueue.Pop(trigSound)) { buffer.emplace(std::move(trigSound)); } // Write data to file if(buffer.size() >= recordQueue.Capacity() / 8) { DumpBufferToFile(); } // Wait before we try to get more sounds if(isRecord.load(std::memory_order_relaxed)) { sleep_for(500ms); } } DumpBufferToFile(); file.close(); lastFile = fileName; //ConvertFile(fileName); } /** * Converts the temporary csv file to an xml file. * @param fileLoc File location. */ void Recorder::ConvertFile(const std::string& fileLoc) { using namespace Util; using namespace tinyxml2; using namespace std::chrono; using TrigSoundTuple = std::tuple; std::ifstream file{fileLoc}; if(!file.good()) { throw Exception("Could not load record file.", error_type_error); } // Read file line by line std::vector lines{std::istream_iterator{file}, std::istream_iterator{}}; XMLDocument doc; auto root = doc.NewElement("root"); // We'll store all the sounds ids in that vector std::vector soundsIds; soundsIds.reserve(lines.size()); std::map> instrumentsSounds; auto xmlSounds = CreateXmlElement(doc, "Sounds"); root->InsertEndChild(xmlSounds); for(const auto& l : lines) { std::istringstream iss(l); std::vector tokens{std::istream_iterator>{iss}, std::istream_iterator>{}}; TrigSoundTuple tuple; VectorOfStrToTuple(tokens, tuple); TrigSound t; std::tie(t.instrumentId, t.soundId, t.timeStamp, t.volume) = tuple; soundsIds.push_back(t.soundId); instrumentsSounds[t.instrumentId].emplace(t.soundId); xmlSounds->InsertEndChild(CreateXmlElement(doc, "Sound", "", {{"Id", t.soundId}, {"TrigTime", t.timeStamp}, {"Volume", t.volume}})); } // Remove metronome from the instruments list instrumentsSounds.erase(-1); // Get all the unique sounds ids std::set uniqueSoundsIds(soundsIds.begin(), soundsIds.end()); // Remove the metronome from the set uniqueSoundsIds.erase(-1); // Create xml document // Header auto xmlHeader = CreateXmlElement(doc, "Header"); { const auto fileTimeStamp = duration_cast(system_clock::now().time_since_epoch()).count(); xmlHeader->InsertEndChild(CreateXmlElement(doc, "Date", TimeStampToStr(fileTimeStamp))); xmlHeader->InsertEndChild(CreateXmlElement(doc, "SampleRate", alsaParameters.sampleRate)); xmlHeader->InsertEndChild(CreateXmlElement(doc, "NumberOfChannels", alsaParameters.nChannels)); auto instrumentsXml = CreateXmlElement(doc, "Instruments"); xmlHeader->InsertEndChild(instrumentsXml); for(const auto& instrumentSounds : instrumentsSounds) { instrumentsXml->InsertEndChild(CreateXmlElement(doc, "Instrument", "", {{"Id", instrumentSounds.first}, {"Sounds", JoinToStr(instrumentSounds.second, ", ")}})); } root->InsertFirstChild(xmlHeader); } // Data { auto xmlData = CreateXmlElement(doc, "Data"); for(const auto& soundId : uniqueSoundsIds) { const auto& sound = soundBankPtr->GetSound(soundId); const auto& soundData = sound.GetInternalData(); xmlData->InsertEndChild(CreateXmlElement(doc, "Sound", Base64Encode(soundData), {{"Id", soundId}})); } xmlHeader->InsertEndChild(xmlData); } doc.InsertFirstChild(root); if(outputFile.empty()) { doc.SaveFile(std::string(directory + std::string("rec.xml")).data()); } else { fs::path p{outputFile}; if(p.extension() == ".xml") { doc.SaveFile(p.c_str()); } else { doc.SaveFile((outputFile + ".xml").data()); } } } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/DrumModule/Recorder.h000066400000000000000000000031701354641705500213210ustar00rootroot00000000000000/* * Recorder.h * * Created on: 24 Feb 2018 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_DRUMMODULE_RECORDER_H_ #define SOURCE_DRUMKIT_DRUMMODULE_RECORDER_H_ #include "../../Sound/SoundBank/SoundBank.h" #include "../../Util/SimpleSafeQueue.h" #include "../../Sound/Alsa/AlsaParams.h" #include "TrigSound.h" #include #include #include #include #include #include #include namespace DrumKit { class Module; class Recorder { public: Recorder(Sound::SoundBank* sndBankPtr, const Sound::AlsaParams& alsaParams) noexcept; virtual ~Recorder(); void SetDirectory(const std::string& dir) noexcept { directory = dir + "Rec/"; } template void SetMetronomeTimeFunc(T&& f) noexcept { getLastClickTime = std::function{f}; } void Start(); void Stop(); void Export(const std::string& fileName); bool Push(TrigSound&& value) { return recordQueue.Push(value); } bool IsRecording(std::memory_order memOrder = std::memory_order_acquire) const { return isRecord.load(memOrder); } private: void Record(); void DumpBufferToFile(); void ConvertFile(const std::string& file); std::atomic isRecord; Sound::SoundBank* soundBankPtr; Sound::AlsaParams alsaParameters; std::string directory; std::string outputFile; std::string lastFile; std::function getLastClickTime = []{return 0;}; std::ofstream file; std::thread recordThread; std::queue buffer; Util::SimpleSafeQueue recordQueue; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_DRUMMODULE_RECORDER_H_ */ libeXaDrums-0.4.2/DrumKit/DrumModule/TrigSound.h000066400000000000000000000005601354641705500214720ustar00rootroot00000000000000/* * TrigSound.h * * Created on: 3 Mar 2018 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_DRUMMODULE_TRIGSOUND_H_ #define SOURCE_DRUMKIT_DRUMMODULE_TRIGSOUND_H_ #include namespace DrumKit { struct TrigSound { int instrumentId; int soundId; int64_t timeStamp; float volume; }; } #endif /* SOURCE_DRUMKIT_DRUMMODULE_TRIGSOUND_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/000077500000000000000000000000001354641705500176605ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Instruments/Cymbals/000077500000000000000000000000001354641705500212525ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Instruments/Cymbals/TestHiHat.cpp000066400000000000000000000055101354641705500236140ustar00rootroot00000000000000/* * TestHiHat.cpp * * Created on: 2 Nov 2016 * Author: jeremy */ #include "TestHiHat.h" #include "../../../Sound/InstrumentSoundType.h" #include "../../../Sound/SoundProcessor/SoundProcessor.h" #include using namespace Sound; namespace DrumKit { TestHiHat::TestHiHat(InstrumentParameters parameters, std::shared_ptr soundBank) : Instrument(parameters, soundBank), cymbalSoundId(0) { return; } void TestHiHat::SetTriggers(const std::vector& triggers) { for(const TriggerPtr& triggerPtr : triggers) { auto triggerIdAndLocation = std::find_if(parameters.triggersIdsAndLocations.cbegin(), parameters.triggersIdsAndLocations.cend(), [triggerPtr](std::pair const& idAndLocation) { return (idAndLocation.first == triggerPtr->GetId()); }); if(triggerIdAndLocation != std::end(parameters.triggersIdsAndLocations)) { TriggerLocation triggerLocation = triggerIdAndLocation->second; switch (triggerLocation) { case TriggerLocation::DrumHead: this->cymbalTrigger = triggerPtr; break; case TriggerLocation::Rim: this->pedalTrigger = triggerPtr; break; default: break; } } } return; } void TestHiHat::SetSound(const InstrumentSoundInfo& soundInfo) { InstrumentSoundType soundType = soundInfo.type; std::string soundLocation = soundInfo.soundLocation; switch (soundType) { case InstrumentSoundType::Default: { cymbalSoundId = soundBank->LoadSound(soundLocation, parameters.volume); for(int i = 0; i < 10; i++) { const auto& cymbalSound = soundBank->GetSound(cymbalSoundId); auto&& newSound = SoundProcessor::Muffle(cymbalSound, 0.25f/float(i + 1)); int newSoundId = soundBank->AddSound(std::move(newSound), parameters.volume); hiHatSoundsIds.push_back(newSoundId); } break; } default: throw -1; break; } return; } void TestHiHat::SetVolume(float volume) { soundBank->SetSoundVolume(cymbalSoundId, volume); std::for_each(hiHatSoundsIds.cbegin(), hiHatSoundsIds.cend(), [&](const int& id) { soundBank->SetSoundVolume(id, volume); }); parameters.volume = volume; return; } bool TestHiHat::IsTriggerEvent() const { TriggerState cymbalTriggerState = cymbalTrigger->GetTriggerState(); if(cymbalTriggerState.isTrig) { return true; } else { return false; } } void TestHiHat::GetSoundProps(int& id, float& volume) const { TriggerState cymbalTriggerState = cymbalTrigger->GetTriggerState(); TriggerState pedalTriggerState = pedalTrigger->GetTriggerState(); if(cymbalTriggerState.isTrig) { float pedalPosition = pedalTriggerState.value; int hiHatSoundIndex = cymbalSoundId + std::floor(pedalPosition * 10) + 1; id = hiHatSoundIndex; volume = cymbalTriggerState.value; } return; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Instruments/Cymbals/TestHiHat.h000066400000000000000000000027461354641705500232710ustar00rootroot00000000000000/* * TestHiHat.h * * Created on: 2 Nov 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_CYMBALS_TESTHIHAT_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_CYMBALS_TESTHIHAT_H_ #include "../../../Sound/SoundBank/SoundBank.h" #include "../../../Sound/InstrumentSoundType.h" #include "../../Triggers/Triggers/Trigger.h" #include "../Instrument.h" #include #include #include namespace DrumKit { class TestHiHat: public Instrument { public: TestHiHat(InstrumentParameters parameters, std::shared_ptr soundBank); ~TestHiHat() = default; virtual void SetTriggers(std::vector const& triggers) final; virtual void SetSound(InstrumentSoundInfo const& soundInfo) final; virtual void SetVolume(float volume) final; virtual bool IsTriggerEvent() const final; virtual void GetSoundProps(int& id, float& volume) const final; virtual std::vector GetSoundTypes() const final { return {Sound::InstrumentSoundType::Default}; } virtual std::vector GetTriggersLocations() const final { return {TriggerLocation::DrumHead, TriggerLocation::Rim}; }; virtual std::vector GetTriggersIds() const final { return {cymbalTrigger->GetId(), pedalTrigger->GetId()}; }; private: TriggerPtr cymbalTrigger; TriggerPtr pedalTrigger; std::vector hiHatSoundsIds; int cymbalSoundId; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_INSTRUMENTS_CYMBALS_TESTHIHAT_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/Drums/000077500000000000000000000000001354641705500207525ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Instruments/Drums/TestDrum.cpp000066400000000000000000000062621354641705500232330ustar00rootroot00000000000000/* * Drum.cpp * * Created on: 28 Oct 2015 * Author: jeremy */ #include "TestDrum.h" #include using namespace Sound; namespace DrumKit { TestDrum::TestDrum(InstrumentParameters parameters, std::shared_ptr soundBank): Instrument(parameters, soundBank), drumHeadSoundId(0), drumRimSoundId(0) { return; } void TestDrum::SetTriggers(std::vector const& triggers) { for(const TriggerPtr& triggerPtr : triggers) { auto triggerIdAndLocation = std::find_if(parameters.triggersIdsAndLocations.cbegin(), parameters.triggersIdsAndLocations.cend(), [triggerPtr](std::pair const& idAndLocation) { return (idAndLocation.first == triggerPtr->GetId()); }); if(triggerIdAndLocation != std::end(parameters.triggersIdsAndLocations)) { TriggerLocation triggerLocation = triggerIdAndLocation->second; switch (triggerLocation) { case TriggerLocation::DrumHead: this->drumHeadTrigger = triggerPtr; break; case TriggerLocation::Rim: this->drumRimTrigger = triggerPtr; break; default: break; } } } return; } void TestDrum::SetSound(InstrumentSoundInfo const& soundInfo) { InstrumentSoundType soundType = soundInfo.type; std::string soundLocation = soundInfo.soundLocation; switch (soundType) { case InstrumentSoundType::RimShot: drumRimSoundId = soundBank->LoadSound(soundLocation, parameters.volume); break; case InstrumentSoundType::Default: drumHeadSoundId = soundBank->LoadSound(soundLocation, parameters.volume); break; default: throw -1; break; } return; } void TestDrum::SetVolume(float volume) { soundBank->SetSoundVolume(drumRimSoundId, volume); soundBank->SetSoundVolume(drumHeadSoundId, volume); parameters.volume = volume; return; } bool TestDrum::IsTriggerEvent() const { TriggerState headTriggerState = drumHeadTrigger->GetTriggerState(); TriggerState rimTriggerState = drumRimTrigger->GetTriggerState(); if(headTriggerState.isTrig || rimTriggerState.isTrig) { return true; } else { return false; } } void TestDrum::GetSoundProps(int& id, float& volume) const { TriggerState headTriggerState = drumHeadTrigger->GetTriggerState(); TriggerState rimTriggerState = drumRimTrigger->GetTriggerState(); if(headTriggerState.isTrig) { id = drumHeadSoundId; volume = headTriggerState.value; } else if(rimTriggerState.isTrig) { id = drumRimSoundId; volume = rimTriggerState.value; } return; } // PRIVATE /*void Drum::GenerateSounds() { std::function genSounds = [this](InstrumentSoundInfo soundInfo) { std::vector soundData; unsigned int soundDuration; // Load sound //Sound::SoundBank::LoadSound(soundInfo.soundLocation, soundData, soundDuration); switch (soundInfo.type) { case Sound::InstrumentSoundType::Default: int id; //soundProcessor->AddSound(id, soundData); // Internal Id = 0 for default sound soundIds.insert(std::pair(0, id)); break; default: break; } }; std::for_each(parameters.soundsInfo.cbegin(), parameters.soundsInfo.cend(), genSounds); return; } */ } libeXaDrums-0.4.2/DrumKit/Instruments/Drums/TestDrum.h000066400000000000000000000026511354641705500226760ustar00rootroot00000000000000/* * Drum.h * * Created on: 28 Oct 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_DRUMKIT_DRUM_H_ #define LIBEXADRUMS_SOURCE_DRUMKIT_DRUM_H_ #include "../../../Sound/SoundBank/SoundBank.h" #include "../../../Sound/InstrumentSoundType.h" #include "../../Triggers/Triggers/Trigger.h" #include "../Instrument.h" #include #include namespace DrumKit { class TestDrum : public Instrument { public: TestDrum(InstrumentParameters parameters, std::shared_ptr sb); ~TestDrum() = default; virtual void SetTriggers(std::vector const& triggers) final; virtual void SetSound(InstrumentSoundInfo const& soundInfo) final; virtual void SetVolume(float volume) final; virtual bool IsTriggerEvent() const final; virtual void GetSoundProps(int& id, float& volume) const final; virtual std::vector GetSoundTypes() const final { return {Sound::InstrumentSoundType::Default, Sound::InstrumentSoundType::RimShot}; } virtual std::vector GetTriggersLocations() const final { return {TriggerLocation::DrumHead, TriggerLocation::Rim}; }; virtual std::vector GetTriggersIds() const final { return {drumHeadTrigger->GetId(), drumRimTrigger->GetId()}; }; private: TriggerPtr drumHeadTrigger; TriggerPtr drumRimTrigger; int drumHeadSoundId; int drumRimSoundId; }; } #endif /* LIBEXADRUMS_SOURCE_DRUMKIT_DRUM_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/Instrument.cpp000066400000000000000000000004631354641705500225370ustar00rootroot00000000000000/* * Instrument.cpp * * Created on: 15 Nov 2015 * Author: jeremy */ #include "Instrument.h" namespace DrumKit { Instrument::Instrument(const InstrumentParameters& parameters, std::shared_ptr sb) : parameters(parameters), soundBank(std::move(sb)) { return; } } libeXaDrums-0.4.2/DrumKit/Instruments/Instrument.h000066400000000000000000000027241354641705500222060ustar00rootroot00000000000000/* * IInstrument.h * * Created on: 15 Nov 2015 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENT_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENT_H_ #include "../../Sound/SoundBank/SoundBank.h" #include "../Triggers/Triggers/Trigger.h" #include "InstrumentParameters.h" #include #include namespace DrumKit { class Instrument { public: Instrument(const InstrumentParameters& parameters, std::shared_ptr sb); virtual void SetTriggers(std::vector const& triggers) = 0; virtual void SetSound(InstrumentSoundInfo const& soundInfo) = 0; virtual void SetVolume(float volume) = 0; virtual void GetSoundProps(int& id, float& volume) const = 0; virtual bool IsTriggerEvent() const = 0; virtual int GetId() const { return this->parameters.id; } virtual float GetVolume() const { return this->parameters.volume; } virtual std::string GetName() const { return this->parameters.instrumentName; } virtual std::vector GetSoundTypes() const = 0; virtual std::vector GetTriggersLocations() const = 0; virtual std::vector GetTriggersIds() const = 0; protected: virtual ~Instrument() = default; InstrumentParameters parameters; std::shared_ptr soundBank; //std::map soundIds; private: }; typedef std::shared_ptr InstrumentPtr; } #endif /* SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENT_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/InstrumentFactory.h000066400000000000000000000030651354641705500235350ustar00rootroot00000000000000/* * InstrumentFactory.h * * Created on: 15 Jun 2017 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTFACTORY_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTFACTORY_H_ #include "../../Util/ErrorHandling.h" #include "../../Sound/SoundBank/SoundBank.h" #include "../../Sound/InstrumentSoundType.h" #include "../Triggers/TriggerType.h" #include "Cymbals/TestHiHat.h" #include "Drums/TestDrum.h" #include "Pads/Pad.h" #include "InstrumentType.h" #include "Instrument.h" #include namespace DrumKit { class InstrumentFactory { public: static InstrumentPtr CreateInstrument(InstrumentType type, InstrumentParameters parameters, std::shared_ptr sb) { switch(type) { case InstrumentType::Pad: return std::make_shared(parameters, sb); case InstrumentType::TestDrum: return std::make_shared(parameters, sb); case InstrumentType::HiHat: return std::make_shared(parameters, sb); } throw Util::Exception("Instrument type does not exist.", Util::error_type_error); } static std::vector GetSoundsTypes(InstrumentType type) { return CreateInstrument(type, InstrumentParameters(), nullptr)->GetSoundTypes(); } static std::vector GetTriggersTypes(InstrumentType type) { return CreateInstrument(type, InstrumentParameters(), nullptr)->GetTriggersLocations(); } private: InstrumentFactory() = delete; ~InstrumentFactory() = delete; }; } #endif /* SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTFACTORY_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/InstrumentParameters.h000066400000000000000000000032301354641705500242230ustar00rootroot00000000000000/* * InstrumentParameters.h * * Created on: 15 Nov 2015 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTPARAMETERS_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTPARAMETERS_H_ #include "../../Util/Xml.h" #include "../../Util/Enums.h" #include "../Triggers/TriggerLocation.h" #include "InstrumentSoundInfo.h" #include "InstrumentType.h" #include #include #include #include namespace DrumKit { struct InstrumentParameters { void ToXml(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* element) { using namespace Util; element->InsertEndChild(CreateXmlElement(doc, "instrumentName", instrumentName)); // Triggers { // Create triggers element tinyxml2::XMLElement* triggers = CreateXmlElement(doc, "triggers", ""); for(const auto& trigger : triggersIdsAndLocations) { triggers->InsertEndChild(CreateXmlElement(doc, "trigger", trigger.first, {{"location", Enums::ToString(trigger.second)}})); } element->InsertEndChild(triggers); } // Sounds { // Create sounds element tinyxml2::XMLElement* sounds = CreateXmlElement(doc, "sounds", ""); for(const auto& sound : soundsInfo) { sounds->InsertEndChild(CreateXmlElement(doc, "sound", sound.soundLocation, {{"type", Enums::ToString(sound.type)}})); } element->InsertEndChild(sounds); } } InstrumentType instrumentType; int id; float volume; std::string instrumentName; std::vector soundsInfo; std::vector> triggersIdsAndLocations; }; } #endif /* SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTPARAMETERS_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/InstrumentSoundInfo.h000066400000000000000000000007311354641705500240270ustar00rootroot00000000000000/* * InstrumentSoundInfo.h * * Created on: 15 Feb 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTSOUNDINFO_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTSOUNDINFO_H_ #include "../../Sound/InstrumentSoundType.h" #include namespace DrumKit { struct InstrumentSoundInfo { int id; std::string soundLocation; Sound::InstrumentSoundType type; }; } #endif /* SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTSOUNDINFO_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/InstrumentType.h000066400000000000000000000027161354641705500230510ustar00rootroot00000000000000/* * InstrumentTypes.h * * Created on: 7 Feb 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTTYPE_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTTYPE_H_ #include #include #include namespace DrumKit { enum class InstrumentType { TestDrum, Pad, //Drum, //Cymbal, HiHat, //BassDrum, First = TestDrum, Last = HiHat }; inline std::ostream& operator<<(std::ostream& o, const InstrumentType& x) { std::string os; switch (x) { case InstrumentType::TestDrum: os = "DualZonePad"; break; case InstrumentType::Pad: os = "Pad"; break; //case InstrumentType::Drum: os = "Drum"; break; //case InstrumentType::Cymbal: os = "Cymbal"; break; case InstrumentType::HiHat: os = "HiHat"; break; //case InstrumentType::BassDrum: os = "BassDrum"; break; default: break; } return o << os; } inline InstrumentType operator++(InstrumentType& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline InstrumentType operator*(InstrumentType i) { return i; }; inline InstrumentType begin(InstrumentType x) { return InstrumentType::First; }; inline InstrumentType end(InstrumentType x) { InstrumentType l = InstrumentType::Last; return ++l; }; inline std::istream& operator>>(std::istream& is, InstrumentType& x) { return Util::StreamToEnum(is, x); } } #endif /* SOURCE_DRUMKIT_INSTRUMENTS_INSTRUMENTTYPE_H_ */ libeXaDrums-0.4.2/DrumKit/Instruments/Pads/000077500000000000000000000000001354641705500205475ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Instruments/Pads/Pad.cpp000066400000000000000000000035041354641705500217610ustar00rootroot00000000000000/* * Pad.cpp * * Created on: 11 Jun 2017 * Author: jeremy */ #include "Pad.h" using namespace Sound; #include namespace DrumKit { Pad::Pad(InstrumentParameters parameters, std::shared_ptr soundBank): Instrument(parameters, soundBank), soundId(0) { return; } void Pad::SetTriggers(std::vector const& triggers) { for(const TriggerPtr& triggerPtr : triggers) { auto triggerIdAndLocation = std::find_if(parameters.triggersIdsAndLocations.cbegin(), parameters.triggersIdsAndLocations.cend(), [triggerPtr](std::pair const& idAndLocation) { return (idAndLocation.first == triggerPtr->GetId()); }); if(triggerIdAndLocation != std::end(parameters.triggersIdsAndLocations)) { TriggerLocation triggerLocation = triggerIdAndLocation->second; switch (triggerLocation) { case TriggerLocation::DrumHead: this->trigger = triggerPtr; break; default: break; } } } return; } void Pad::SetSound(InstrumentSoundInfo const& soundInfo) { InstrumentSoundType soundType = soundInfo.type; std::string soundLocation = soundInfo.soundLocation; switch (soundType) { case InstrumentSoundType::Default: soundId = soundBank->LoadSound(soundLocation, parameters.volume); break; default: throw -1; break; } return; } void Pad::SetVolume(float volume) { soundBank->SetSoundVolume(soundId, volume); parameters.volume = volume; return; } void Pad::GetSoundProps(int& id, float& volume) const { TriggerState triggerState = trigger->GetTriggerState(); if(triggerState.isTrig) { id = soundId; volume = triggerState.value; } return; } bool Pad::IsTriggerEvent() const { TriggerState triggerState = trigger->GetTriggerState(); return triggerState.isTrig; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Instruments/Pads/Pad.h000066400000000000000000000024361354641705500214310ustar00rootroot00000000000000/* * Pad.h * * Created on: 11 Jun 2017 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_INSTRUMENTS_PADS_PAD_H_ #define SOURCE_DRUMKIT_INSTRUMENTS_PADS_PAD_H_ #include "../../../Sound/SoundBank/SoundBank.h" #include "../../../Sound/InstrumentSoundType.h" #include "../../Triggers/Triggers/Trigger.h" #include "../Instrument.h" #include #include namespace DrumKit { class Pad : public Instrument { public: Pad(InstrumentParameters parameters, std::shared_ptr sb); ~Pad() = default; virtual void SetTriggers(std::vector const& triggers) final; virtual void SetSound(InstrumentSoundInfo const& soundInfo) final; virtual void SetVolume(float volume) final; virtual void GetSoundProps(int& id, float& volume) const final; virtual bool IsTriggerEvent() const final; virtual std::vector GetSoundTypes() const final { return {Sound::InstrumentSoundType::Default}; } virtual std::vector GetTriggersLocations() const final { return {TriggerLocation::DrumHead}; }; virtual std::vector GetTriggersIds() const final { return { trigger->GetId() }; }; private: TriggerPtr trigger; int soundId; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_INSTRUMENTS_PADS_PAD_H_ */ libeXaDrums-0.4.2/DrumKit/Kits/000077500000000000000000000000001354641705500162375ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Kits/Kit.cpp000066400000000000000000000037721354641705500175030ustar00rootroot00000000000000/* * Kit.cpp * * Created on: 21 Aug 2016 * Author: jeremy */ #include "Kit.h" #include "../../Util/ErrorHandling.h" #include "../Triggers/TriggerType.h" #include "../Instruments/InstrumentFactory.h" #include using namespace Util; namespace DrumKit { Kit::Kit(const KitParameters& params, std::vector const& trigs, std::shared_ptr sb) : parameters(params), triggers(trigs), soundBank(std::move(sb)) { return; } Kit::~Kit() { return; } void Kit::Enable() { CreateInstruments(); return; } void Kit::Disable() { std::for_each(instruments.begin(), instruments.end(), [](InstrumentPtr& inst) { inst.reset(); }); instruments.clear(); return; } void Kit::SetInstrumentVolume(size_t id, float volume) { if(id >= this->instruments.size()) { throw Exception("Could not set instrument volume: instrument does not exist.", error_type_warning); } this->instruments[id]->SetVolume(volume); this->parameters.instrumentParameters[id].volume = volume; return; } std::string Kit::GetInstrumentName(std::size_t id) const { if(id > parameters.instrumentParameters.size()) { throw Exception("The instrument could not be found.", error_type_error); } std::string name = parameters.instrumentParameters[id].instrumentName; return name; } /// PRIVATE METHODS void Kit::CreateInstruments() { for(InstrumentParameters const& instrumentParameters : this->parameters.instrumentParameters) { // Create instrument InstrumentPtr instrumentPtr = InstrumentFactory::CreateInstrument(instrumentParameters.instrumentType, instrumentParameters, soundBank); // Create instrument's triggers instrumentPtr->SetTriggers(this->triggers); // Set instrument sounds for(InstrumentSoundInfo const& soundInfo : instrumentParameters.soundsInfo) { instrumentPtr->SetSound(soundInfo); } // Add instrument to drum module instruments.push_back(instrumentPtr); } return; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Kits/Kit.h000066400000000000000000000027011354641705500171370ustar00rootroot00000000000000/* * Kit.h * * Created on: 21 Aug 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_KITS_KIT_H_ #define SOURCE_DRUMKIT_KITS_KIT_H_ #include "KitParameters.h" #include "KitManager.h" #include "../../Sound/SoundBank/SoundBank.h" #include "../Instruments/Instrument.h" #include "../Triggers/Triggers/Trigger.h" #include #include namespace DrumKit { class Kit { public: Kit(const KitParameters& params, std::vector const& trigs, std::shared_ptr sb); virtual ~Kit(); void Enable(); void Disable(); void Save() const { KitManager::SaveKit(parameters.configFilePath, parameters);} void SetInstrumentVolume(size_t id, float volume); std::string GetConfigFilePath() const noexcept { return parameters.configFilePath; } float GetInstrumentVolume(int id) const { return instruments[id]->GetVolume(); } std::string GetInstrumentName(std::size_t id) const; std::string GetName() const noexcept { return parameters.kitName; } int GetNumInstruments() const { return (int)parameters.instrumentParameters.size(); } const std::vector& GetInstruments() const { return instruments; } private: void CreateInstruments(); KitParameters parameters; const std::vector& triggers; std::shared_ptr soundBank; std::vector instruments; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_KITS_KIT_H_ */ libeXaDrums-0.4.2/DrumKit/Kits/KitCreator.cpp000066400000000000000000000172311354641705500210160ustar00rootroot00000000000000/* * KitCreator.cpp * * Created on: 9 Nov 2016 * Author: jeremy */ #include "KitCreator.h" #include "../../Sound/SoundBank/SoundBank.h" #include "../Instruments/InstrumentFactory.h" #include using namespace Sound; using namespace Util; namespace DrumKit { KitCreator::KitCreator(const std::string& dataLoc) noexcept : dataFolder{dataLoc}, kitsDirectory(dataLoc + "Kits/"), instrument() //, soundFiles(SoundBank::GetSoundFiles(dataLoc)) { return; } KitCreator::~KitCreator() { return; } void KitCreator::CreateNewKit() noexcept { this->parameters = KitParameters(); this->instrument = InstrumentParameters(); return; } void KitCreator::CreateFromModel(const std::string& file) { KitManager::LoadKit(this->kitsDirectory + file, this->parameters); this->instrument = InstrumentParameters(); return; } void KitCreator::SaveKit(const std::string& file, bool fullPath) const { if(fullPath) { KitManager::SaveKit(file, this->parameters); } else { KitManager::SaveKit(this->kitsDirectory + file, this->parameters); } return; } void KitCreator::SaveKit() const { std::string configFilePath = this->parameters.configFilePath; if(configFilePath.empty()) { std::string file = this->parameters.kitName + ".xml"; SaveKit(file); } else { SaveKit(configFilePath, true); } return; } void KitCreator::AddInstrumentToKit() noexcept { this->parameters.instrumentParameters.push_back(this->instrument); this->instrument = InstrumentParameters(); return; } void KitCreator::CreateNewInstrument() noexcept { this->instrument = InstrumentParameters(); this->instrument.id = (int) this->parameters.instrumentParameters.size(); return; } void KitCreator::RemoveInstrument(std::size_t i) noexcept { if(parameters.instrumentParameters.size() > 1) { parameters.instrumentParameters.erase(parameters.instrumentParameters.begin() + i); } return; } void KitCreator::RemoveLastInstrument() noexcept { if(parameters.instrumentParameters.size() > 1) { parameters.instrumentParameters.erase(parameters.instrumentParameters.end() - 1); } return; } void KitCreator::SetInstrumentType(const std::string& typeStr) { InstrumentType type = Enums::ToElement(typeStr); this->instrument.instrumentType = type; return; } void KitCreator::AddInstrumentSound(const std::string& file, const std::string& typeStr) { InstrumentSoundType soundType = Enums::ToElement(typeStr); InstrumentSoundInfo instrumentSoundInfo; { instrumentSoundInfo.id = (int) this->instrument.soundsInfo.size(); instrumentSoundInfo.soundLocation = file; instrumentSoundInfo.type = soundType; } this->instrument.soundsInfo.push_back(instrumentSoundInfo); return; } void KitCreator::AddInstrumentTrigger(const int id, const std::string& location) { TriggerLocation trigLoc = Enums::ToElement(location); this->instrument.triggersIdsAndLocations.push_back(std::pair{id, trigLoc}); return; } void KitCreator::SetInstrumentTriggersIdsAndLocs(int id, const std::vector>& trigsIdsAndLocs) { InstrumentParameters& instrument = parameters.instrumentParameters[id]; instrument.triggersIdsAndLocations.clear(); instrument.triggersIdsAndLocations.resize(trigsIdsAndLocs.size()); for(std::size_t i = 0; i < trigsIdsAndLocs.size(); i++) { instrument.triggersIdsAndLocations[i].first = trigsIdsAndLocs[i].first; TriggerLocation trigLoc = Enums::ToElement(trigsIdsAndLocs[i].second); instrument.triggersIdsAndLocations[i].second = trigLoc; } return; } void KitCreator::SetInstrumentSoundsTypesAndLocs(int id, const std::vector>& sndsTypesAndLocs) { InstrumentParameters& instrument = parameters.instrumentParameters[id]; instrument.soundsInfo.clear(); instrument.soundsInfo.resize(sndsTypesAndLocs.size()); for(std::size_t i = 0; i < sndsTypesAndLocs.size(); i++) { instrument.soundsInfo[i].type = Enums::ToElement(sndsTypesAndLocs[i].first); instrument.soundsInfo[i].soundLocation = sndsTypesAndLocs[i].second; } return; } std::string KitCreator::GetInstrumentType(int i) const { InstrumentType type = parameters.instrumentParameters[i].instrumentType; std::string typeStr = Enums::ToString(type); return typeStr; } std::vector KitCreator::GetInstrumentsTriggersIds(int i) const { const auto& triggers = parameters.instrumentParameters[i].triggersIdsAndLocations; std::vector triggersIds(triggers.size()); std::transform(triggers.cbegin(), triggers.cend(), triggersIds.begin(), [](const std::pair& t){ return t.first; }); return triggersIds; } std::vector KitCreator::GetInstrumentTriggersLocations(int i) const { const auto& trigs = parameters.instrumentParameters[i].triggersIdsAndLocations; std::vector triggersLocations(trigs.size()); std::transform(trigs.cbegin(), trigs.cend(), triggersLocations.begin(), [](const std::pair& t){ return Enums::ToString(t.second); }); return triggersLocations; } std::vector KitCreator::GetInstrumentSoundsTypes(int i) const { const auto& sounds = parameters.instrumentParameters[i].soundsInfo; std::vector soundsTypes(sounds.size()); std::transform(sounds.cbegin(), sounds.cend(), soundsTypes.begin(), [](const InstrumentSoundInfo& s) { return Enums::ToString(s.type); }); return soundsTypes; } std::vector KitCreator::GetInstrumentSoundsLocs(int i) const { const auto& sounds = parameters.instrumentParameters[i].soundsInfo; std::vector soundsLocs(sounds.size()); std::transform(sounds.cbegin(), sounds.cend(), soundsLocs.begin(), [](const InstrumentSoundInfo& s) { return s.soundLocation; }); return soundsLocs; } std::vector KitCreator::GetSoundTypes(const std::string& instrumentType) const { InstrumentType type = Enums::ToElement(instrumentType); std::vector sndTypes = InstrumentFactory::GetSoundsTypes(type); std::vector soundsTypes; std::transform(sndTypes.cbegin(), sndTypes.cend(), std::back_inserter(soundsTypes), [](const InstrumentSoundType& t) { return Enums::ToString(t); }); return soundsTypes; } std::vector KitCreator::GetTriggersLocations(const std::string& instrumentType) const { InstrumentType type = Enums::ToElement(instrumentType); std::vector trigsLocs = InstrumentFactory::GetTriggersTypes(type); std::vector triggersLocations; std::transform(trigsLocs.cbegin(), trigsLocs.cend(), std::back_inserter(triggersLocations), [](const TriggerLocation& l) { return Enums::ToString(l); }); return triggersLocations; } std::vector KitCreator::GetInstrumentsTypes() const { std::vector types = Enums::GetEnumVector(); std::vector instrumentTypes; std::transform(types.cbegin(), types.cend(), std::back_inserter(instrumentTypes), [](const InstrumentType& t) { return Enums::ToString(t); }); return instrumentTypes; } std::vector KitCreator::GetInstrumentsNames() const { const std::vector& instruments = this->parameters.instrumentParameters; std::vector instrumentsNames; std::transform(instruments.cbegin(), instruments.cend(), std::back_inserter(instrumentsNames),[](const InstrumentParameters& i) { return i.instrumentName; }); return instrumentsNames; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Kits/KitCreator.h000066400000000000000000000055051354641705500204640ustar00rootroot00000000000000/* * KitCreator.h * * Created on: 9 Nov 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_KITS_KITCREATOR_H_ #define SOURCE_DRUMKIT_KITS_KITCREATOR_H_ #include "../../Util/Enums.h" #include "../Triggers/TriggerManager.h" #include "KitParameters.h" #include "KitManager.h" #include #include namespace DrumKit { class KitCreator { public: explicit KitCreator(const std::string& dataLoc) noexcept; virtual ~KitCreator(); // Kit void CreateNewKit() noexcept; void CreateFromModel(const std::string& file); int GetNumInstruments() const noexcept { return (int)this->parameters.instrumentParameters.size(); } void SetKitName(const std::string& name) noexcept { parameters.kitName = name; }; void SaveKit(const std::string& file, bool fullPath = false) const; void SaveKit() const; // Instruments void CreateNewInstrument() noexcept; void RemoveInstrument(std::size_t i) noexcept; void RemoveLastInstrument() noexcept; void AddInstrumentToKit() noexcept; void SetInstrumentName(const std::string& name) { this->instrument.instrumentName = name; } void SetInstrumentType(const std::string& type); void SetInstrumentVolume(const float v) noexcept { this->instrument.volume = v; } void AddInstrumentSound(const std::string& file, const std::string& type); void AddInstrumentTrigger(const int id, const std::string& location); void SetInstrumentName(int id, const std::string& name) { this->parameters.instrumentParameters[id].instrumentName = name; } void SetInstrumentType(int id, const std::string& type) { this->parameters.instrumentParameters[id].instrumentType = Util::Enums::ToElement(type); } void SetInstrumentTriggersIdsAndLocs(int id, const std::vector>& trigsIdsAndLocs); void SetInstrumentSoundsTypesAndLocs(int id, const std::vector>& sndsTypesAndLocs); std::string GetInstrumentType(int i) const; std::vector GetInstrumentsTriggersIds(int i) const; std::vector GetInstrumentTriggersLocations(int i) const; std::vector GetInstrumentSoundsTypes(int i) const; std::vector GetInstrumentSoundsLocs(int i) const; // Enums // Instruments std::vector GetInstrumentsTypes() const; std::vector GetInstrumentsNames() const; // Triggers std::vector GetTriggersIds() const { return TriggerManager::LoadTriggersIds(dataFolder); } std::vector GetTriggersLocations(const std::string& instrumentType) const; // Sounds std::vector GetSoundTypes(const std::string& instrumentType) const; private: std::string dataFolder; std::string kitsDirectory; KitParameters parameters; InstrumentParameters instrument; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_KITS_KITCREATOR_H_ */ libeXaDrums-0.4.2/DrumKit/Kits/KitManager.cpp000066400000000000000000000146041354641705500207720ustar00rootroot00000000000000/* * KitsManager.cpp * * Created on: 8 Nov 2015 * Author: jeremy */ #include "KitManager.h" #include "../../Util/ErrorHandling.h" #include "../../Util/Enums.h" #include "../../Util/Xml.h" #include "../Instruments/InstrumentType.h" #include "../Instruments/InstrumentSoundInfo.h" #include "../Triggers/TriggerLocation.h" #include #include #include #include #include #include #include #if __has_include() #include namespace fs = std::filesystem; #else #include namespace fs = std::experimental::filesystem; #endif using namespace Sound; using namespace tinyxml2; using namespace Util; namespace DrumKit { KitManager::KitManager(const std::string& kitsPath) : kitsPath(kitsPath) { this->ScanFolder(); return; } KitManager::~KitManager() { return; } void KitManager::LoadKit(std::string file, KitParameters& parameters) { parameters.instrumentParameters.clear(); XMLDocument doc; if(doc.LoadFile(file.c_str()) != XML_SUCCESS) { throw Exception("Could not read the drum kit configuration file.", error_type_error); return; } XMLElement* root = doc.RootElement(); XMLElement* kitName = root->FirstChildElement("kitName"); parameters.kitName = kitName->GetText(); //parameters.kitFolder = kitFolder->GetText(); int instrumentId = 0; for(const auto& instrument : XmlElement{root, "Instrument"}) { InstrumentParameters instrumentParameters; instrumentParameters.instrumentName = instrument.FirstChildElement("instrumentName").GetText(); for(const auto& trigger : XmlElement{instrument.FirstChildElement("triggers")}) { int id = std::stoi(trigger.GetText()); TriggerLocation location = trigger.Attribute("location"); instrumentParameters.triggersIdsAndLocations.emplace_back(id, location); } int soundId = 0; for(const auto& sound : XmlElement{instrument.FirstChildElement("sounds")}) { InstrumentSoundInfo soundInfo; soundInfo.id = soundId; auto soundText = sound.GetText(); if(soundText != nullptr) { soundInfo.soundLocation = soundText; } else { throw Exception("Sound location is empty.", error_type_error); return; } sound.Attribute("type", soundInfo.type); instrumentParameters.soundsInfo.push_back(soundInfo); soundId++; } // Populate instrumentParameters instrument.Attribute("type", instrumentParameters.instrumentType); instrumentParameters.id = instrumentId; // Instrument volume std::string volumeStr = instrument.Attribute("volume"); instrumentParameters.volume = float(std::stoi(volumeStr)/100.0f); parameters.instrumentParameters.push_back(instrumentParameters); instrumentId++; } parameters.configFilePath = file; return; } void KitManager::SaveKit(std::string file, KitParameters parameters) { // Create document XMLDocument doc; // Add root element XMLElement* root = doc.NewElement("root"); doc.InsertFirstChild(root); // Create Elements XMLElement* kitName = doc.NewElement("kitName"); XMLElement* kitFolder = doc.NewElement("kitFolder"); // Add values and attributes to elements kitName->SetText(parameters.kitName.c_str()); //kitFolder->SetText(parameters.kitFolder.c_str()); // Add elements to document root->InsertEndChild(kitName); root->InsertEndChild(kitFolder); // Instruments for(InstrumentParameters const& instrumentParameters : parameters.instrumentParameters) { XMLElement* instrument = doc.NewElement("Instrument"); // Set type std::string instrumentType = Enums::ToString(instrumentParameters.instrumentType); instrument->SetAttribute("type", instrumentType.c_str()); // Set volume int volume = (int)std::floor(instrumentParameters.volume * 100.0f); instrument->SetAttribute("volume", volume); // Add Instrument name XMLElement* instrumentName = doc.NewElement("instrumentName"); instrumentName->SetText(instrumentParameters.instrumentName.c_str()); instrument->InsertEndChild(instrumentName); // Triggers XMLElement* triggers = doc.NewElement("triggers"); for(auto const& triggerLoc : instrumentParameters.triggersIdsAndLocations) { XMLElement* trigger = doc.NewElement("trigger"); // Set location std::string location = Enums::ToString(triggerLoc.second); trigger->SetAttribute("location", location.c_str()); // Set id trigger->SetText(triggerLoc.first); triggers->InsertEndChild(trigger); } instrument->InsertEndChild(triggers); // Sounds XMLElement* sounds = doc.NewElement("sounds"); for(InstrumentSoundInfo const& soundInfo : instrumentParameters.soundsInfo) { XMLElement* sound = doc.NewElement("sound"); // Set type std::string type = Enums::ToString(soundInfo.type); sound->SetAttribute("type", type.c_str()); // Set file path sound->SetText(soundInfo.soundLocation.c_str()); // Add sound sounds->InsertEndChild(sound); } instrument->InsertEndChild(sounds); // Insert in root root->InsertEndChild(instrument); } // Save file auto result = doc.SaveFile(file.c_str()); if(XML_SUCCESS != result) { throw Exception("Could not save drum kit parameters.", error_type_error); } return; } bool KitManager::DeleteKit(const int& id) { const std::string& filePath = filesPaths[id]; std::ifstream file(filePath.c_str()); if(file.good()) { unlink(filePath.c_str()); this->ScanFolder(); return true; } return false; } // PRIVATE METHODS void KitManager::ScanFolder() { this->filesPaths.clear(); for(const auto& p: fs::recursive_directory_iterator(kitsPath)) { if(p.path().extension() == ".xml") { this->filesPaths.push_back(p.path().string()); } } // Sort (had to be improved to take capital letters into account) std::sort(filesPaths.begin(), filesPaths.end(), [](const std::string& lhs, const std::string& rhs) { const auto result = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin(), [](const char& lhs, const char& rhs){return std::tolower(lhs) == std::tolower(rhs);}); return result.second != rhs.cend() && (result.first == lhs.cend() || std::tolower(*result.first) < std::tolower(*result.second)); }); //std::sort(this->filesPaths.begin(), this->filesPaths.end()); return; } // PRIVATE } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Kits/KitManager.h000066400000000000000000000020261354641705500204320ustar00rootroot00000000000000/* * KitsManager.h * * Created on: 8 Nov 2015 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_KITS_KITMANAGER_H_ #define SOURCE_DRUMKIT_KITS_KITMANAGER_H_ #include "KitParameters.h" #include "../../Sound/InstrumentSoundType.h" #include #include namespace DrumKit { class KitManager { public: explicit KitManager(const std::string& kitsPath); virtual ~KitManager(); static void LoadKit(std::string file, KitParameters& parameters); static void SaveKit(std::string file, KitParameters parameters); bool DeleteKit(const int& id); void ReScan() { ScanFolder(); } int GetNumKits() { return int(this->filesPaths.size()); } std::vector GetKitsLocations() const { return filesPaths; } private: static Sound::InstrumentSoundType GetSoundType(std::string type); static std::string GetSoundTypeStr(Sound::InstrumentSoundType soundType); void ScanFolder(); std::string kitsPath; std::vector filesPaths; }; } #endif /* SOURCE_DRUMKIT_KITS_KITMANAGER_H_ */ libeXaDrums-0.4.2/DrumKit/Kits/KitParameters.h000066400000000000000000000010671354641705500211670ustar00rootroot00000000000000/* * KitParameters.h * * Created on: 7 Feb 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_KITMANAGER_KITPARAMS_H_ #define SOURCE_DRUMKIT_KITMANAGER_KITPARAMS_H_ #include "../Instruments/InstrumentParameters.h" #include #include namespace DrumKit { struct KitParameters { KitParameters() noexcept : kitName(), configFilePath(), instrumentParameters() {} std::string kitName; std::string configFilePath; std::vector instrumentParameters; }; } #endif /* SOURCE_DRUMKIT_KITMANAGER_KITPARAMS_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/000077500000000000000000000000001354641705500171135ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Triggers/Curves/000077500000000000000000000000001354641705500203625ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Triggers/Curves/CurveType.h000066400000000000000000000027471354641705500224730ustar00rootroot00000000000000/* * Curves.h * * Created on: 2 Jun 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVE_H_ #define LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVE_H_ #include "../../../Util/Enums.h" #include #include #include namespace DrumKit { enum class CurveType { Linear, Exponential1, Exponential2, Log1, Log2, Loud1, Loud2, Spline, First = Linear, Last = Spline }; inline std::ostream& operator<<(std::ostream& o, const CurveType& x) { std::string os; switch (x) { case CurveType::Exponential1: os = "Exponential1";break; case CurveType::Linear: os = "Linear"; break; case CurveType::Exponential2: os = "Exponential2";break; case CurveType::Log1: os = "Log1"; break; case CurveType::Log2: os = "Log2"; break; case CurveType::Loud1: os = "Loud1"; break; case CurveType::Loud2: os = "Loud2"; break; case CurveType::Spline: os = "Spline"; break; default: break; } return o << os; } inline CurveType operator++(CurveType& x) { return x = (CurveType)(std::underlying_type_t(x) + 1); }; inline CurveType operator*(CurveType x) { return x; }; inline CurveType begin(CurveType x) { return CurveType::First; }; inline CurveType end(CurveType x) { CurveType l = CurveType::Last; return ++l; }; inline std::istream& operator>>(std::istream& is, CurveType& x) { return Util::StreamToEnum(is, x); } } #endif /* LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVE_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/Curves/Curves.h000066400000000000000000000103341354641705500220030ustar00rootroot00000000000000/* * Curves.h * * Created on: 2 Jun 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVES_H_ #define LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVES_H_ #include "../../../Util/Misc.h" #include "../../../Util/Enums.h" #include "CurveType.h" #include #include #include #include #include #include namespace DrumKit { template using curve_t = std::vector; class Curves { public: template static curve_t MakeCurve(CurveType t, size_t length) { curve_t curve; switch(t) { case CurveType::Linear: Linear(curve, length); break; case CurveType::Exponential1: Exp(curve, length); break; case CurveType::Exponential2: Exp2(curve, length); break; case CurveType::Log1: Log(curve, length); break; case CurveType::Log2: Log2(curve, length); break; case CurveType::Loud1: Loud1(curve, length); break; case CurveType::Loud2: Loud2(curve, length); break; case CurveType::Spline: Sigmoid(curve, length); break; default: Linear(curve, length); break; } return curve; } template static T Apply(const curve_t& curve, U val) { const auto index = std::min(val, curve.size()-1); return curve[index]; } template static void Linear(curve_t& curve, std::size_t length) { // Create a vector that contains values increasing from 0 to numSamples-1 std::vector linearVector(length); std::iota(linearVector.begin(), linearVector.end(), 0); // Normalise vector Normalize(linearVector); // Copy normalised vector into curve curve.swap(linearVector); return; } template static void GenerateNormalizedCurve(curve_t& curve, std::size_t length, F&& func) { // Get normalised linear vector std::vector normLin; Linear(normLin, length); // Create vector to contain the non-normalised cruve std::vector curveVector(normLin.size()); // Create non-normalised exponential vector std::transform(normLin.begin(), normLin.end(), curveVector.begin(), func); // Create normalised exponential vector Normalize(curveVector); // Copy generated vector into the curve vector curve.swap(curveVector); } template static void Exp(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return std::expm1(x); }); return; } template static void Exp2(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return std::expm1(x) * std::expm1(x); }); return; } template static void Log(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return std::log2(1 + x); }); return; } template static void Log2(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return std::log2(1 + x) * std::log2(1 + x); }); return; } template static void Loud1(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return .25 + .75 * x; }); return; } template static void Loud2(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return .75 + .25 * x; }); return; } template static void Sigmoid(curve_t& curve, std::size_t length) { GenerateNormalizedCurve(curve, length, [](auto x) { return 1. / ( 1. + std::exp(-12. * (x - .5))); }); return; } private: Curves(){}; virtual ~Curves(){}; template static void Normalize(std::vector& curve) { // Create empty vector to contain the normalised curve std::vector normalisedCurve(curve.size()); // Get maximum value of the vector auto max = *std::max_element(curve.begin(), curve.end()); // Normalise linear vector std::transform(curve.begin(), curve.end(), normalisedCurve.begin(), [&max](auto v) { return v/max; }); // Copy normalised curve to the curve vector curve.swap(normalisedCurve); return; } }; } #endif /* LIBEXADRUMS_SOURCE_DRUMKIT_CURVES_CURVES_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerFactory.h000066400000000000000000000016641354641705500222260ustar00rootroot00000000000000/* * TriggerFactory.h * * Created on: 18 Jun 2017 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERFACTORY_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERFACTORY_H_ #include "../../Util/ErrorHandling.h" #include "Triggers/DiscreteTrigger.h" #include "Triggers/ContinuousTrigger.h" namespace DrumKit { class TriggerFactory { public: static TriggerPtr CreateTrigger(const TriggerParameters& triggerParameters) { switch (triggerParameters.type) { case TriggerType::Discrete: return std::make_shared(triggerParameters); case TriggerType::Continuous: return std::make_shared(triggerParameters); default: Util::Exception("Unknown trigger type.", Util::error_type_error); return TriggerPtr(nullptr); } } private: TriggerFactory() = delete; ~TriggerFactory() = delete; }; } // namespace DrumKit #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERFACTORY_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerLocation.h000066400000000000000000000023041354641705500223570ustar00rootroot00000000000000/* * TriggerLocation.h * * Created on: 8 Mar 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERLOCATION_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERLOCATION_H_ #include #include #include namespace DrumKit { enum class TriggerLocation { DrumHead, Rim, First = DrumHead, Last = Rim }; inline std::ostream& operator<<(std::ostream& o, const TriggerLocation& x) { std::string os; switch (x) { case TriggerLocation::DrumHead: os = "DrumHead"; break; case TriggerLocation::Rim: os = "Rim"; break; default: break; } return o << os; } inline TriggerLocation operator++(TriggerLocation& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline TriggerLocation operator*(TriggerLocation i) { return i; }; inline TriggerLocation begin(TriggerLocation x) { return TriggerLocation::First; }; inline TriggerLocation end(TriggerLocation x) { TriggerLocation l = TriggerLocation::Last; return ++l; }; inline std::istream& operator>>(std::istream& is, TriggerLocation& x) { return Util::StreamToEnum(is, x); } } #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERLOCATION_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerManager.cpp000066400000000000000000000127251354641705500225240ustar00rootroot00000000000000/* * TriggerManager.cpp * * Created on: 3 Sep 2016 * Author: jeremy */ #include "TriggerManager.h" #include "../../Util/Enums.h" #include "../../Util/ErrorHandling.h" #include "../../Util/Xml.h" #include "Curves/CurveType.h" #include "TriggerLocation.h" #include #include #include using namespace tinyxml2; using namespace Util; namespace DrumKit { std::vector TriggerManager::LoadTriggersIds(const std::string& moduleDir) { // Set default sensors parameters IO::SensorsConfig sensorsConfig; sensorsConfig.resolution = 12; sensorsConfig.samplingRate = 1000000; sensorsConfig.sensorType = IO::SensorType::Hdd; sensorsConfig.hddDataFolder = ""; // Load triggers config with default sensor parameters std::vector trigsParams; LoadTriggersConfig(moduleDir, sensorsConfig, trigsParams); std::vector triggersIds(trigsParams.size()); std::transform(trigsParams.cbegin(), trigsParams.cend(), triggersIds.begin(), [&](const TriggerParameters& p) { return p.sensorId; }); return triggersIds; } void TriggerManager::LoadTriggersConfig(const std::string& moduleDir, const IO::SensorsConfig& sensorsConfig, std::vector& trigsParams) { trigsParams.clear(); const std::string file(moduleDir + "triggersConfig.xml"); XMLDocument doc; if(doc.LoadFile(file.data()) != XML_SUCCESS) { throw Exception("Could not load triggers configuration.", error_type_error); } XMLElement* root = doc.RootElement(); // Read all triggers for(const auto& trigger : XmlElement{root, "Trigger"}) { TriggerParameters trigParams; // Get trigger id trigger.Attribute("sensorId", trigParams.sensorId); // Get trigger type trigParams.type = trigger.Attribute("sensorType"); // Read xml elements trigger.FirstChildElement("Threshold").GetValue(trigParams.threshold); trigger.FirstChildElement("ScanTime").GetValue(trigParams.scanTime); trigger.FirstChildElement("MaskTime").GetValue(trigParams.maskTime); auto response = trigger.FirstChildElement("Response"); trigParams.response = response.GetValue(); // Sensors configuation trigParams.sensorConfig = sensorsConfig; trigsParams.push_back(trigParams); } return; } void TriggerManager::SaveTriggersConfig(const std::string& moduleDir, const std::vector& triggerParameters) { std::vector trigsParams = triggerParameters; std::sort(trigsParams.begin(), trigsParams.end(), [](const auto& t1, const auto& t2) { return t1.sensorId < t2.sensorId; }); std::string file(moduleDir + "triggersConfig.xml"); // Create document XMLDocument doc; // Add root element auto root = doc.NewElement("Triggers"); doc.InsertFirstChild(root); // Add triggers configurations for(const auto& trigger : trigsParams) { std::string sensorTypeStr = Enums::ToString(trigger.type); auto trig = CreateXmlElement(doc, "Trigger", "", {{"sensorType", sensorTypeStr}, {"sensorId", trigger.sensorId}}); trig->InsertEndChild(CreateXmlElement(doc, "Threshold", trigger.threshold)); trig->InsertEndChild(CreateXmlElement(doc, "ScanTime", trigger.scanTime)); trig->InsertEndChild(CreateXmlElement(doc, "MaskTime", trigger.maskTime)); trig->InsertEndChild(CreateXmlElement(doc, "Response", Enums::ToString(trigger.response))); root->InsertEndChild(trig); } // Save file auto result = doc.SaveFile(file.c_str()); if(XML_SUCCESS != result) { throw Exception("Could not save triggers configuration.", error_type_error); } return; } void TriggerManager::LoadSensorsConfig(const std::string& moduleDir, IO::SensorsConfig& sensorConfig) { std::string file(moduleDir + "sensorsConfig.xml"); XMLDocument doc; auto ret = doc.LoadFile(file.c_str()); if(ret != XML_SUCCESS) { throw Exception("Could not load sensors configuration.", error_type_error); } auto root = XmlElement{doc.RootElement()}; root.FirstChildElement("SamplingRate").GetValue(sensorConfig.samplingRate); root.FirstChildElement("Resolution").GetValue(sensorConfig.resolution); root.FirstChildElement("HddDataFolder").GetValue(sensorConfig.hddDataFolder); auto type = root.FirstChildElement("Type").GetValue(); sensorConfig.sensorType = Enums::ToElement(type); return; } void TriggerManager::SaveSensorsConfig(const std::string& moduleDir, IO::SensorsConfig& sensorConfig) { std::string file(moduleDir + "sensorsConfig.xml"); XMLDocument doc; // Add root element XMLElement* root = doc.NewElement("SensorsConfig"); doc.InsertFirstChild(root); // Create Elements XMLElement* samplingRate = doc.NewElement("SamplingRate"); XMLElement* resolution = doc.NewElement("Resolution"); XMLElement* type = doc.NewElement("Type"); XMLElement* dataFolder = doc.NewElement("HddDataFolder"); samplingRate->SetText(sensorConfig.samplingRate); resolution->SetText(sensorConfig.resolution); std::string typeStr = Enums::ToString(sensorConfig.sensorType); type->SetText(typeStr.c_str()); dataFolder->SetText(sensorConfig.hddDataFolder.c_str()); // Add elements to document root->InsertEndChild(samplingRate); root->InsertEndChild(resolution); root->InsertEndChild(type); root->InsertEndChild(dataFolder); auto result = doc.SaveFile(file.c_str()); if(XML_SUCCESS != result) { throw Exception("Could not save sensors configuration.", error_type_error); } return; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerManager.h000066400000000000000000000020651354641705500221650ustar00rootroot00000000000000/* * TriggerManager.h * * Created on: 3 Sep 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERMANAGER_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERMANAGER_H_ #include "../../IO/SensorType.h" #include "../../IO/SensorsConfig.h" #include "TriggerParameters.h" #include #include namespace DrumKit { class TriggerManager { public: static void LoadTriggersConfig(const std::string& moduleDir, const IO::SensorsConfig& sensorsConfig, std::vector& trigsParams); static void SaveTriggersConfig(const std::string& moduleDir, const std::vector& trigsParams); static std::vector LoadTriggersIds(const std::string& moduleDir); static void LoadSensorsConfig(const std::string& moduleDir, IO::SensorsConfig& sensorConfig); static void SaveSensorsConfig(const std::string& moduleDir, IO::SensorsConfig& sensorConfig); private: TriggerManager() = delete; virtual ~TriggerManager() = delete; }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERMANAGER_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerParameters.h000066400000000000000000000010441354641705500227120ustar00rootroot00000000000000/* * TriggerParameters.h * * Created on: 8 Nov 2015 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERPARAMETERS_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERPARAMETERS_H_ #include "../../IO/SensorsConfig.h" #include "Curves/CurveType.h" #include "TriggerType.h" namespace DrumKit { struct TriggerParameters { int sensorId; int scanTime; short threshold; int maskTime; TriggerType type; CurveType response; IO::SensorsConfig sensorConfig; }; } #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERPARAMETERS_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerState.h000066400000000000000000000005421354641705500216710ustar00rootroot00000000000000/* * TriggerState.h * * Created on: 6 Mar 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERSTATE_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERSTATE_H_ namespace DrumKit { struct TriggerState { int sensorId; float value; bool isTrig; int64_t trigTime; }; } #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERSTATE_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/TriggerType.h000066400000000000000000000022051354641705500215300ustar00rootroot00000000000000/* * TriggerType.h * * Created on: 6 Mar 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERTYPE_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERTYPE_H_ #include #include #include namespace DrumKit { enum class TriggerType { Discrete, Continuous, First = Discrete, Last = Continuous }; inline std::ostream& operator<<(std::ostream& o, const TriggerType& x) { std::string os; switch (x) { case TriggerType::Discrete: os = "Discrete"; break; case TriggerType::Continuous: os = "Continuous"; break; default: break; } return o << os; } inline TriggerType operator++(TriggerType& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline TriggerType operator*(TriggerType x) { return x; }; inline TriggerType begin(TriggerType x) { return TriggerType::First; }; inline TriggerType end(TriggerType x) { TriggerType l = TriggerType::Last; return ++l; }; inline std::istream& operator>>(std::istream& is, TriggerType& x) { return Util::StreamToEnum(is, x); } } #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERTYPE_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/000077500000000000000000000000001354641705500207015ustar00rootroot00000000000000libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/ContinuousTrigger.cpp000066400000000000000000000011071354641705500250760ustar00rootroot00000000000000/* * ContinuousTrigger.cpp * * Created on: 28 Oct 2016 * Author: jeremy */ #include "ContinuousTrigger.h" namespace DrumKit { ContinuousTrigger::ContinuousTrigger(const TriggerParameters& triggerParams) : Trigger(triggerParams) { return; } void ContinuousTrigger::Refresh() { // Save previous value //float previousValue = state.value; // Reset state value state.value = 0.0f; state.isTrig = false; // Read sensor date short value = this->GetSensorData(); state.value = value / numSamples / 2.0f; return; } } /* namespace DrumKit */ libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/ContinuousTrigger.h000066400000000000000000000011201354641705500245360ustar00rootroot00000000000000/* * ContinuousTrigger.h * * Created on: 28 Oct 2016 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_CONTINUOUSTRIGGER_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_CONTINUOUSTRIGGER_H_ #include "Trigger.h" #include "../TriggerParameters.h" namespace DrumKit { class ContinuousTrigger : public Trigger { public: explicit ContinuousTrigger(const TriggerParameters& triggerParams); ~ContinuousTrigger() = default; virtual void Refresh() final; private: }; } /* namespace DrumKit */ #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_CONTINUOUSTRIGGER_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/DiscreteTrigger.cpp000066400000000000000000000032211354641705500244710ustar00rootroot00000000000000/* * Conditioner.cpp * * Created on: 4 May 2015 * Author: jeremy */ #include "DiscreteTrigger.h" #include #include using namespace std::chrono; namespace DrumKit { DiscreteTrigger::DiscreteTrigger(const TriggerParameters& triggerParams) : Trigger(triggerParams) { return; } void DiscreteTrigger::Refresh() { // Reset state value state.value = 0.0f; state.isTrig = false; // Read sensor date short value = this->GetSensorData(); const auto parameters = this->GetParameters(); // Remove DC offset (high pass filter: y[n] = x[n] - x[n-1] + R * y[n-1]) filteredValue = value - prevValue + 0.99 * prevFilteredValue; // Update values prevValue = value; prevFilteredValue = filteredValue; velocity = std::abs(filteredValue); // Get current time high_resolution_clock::time_point t = high_resolution_clock::now(); int64_t dt = static_cast(duration(t - t0).count()); if(velocity > parameters.threshold) { if(!trig) { trigTime = dt; trig = true; } if(maxVelocity < velocity && dt < trigTime + parameters.scanTime) { maxVelocity = velocity; } if(sensor->IsDigital() || (dt > trigTime + parameters.scanTime && !out)) { out = true; // Update trigger state state.value = Curves::Apply(this->curves[static_cast(parameters.response)], maxVelocity); state.trigTime = static_cast(time_point_cast(t).time_since_epoch().count()); state.isTrig = true; } } if(trig && dt > trigTime + parameters.maskTime) { trig = false; maxVelocity = 0; out = false; } return; } } libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/DiscreteTrigger.h000066400000000000000000000012011354641705500241320ustar00rootroot00000000000000/* * Conditioner.h * * Created on: 4 May 2015 * Author: jeremy */ #ifndef RASPIDRUMS_SOURCE_DRUMKIT_TRIGGER_H_ #define RASPIDRUMS_SOURCE_DRUMKIT_TRIGGER_H_ #include "Trigger.h" #include "../TriggerParameters.h" namespace DrumKit { class DiscreteTrigger : public Trigger { public: explicit DiscreteTrigger(const TriggerParameters& triggerParams); ~DiscreteTrigger() = default; virtual void Refresh() final; //virtual bool Trig(short value, float& strength); //bool GetState() const { return trig; } private: //mutable std::mutex triggerMutex; }; } #endif /* RASPIDRUMS_SOURCE_DRUMKIT_TRIGGER_H_ */ libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/Trigger.cpp000066400000000000000000000036731354641705500230210ustar00rootroot00000000000000/* * Trigger.cpp * * Created on: 13 Dec 2015 * Author: jeremy */ #include "Trigger.h" #include "../../../IO/HddSensor.h" #include "../../../IO/SpiSensor.h" #include "../../../IO/VirtualSensor.h" #include #include #include #include using namespace std::chrono; using namespace Util; namespace DrumKit { Trigger::Trigger(TriggerParameters triggerParams) : trig(false), out(false), trigTime(0), velocity(0), maxVelocity(0), state(), triggerParameters(triggerParams) { t0 = high_resolution_clock::now(); numSamples = static_cast(std::pow(2.0f, triggerParams.sensorConfig.resolution) / 2.0f); //mean = numSamples; prevValue = 0; filteredValue = 0; prevFilteredValue = 0; // Default state values state.isTrig = false; state.sensorId = triggerParams.sensorId; state.value = 0.0f; const std::string dataFolder = triggerParams.sensorConfig.hddDataFolder; switch(triggerParams.sensorConfig.sensorType) { case IO::SensorType::Hdd: this->sensor = std::make_unique(dataFolder); break; case IO::SensorType::Spi: this->sensor = std::make_unique(); break; case IO::SensorType::Virtual: this->sensor = std::make_unique(); break; default: throw -1; break; } // Generate curves const auto curves_types = Enums::GetEnumVector(); curves.resize(curves_types.size()); std::transform(curves_types.cbegin(), curves_types.cend(), curves.begin(), [&](const auto& t) { return Curves::MakeCurve(t, numSamples);}); return; } short Trigger::GetSensorData() const { return sensor->GetData(triggerParameters.sensorId); } void Trigger::SetParameters(const TriggerParameters& params) { std::lock_guard lock(spin); triggerParameters = params; } TriggerParameters Trigger::GetParameters() const { std::lock_guard lock(spin); return triggerParameters; } } libeXaDrums-0.4.2/DrumKit/Triggers/Triggers/Trigger.h000066400000000000000000000031351354641705500224570ustar00rootroot00000000000000/* * ITrigger.h * * Created on: 9 Dec 2015 * Author: jeremy */ #ifndef SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_TRIGGER_H_ #define SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_TRIGGER_H_ #include "../Curves/Curves.h" #include "../../../IO/ISensor.h" #include "../../../Util/Threading.h" #include "../TriggerParameters.h" #include "../TriggerState.h" #include #include namespace DrumKit { class Trigger { public: explicit Trigger(TriggerParameters trigParams); //virtual bool Trig(short value, float& strength) = 0; virtual void Refresh() = 0; virtual void SetParameters(const TriggerParameters& params); virtual void SetSensorData(char channel, short data) { this->sensor->SetData(channel, data); } virtual int GetId() const { return this->triggerParameters.sensorId; }; virtual TriggerType GetType() const { return this->triggerParameters.type; } virtual TriggerState const& GetTriggerState() const { return state; } virtual TriggerParameters GetParameters() const; protected: virtual ~Trigger() = default; virtual short GetSensorData() const; std::chrono::high_resolution_clock::time_point t0; size_t numSamples; short prevValue; short filteredValue; short prevFilteredValue; bool trig; bool out; int64_t trigTime; short velocity; short maxVelocity; TriggerState state; std::vector> curves; std::unique_ptr sensor; private: mutable Util::SpinLock spin; TriggerParameters triggerParameters; }; typedef std::shared_ptr TriggerPtr; } #endif /* SOURCE_DRUMKIT_TRIGGERS_TRIGGERS_TRIGGER_H_ */ libeXaDrums-0.4.2/IO/000077500000000000000000000000001354641705500142555ustar00rootroot00000000000000libeXaDrums-0.4.2/IO/HddSensor.cpp000066400000000000000000000021761354641705500166600ustar00rootroot00000000000000/* * Sensor.cpp * * Created on: 7 May 2015 * Author: jeremy */ #include "HddSensor.h" #include #include #include namespace IO { const std::vector HddSensor::dataFiles({"out.raw", "out.raw", "out.raw"}); HddSensor::HddSensor(const std::string& dataFolder) : path(dataFolder), index(0) { return; } HddSensor::~HddSensor() { return; } short HddSensor::GetData(char channel) { if(data.empty()) { ReadData(channel); } // Wait for a few microseconds { clock_t endwait = clock() + (5.0f * (double)CLOCKS_PER_SEC) / 1000000.0f ; while (clock() < endwait); } short val = data[++index]; if(index == data.size()) { index = 0; } return val; } // Private Methods void HddSensor::ReadData(char channel) { std::string fileName = dataFiles[channel % dataFiles.size()]; std::string fileLoc(path + fileName); std::ifstream file(fileLoc, std::ifstream::binary); if(!file.good()) { throw - 1; } short val; while(file.read((char*)&val, sizeof(short))) { data.push_back(val); } file.close(); return; } } libeXaDrums-0.4.2/IO/HddSensor.h000066400000000000000000000012541354641705500163210ustar00rootroot00000000000000/* * Sensor.h * * Created on: 7 May 2015 * Author: jeremy */ #ifndef RASPIDRUMS_SOURCE_IO_HDDSENSOR_H_ #define RASPIDRUMS_SOURCE_IO_HDDSENSOR_H_ #include "ISensor.h" #include #include namespace IO { class HddSensor : public ISensor { public: explicit HddSensor(const std::string& filePath); virtual ~HddSensor(); virtual short GetData(char channel) final; virtual void SetData(char channel, short value) final {} private: static const std::vector dataFiles; void ReadData(char channel); std::string path; std::vector data; unsigned int index; }; } #endif /* RASPIDRUMS_SOURCE_IO_HDDSENSOR_H_ */ libeXaDrums-0.4.2/IO/ISensor.h000066400000000000000000000007601354641705500160130ustar00rootroot00000000000000/* * Sensor.h * * Created on: 25 Oct 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_IO_ISENSOR_H_ #define LIBEXADRUMS_SOURCE_IO_ISENSOR_H_ namespace IO { class ISensor { public: virtual short GetData(char channel) = 0; virtual void SetData(char channel, short value) = 0; virtual bool IsDigital() const { return is_digital; } virtual ~ISensor() {}; protected: bool is_digital{false}; }; } /* namespace IO */ #endif /* LIBEXADRUMS_SOURCE_IO_ISENSOR_H_ */ libeXaDrums-0.4.2/IO/SensorType.h000066400000000000000000000021231354641705500165370ustar00rootroot00000000000000/* * SensorType.h * * Created on: 28 Oct 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_IO_SENSORTYPE_H_ #define LIBEXADRUMS_SOURCE_IO_SENSORTYPE_H_ #include #include #include namespace IO { enum class SensorType { Virtual, Spi, UsbSerial, Hdd, First = Virtual, Last = Hdd }; inline std::ostream& operator<<(std::ostream& o, const SensorType& x) { std::string os; switch (x) { case SensorType::Virtual: os = "Virtual"; break; case SensorType::Spi: os = "Spi"; break; case SensorType::UsbSerial: os = "UsbSerial"; break; case SensorType::Hdd: os = "Hdd"; break; default: break; } return o << os; } inline SensorType operator++(SensorType& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline SensorType operator*(SensorType x) { return x; }; inline SensorType begin(SensorType x) { return SensorType::First; }; inline SensorType end(SensorType x) { SensorType l = SensorType::Last; return ++l; }; } #endif /* LIBEXADRUMS_SOURCE_IO_SENSORTYPE_H_ */ libeXaDrums-0.4.2/IO/SensorsConfig.h000066400000000000000000000006001354641705500172040ustar00rootroot00000000000000/* * SensorsConfig.h * * Created on: 21 Feb 2017 * Author: jeremy */ #ifndef SOURCE_IO_SENSORSCONFIG_H_ #define SOURCE_IO_SENSORSCONFIG_H_ #include "SensorType.h" #include namespace IO { struct SensorsConfig { int samplingRate; int resolution; SensorType sensorType; std::string hddDataFolder; }; } #endif /* SOURCE_IO_SENSORSCONFIG_H_ */ libeXaDrums-0.4.2/IO/Serial.cpp000066400000000000000000000046421354641705500162060ustar00rootroot00000000000000/* * Serial.cpp * * Created on: 13 Sep 2015 * Author: jeremy */ #include "Serial.h" #include // Standard input / output functions #include #include // String function definitions #include // UNIX standard function definitions #include // File control definitions #include // Error number definitions #include // POSIX terminal control definitions namespace IO { Serial::Serial() : isOpen(false), baudRate(230400), port("/dev/ttyUSB0"), handle(), buf() { this->Open(); return; } Serial::~Serial() { if(isOpen) this->Close(); return; } short Serial::GetData(char port) { if(::write(this->handle, &port, 1) == 1) { auto res = ::read(this->handle, &this->buf, 1); if(res != -1) { if(this->buf == 's') { auto resValue = ::read(this->handle, &this->buf, 1); if(resValue < 0) { return 0; } } } } else return 0; return short(this->buf); } // PRIVATE void Serial::Open() { this->handle = ::open(this->port.c_str(), O_RDWR| O_NOCTTY); this->isOpen = true; this->Configure(); return; } void Serial::Close() { if(this->handle) ::close(this->handle); this->isOpen = false; return; } void Serial::Configure() { if(!isOpen) return; struct termios tty; struct termios tty_old; memset(&tty, 0, sizeof tty); /* Error Handling */ if(tcgetattr(this->handle, &tty) != 0 ) { //std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl; } /* Save old tty parameters */ tty_old = tty; /* Set Baud Rate */ cfsetospeed (&tty, (speed_t)B230400); cfsetispeed (&tty, (speed_t)B230400); /* Setting other Port Stuff */ tty.c_cflag &= ~PARENB; // Make 8n1 tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; tty.c_cflag &= ~CRTSCTS; // no flow control tty.c_cc[VMIN] = 1; // read doesn't block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines /* Make raw */ cfmakeraw(&tty); /* Flush Port, then applies attributes */ tcflush(this->handle, TCIFLUSH); if(tcsetattr (this->handle, TCSANOW, &tty) != 0) { //std::cout << "Error " << errno << " from tcsetattr" << std::endl; } return; } } libeXaDrums-0.4.2/IO/Serial.h000066400000000000000000000012611354641705500156450ustar00rootroot00000000000000/* * Serial.h * * Created on: 13 Sep 2015 * Author: jeremy */ #ifndef LIBEXADRUMS_SOURCE_IO_SERIAL_H_ #define LIBEXADRUMS_SOURCE_IO_SERIAL_H_ #include "ISensor.h" #include namespace IO { class Serial : public ISensor { public: Serial(); virtual ~Serial(); short GetData(char port); virtual void SetData(char channel, short value) final {} private: void Configure(); void Open(); void Close(); bool isOpen; //const unsigned int defaultBaudRate = 230400; //const std::string defaultPort = "/dev/ttyUSB0"; unsigned int baudRate; std::string port; int handle; char buf; }; } #endif /* LIBEXADRUMS_SOURCE_IO_SERIAL_H_ */ libeXaDrums-0.4.2/IO/Spi.cpp000066400000000000000000000022071354641705500155150ustar00rootroot00000000000000/* * Spi.cpp * * Created on: 2 May 2017 * Author: jeremy */ #include "Spi.h" #include #include #include namespace IO { const std::string Spi::spiDev0 = "/dev/spidev0.0"; const uint8_t Spi::bitsPerWord = 8; const uint16_t Spi::delay = 0; void Spi::Open(int freq, int mode) noexcept { this->clkFreq = freq; this->fd = open(Spi::spiDev0.c_str(), O_RDWR); mode &= 3; ioctl(this->fd, SPI_IOC_WR_MODE, &mode); ioctl(this->fd, SPI_IOC_WR_BITS_PER_WORD, &Spi::bitsPerWord); ioctl(this->fd, SPI_IOC_WR_MAX_SPEED_HZ, &this->clkFreq); return; } void Spi::Close() noexcept { if(fd != -1) { close(this->fd); fd = -1; } return; } int Spi::dataRW(unsigned char* data, int len) { struct spi_ioc_transfer spiData{}; spiData.tx_buf = (unsigned long)data; spiData.rx_buf = (unsigned long)data; spiData.len = len ; spiData.speed_hz = this->clkFreq; spiData.delay_usecs = 0; spiData.bits_per_word = Spi::bitsPerWord; spiData.cs_change = 0; spiData.pad = 0; return ioctl(this->fd, SPI_IOC_MESSAGE(1), &spiData); } } /* namespace IO */ libeXaDrums-0.4.2/IO/Spi.h000066400000000000000000000013421354641705500151610ustar00rootroot00000000000000/* * Spi.h * * Created on: 2 May 2017 * Author: jeremy */ #ifndef SOURCE_IO_SPI_H_ #define SOURCE_IO_SPI_H_ #include #include namespace IO { class Spi { public: static Spi& get() { static Spi instance; return instance; } void Open(int speed, int mode) noexcept; void Close() noexcept; int dataRW(unsigned char* data, int len); private: Spi(Spi const&) = delete; void operator=(Spi const&) = delete; Spi() : clkFreq(1000000), fd(-1) {} static const std::string spiDev0; static const uint8_t bitsPerWord; static const uint16_t delay; unsigned int clkFreq; int fd; }; } /* namespace IO */ #endif /* SOURCE_IO_SPI_H_ */ libeXaDrums-0.4.2/IO/SpiSensor.cpp000066400000000000000000000030561354641705500167120ustar00rootroot00000000000000/* * Accelerometer.cpp * * Created on: 25 May 2015 * Author: jeremy */ #include "SpiSensor.h" #include "Spi.h" //#include namespace IO { // Initilize number of instances //std::size_t SpiSensor::numInstances = 0; SpiSensor::SpiSensor() { /*if(numInstances == 0) { if (!bcm2835_init()) { //std::cout << "Could not initialise bcm2835" << std::endl; return ; } // Bcm2835 configuration { bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // The default bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // The default bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_128); // bcm2835_spi_chipSelect(BCM2835_SPI_CS0); // The default bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default } } numInstances++; */ return; } SpiSensor::~SpiSensor() { /*numInstances--; if(numInstances == 0) { // End Spi transfer bcm2835_spi_end(); // Close bcm2835 library bcm2835_close(); }*/ return; } short SpiSensor::GetData(char channel) { // Select SPI channel unsigned char data = 0b11000000 | (channel << 3); unsigned char mosi[3] = {data}; //char miso[3] = {0}; // Receive data //bcm2835_spi_transfernb(mosi, miso, 3); Spi::get().dataRW(mosi, 3); // Calculate value from received bits //short value = ((miso[0] & 0x01) << 11) | (miso[1] << 3) | ((miso[2] >> 5) & 0x07); short value = ((mosi[0] & 0x01) << 11) | (mosi[1] << 3) | ((mosi[2] >> 5) & 0x07); return value; } } libeXaDrums-0.4.2/IO/SpiSensor.h000066400000000000000000000007661354641705500163640ustar00rootroot00000000000000/* * Accelerometer.h * * Created on: 25 May 2015 * Author: jeremy */ #ifndef RASPIDRUMS_SOURCE_IO_SENSOR_H_ #define RASPIDRUMS_SOURCE_IO_SENSOR_H_ #include "ISensor.h" #include namespace IO { class SpiSensor : public ISensor { public: SpiSensor(); virtual ~SpiSensor(); short GetData(char channel); virtual void SetData(char channel, short value) final {} private: //static std::size_t numInstances; }; } #endif /* RASPIDRUMS_SOURCE_IO_SENSOR_H_ */ libeXaDrums-0.4.2/IO/VirtualSensor.h000066400000000000000000000011531354641705500172460ustar00rootroot00000000000000/* * ExternalSensor.h * * Created on: 6 Jan 2019 * Author: jeremy */ #ifndef IO_VIRTUALSENSOR_H_ #define IO_VIRTUALSENSOR_H_ #include "ISensor.h" #include namespace IO { class VirtualSensor : public ISensor { public: VirtualSensor() { is_digital = true; } virtual ~VirtualSensor() {} virtual short GetData(char channel) final { return data.exchange(0, std::memory_order_acquire); } virtual void SetData(char channel, short value) final { data.store(value, std::memory_order_release); } private: std::atomic data{}; }; } #endif /* IO_VIRTUALSENSOR_H_ */ libeXaDrums-0.4.2/LICENSE000066400000000000000000000027541354641705500147630ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2015-2019, Jeremy Oden All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libeXaDrums-0.4.2/Makefile.am000066400000000000000000000112741354641705500160070ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in # Copyright (C) 2018-2019 Jérémy Oden # Copyright (C) 2018-2019 Nicolas Boulenguez # Cache shared with autoconf. ACLOCAL_AMFLAGS = -I m4 PACKAGE = libexadrums # https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info exadrums_libtool_version_info = 0:0:0 # Distribute (in the tarball created by 'make dist-gzip'). EXTRA_DIST = LICENSE # Distribute and install into docdir. dist_doc_DATA = README.md # Install into pkgconfigdir, but do not distribute. pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = exadrums.pc # Good habits. AM_CXXFLAGS = -Wall AM_LDFLAGS = \ -Wl,--as-needed \ -Wl,--no-allow-shlib-undefined \ -Wl,--no-copy-dt-needed-entries \ -Wl,--no-undefined # Delegate library handling to libtool. lib_LTLIBRARIES = libexadrums.la libexadrums_la_CXXFLAGS = $(AM_CXXFLAGS) \ -pthread \ -std=c++17 $(alsa_CFLAGS) $(tinyxml2_CFLAGS) libexadrums_la_LDFLAGS = $(AM_LDFLAGS) \ -pthread \ -version-info $(exadrums_libtool_version_info) # The -pthread compiler and linker option links with libpthread, but # also selects various architecture-dependent settings. libexadrums_la_LIBADD = $(alsa_LIBS) $(tinyxml2_LIBS) -lpthread -lstdc++fs -latomic # The standard C++ library does not include libatomic on some # architectures (armel mips mipsel). It does not hurt to always list # it here, it will only be effective when used thanks to --as-needed. # Distribute and embed into the library. libexadrums_la_SOURCES = \ Api/Config/Config_api.cpp \ Api/Config/TriggerParameters_api.cpp \ Api/KitCreator/KitCreator_api.cpp \ Api/eXaDrums.cpp \ DrumKit/DrumModule/Module.cpp \ DrumKit/DrumModule/Module.h \ DrumKit/DrumModule/Recorder.cpp \ DrumKit/DrumModule/Recorder.h \ DrumKit/DrumModule/TrigSound.h \ DrumKit/Instruments/Cymbals/TestHiHat.cpp \ DrumKit/Instruments/Cymbals/TestHiHat.h \ DrumKit/Instruments/Drums/TestDrum.cpp \ DrumKit/Instruments/Drums/TestDrum.h \ DrumKit/Instruments/Instrument.cpp \ DrumKit/Instruments/Instrument.h \ DrumKit/Instruments/InstrumentFactory.h \ DrumKit/Instruments/InstrumentParameters.h \ DrumKit/Instruments/InstrumentSoundInfo.h \ DrumKit/Instruments/InstrumentType.h \ DrumKit/Instruments/Pads/Pad.cpp \ DrumKit/Instruments/Pads/Pad.h \ DrumKit/Kits/Kit.cpp \ DrumKit/Kits/Kit.h \ DrumKit/Kits/KitCreator.cpp \ DrumKit/Kits/KitManager.cpp \ DrumKit/Triggers/Curves/Curves.h \ DrumKit/Triggers/TriggerFactory.h \ DrumKit/Triggers/TriggerManager.cpp \ DrumKit/Triggers/TriggerState.h \ DrumKit/Triggers/Triggers/ContinuousTrigger.cpp \ DrumKit/Triggers/Triggers/ContinuousTrigger.h \ DrumKit/Triggers/Triggers/DiscreteTrigger.cpp \ DrumKit/Triggers/Triggers/DiscreteTrigger.h \ DrumKit/Triggers/Triggers/Trigger.cpp \ DrumKit/Triggers/Triggers/Trigger.h \ IO/HddSensor.cpp \ IO/HddSensor.h \ IO/ISensor.h \ IO/Serial.cpp \ IO/Serial.h \ IO/Spi.cpp \ IO/Spi.h \ IO/SpiSensor.cpp \ IO/SpiSensor.h \ IO/VirtualSensor.h \ Metronome/ClickTypes.h \ Metronome/Metronome.cpp \ Metronome/Metronome.h \ Metronome/MetronomeParameters.h \ Sound/Alsa/Alsa.cpp \ Sound/Alsa/Alsa.h \ Sound/Alsa/AlsaParameters.cpp \ Sound/Alsa/AlsaParameters.h \ Sound/Mixer/Mixer.cpp \ Sound/Mixer/Mixer.h \ Sound/Sound.cpp \ Sound/Sound.h \ Sound/SoundBank/SoundBank.cpp \ Sound/SoundBank/SoundBank.h \ Sound/SoundProcessor/SoundProcessor.cpp \ Sound/SoundProcessor/SoundProcessor.h \ Sound/SoundState.h \ Sound/Util/WavUtil.h \ Util/Crypt.h \ Util/ErrorHandling.h \ Util/Misc.h \ Util/Parsing.h \ Util/SimpleSafeQueue.h \ Util/Threading.h \ Util/Time.h # Install into pkgincludedir, but do not distribute (it is generated # by configure.ac). nobase_nodist_pkginclude_HEADERS = \ Api/Version.h # Distribute and install into pkgincludedir. nobase_pkginclude_HEADERS = \ Api/Config/AlsaParams_api.h \ Api/Config/Config_api.h \ Api/Config/Config_api.hpp \ Api/Config/TriggerParameters_api.h \ Api/KitCreator/KitCreator_api.h \ Api/KitCreator/KitCreator_api.hpp \ Api/eXaDrums.h \ Api/eXaDrums.hpp \ DrumKit/Instruments/InstrumentParameters.h \ DrumKit/Instruments/InstrumentSoundInfo.h \ DrumKit/Instruments/InstrumentType.h \ DrumKit/Kits/KitCreator.h \ DrumKit/Kits/KitManager.h \ DrumKit/Kits/KitParameters.h \ DrumKit/Triggers/Curves/CurveType.h \ DrumKit/Triggers/TriggerLocation.h \ DrumKit/Triggers/TriggerManager.h \ DrumKit/Triggers/TriggerParameters.h \ DrumKit/Triggers/TriggerType.h \ IO/SensorType.h \ IO/SensorsConfig.h \ Sound/Alsa/AlsaParams.h \ Sound/InstrumentSoundType.h \ Util/Enums.h \ Util/ErrorHandling.h \ Util/Xml.h libeXaDrums-0.4.2/Metronome/000077500000000000000000000000001354641705500157135ustar00rootroot00000000000000libeXaDrums-0.4.2/Metronome/ClickTypes.h000066400000000000000000000016751354641705500201470ustar00rootroot00000000000000/* * clickTypes.h * * Created on: 28 Sep 2016 * Author: jeremy */ #ifndef SOURCE_METRONOME_CLICKTYPES_H_ #define SOURCE_METRONOME_CLICKTYPES_H_ #include #include #include namespace DrumKit { enum class ClickType { Sine, Square, First = Sine, Last = Square }; inline std::ostream& operator<<(std::ostream& o, const ClickType& x) { std::string os; switch (x) { case ClickType::Sine: os = "Sine"; break; case ClickType::Square: os = "Square"; break; default: break; } return o << os; } inline ClickType operator++(ClickType& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline ClickType operator*(ClickType c) { return c; }; inline ClickType begin(ClickType x) { return ClickType::First; }; inline ClickType end(ClickType x) { ClickType l = ClickType::Last; return ++l; }; } #endif /* SOURCE_METRONOME_CLICKTYPES_H_ */ libeXaDrums-0.4.2/Metronome/Metronome.cpp000066400000000000000000000142351354641705500203710ustar00rootroot00000000000000/* * Metronome.cpp * * Created on: 28 Aug 2016 * Author: jeremy */ #include "Metronome.h" #include "../Util/Enums.h" #include "../Util/ErrorHandling.h" #include #include #include #define _USE_MATH_DEFINES using namespace Sound; using namespace tinyxml2; using namespace Util; namespace DrumKit { Metronome::Metronome(AlsaParams alsaParams) noexcept : Metronome(alsaParams, MetronomeParameters()) { return; } Metronome::Metronome(AlsaParams alsaParams, MetronomeParameters params) noexcept : alsaParameters(alsaParams), parameters(params) { bpmeasList = std::vector{1, 2, 3, 4, 5, 6, 7, 8}; rhythmList = std::vector{1, 2, 4}; return; } Metronome::~Metronome() { return; } void Metronome::GenerateClick() noexcept { switch (this->parameters.clickType) { case ClickType::Sine: GenerateSine(); break; case ClickType::Square: GenerateSquare(); break; default: GenerateSine(); break; } return; } void Metronome::SetTempo(int t) { parameters.tempo = std::min(std::max(t, 40), 250); return; } void Metronome::LoadConfig(const std::string& filePath, MetronomeParameters& params) { XMLDocument doc; if(doc.LoadFile(filePath.c_str()) != XML_SUCCESS) { throw Exception("Could not load metronome configuration.", error_type_error); } // Get elements XMLElement* root = doc.RootElement(); XMLElement* tempo = root->FirstChildElement("Tempo"); XMLElement* rhythm = root->FirstChildElement("Rhythm"); XMLElement* beatsPerMeasure = root->FirstChildElement("BeatsPerMeasure"); XMLElement* clickType = root->FirstChildElement("ClickType"); // Get values params.tempo = std::atoi(tempo->GetText()); params.rhythm = std::atoi(rhythm->GetText()); params.beatsPerMeasure = std::atoi(beatsPerMeasure->GetText()); params.clickType = Enums::ToElement(clickType->GetText()); return; } void Metronome::SaveConfig(const std::string& filePath, const MetronomeParameters& params) { // Create document XMLDocument doc; // Add root element XMLElement* root = doc.NewElement("Metronome"); doc.InsertFirstChild(root); // Create elements XMLElement* tempo = doc.NewElement("Tempo"); XMLElement* rhythm = doc.NewElement("Rhythm"); XMLElement* beatsPerMeasure = doc.NewElement("BeatsPerMeasure"); XMLElement* clickType = doc.NewElement("ClickType"); // Add values and elements to document tempo->SetText(params.tempo); rhythm->SetText(params.rhythm); beatsPerMeasure->SetText(params.beatsPerMeasure); clickType->SetText(Enums::ToString(params.clickType).c_str()); // Add elements to document root->InsertEndChild(tempo); root->InsertEndChild(rhythm); root->InsertEndChild(beatsPerMeasure); root->InsertEndChild(clickType); // Save file auto err = doc.SaveFile(filePath.c_str()); if(err != XML_SUCCESS) { throw Exception("Could not save metronome configuration.", error_type_error); } return; } // Private Methods int Metronome::GetNumSamples() const { // Calculate number of samples to generate the measure float beatsPerSecond = parameters.rhythm * float(parameters.tempo) / 60.0f; float measureTime = parameters.beatsPerMeasure / beatsPerSecond; int numSamples = alsaParameters.nChannels * alsaParameters.sampleRate * measureTime; return numSamples; } int Metronome::GetBeatsRate() const { // Get number of samples between each click float beatsPerSecond = parameters.rhythm * float(parameters.tempo) / 60.0f; float beatsFreq = alsaParameters.nChannels/beatsPerSecond; int beatsRate = std::floor(alsaParameters.sampleRate*beatsFreq); return beatsRate; } void Metronome::GenerateSquare() { const int numSamples = GetNumSamples(); data.clear(); data.resize(numSamples); // Get number of samples between each click const int beatsRate = GetBeatsRate(); // Sinusoid parameters float fSineHz = 880.0f; float radiansPerSample = fSineHz * 2*M_PI / alsaParameters.sampleRate / alsaParameters.nChannels; float clickDuration = alsaParameters.nChannels * 10.0f/1000.0f; std::size_t clickSamples = std::floor(alsaParameters.sampleRate*clickDuration); int n = 0; int mul = 1; double phase = 0; short amplitude = std::numeric_limits::max(); for(std::size_t i = 0; i < data.size(); i++) { std::size_t click = n * beatsRate;// + correction; if(i > click && i < click + clickSamples) { if(n % parameters.beatsPerMeasure == 0) { mul = 2; } else { mul = 1; } phase += mul*radiansPerSample; data[i] = (short)(float(amplitude) * (std::sin(phase) > 0)); } else // No click, so signal is zero { data[i] = 0; phase = 0; if(i == click + clickSamples) { n++; } } } return; } void Metronome::GenerateSine() { const int numSamples = GetNumSamples(); data.clear(); data.resize(numSamples); // Get number of samples between each click const int beatsRate = GetBeatsRate(); // Sinusoid parameters float fSineHz = 880.0f; float radiansPerSample = fSineHz * 2*M_PI / alsaParameters.sampleRate / alsaParameters.nChannels; float clickDuration = alsaParameters.nChannels * 10.0f/1000.0f; std::size_t clickSamples = std::floor(alsaParameters.sampleRate*clickDuration); int n = 0; int mul = 1; double phase = 0; short amplitude = std::numeric_limits::max(); for(std::size_t i = 0; i < data.size(); i++) { std::size_t click = n * beatsRate;// + correction; if(i > click && i < click + clickSamples) { if(n % parameters.beatsPerMeasure == 0) { mul = 2; } else { mul = 1; } phase += mul*radiansPerSample; data[i] = (short)(float(amplitude) * std::sin(phase)); } else // No click, so signal is zero { data[i] = 0; phase = 0; if(i == click + clickSamples) { n++; } } } return; } } /* namespace DrumKit */ libeXaDrums-0.4.2/Metronome/Metronome.h000066400000000000000000000036611354641705500200370ustar00rootroot00000000000000/* * Metronome.h * * Created on: 28 Aug 2016 * Author: jeremy */ #ifndef SOURCE_METRONOME_METRONOME_H_ #define SOURCE_METRONOME_METRONOME_H_ #include "../Sound/Alsa/AlsaParams.h" #include "ClickTypes.h" #include "MetronomeParameters.h" #include #include namespace DrumKit { class Metronome { public: explicit Metronome(Sound::AlsaParams alsaParams) noexcept; Metronome(Sound::AlsaParams alsaParams, MetronomeParameters params) noexcept; virtual ~Metronome(); void GenerateClick() noexcept; void SetParameters(const MetronomeParameters& params) { parameters = params; } void SetClickType(const ClickType& type) { parameters.clickType = type; } void SetRhythm(int rhythm) noexcept { parameters.rhythm = rhythm; } void SetBpmeas(int bpmeas) noexcept { parameters.beatsPerMeasure = bpmeas; } void SetTempo(int tempo); MetronomeParameters GetParameters() const { return parameters; } ClickType GetClickType() const noexcept { return parameters.clickType; } int GetTempo() const noexcept { return parameters.tempo; } int GetRhythm() const noexcept { return parameters.rhythm; } int GetBpmeas() const noexcept { return parameters.beatsPerMeasure; } std::vector GetRhythmList() const { return rhythmList; } std::vector GetBpmeasList() const { return bpmeasList; } std::vector GetData() const noexcept { return data; } static void LoadConfig(const std::string& filePath, MetronomeParameters& params); static void SaveConfig(const std::string& filePath, const MetronomeParameters& params); private: void GenerateSine(); void GenerateSquare(); int GetNumSamples() const; int GetBeatsRate() const; Sound::AlsaParams alsaParameters; // Metronome parameters MetronomeParameters parameters; std::vector bpmeasList; std::vector rhythmList; std::vector data; }; } /* namespace DrumKit */ #endif /* SOURCE_METRONOME_METRONOME_H_ */ libeXaDrums-0.4.2/Metronome/MetronomeParameters.h000066400000000000000000000007651354641705500220650ustar00rootroot00000000000000/* * MetronomeParameters.h * * Created on: 5 Oct 2016 * Author: jeremy */ #ifndef SOURCE_METRONOME_METRONOMEPARAMETERS_H_ #define SOURCE_METRONOME_METRONOMEPARAMETERS_H_ #include "ClickTypes.h" namespace DrumKit { struct MetronomeParameters { MetronomeParameters() : tempo(120), rhythm(2), beatsPerMeasure(4), clickType(ClickType::First) {}; int tempo; int rhythm; int beatsPerMeasure; ClickType clickType; }; } #endif /* SOURCE_METRONOME_METRONOMEPARAMETERS_H_ */ libeXaDrums-0.4.2/README.md000066400000000000000000000054761354641705500152410ustar00rootroot00000000000000# libeXaDrums [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6fd320220fc24258a77b70ac716e4ee1)](https://app.codacy.com/app/SpintroniK/libeXaDrums?utm_source=github.com&utm_medium=referral&utm_content=SpintroniK/libeXaDrums&utm_campaign=Badge_Grade_Dashboard) ExaDrums is a software drum module that allows drummers play with custom-made drum kits. This C++ library provides the most common features of a drum module. Its associated graphical user interface can be found in a separate repository: Each drum kit is made of instruments that can be individually controlled. A built-in metronome can be combined with a rhythm coach to make practice sessions easier and efficient. The drum triggers can be adjusted so that their response feels as natural as possible, and different sensor interfaces include external sensors. Although eXaDrums is usable as a drum module, it is still a young project. As such, some features are not yet implemented or are still experimental. ## Table of content - [Installation and Configuration](#installation) - [Dependencies](#dependencies) - [Install](#install) - [Configuration](#configuration) - [Usage](#usage) ## Installation ### Dependencies libeXaDrums depends on Alsa and TinyXml2. You can install those two libraries using this command line: ```shell sudo apt install libasound2-dev libtinyxml2-dev ``` LibeXaDrums also depends on build-essential, autotools and pkg-config in order to build and install the binaries: ```shell sudo apt install autoconf automake libtool build-essential pkg-config ``` If you wish to build the Debian packages (which is the recommended way to install the library), you will need to install debhelper: ```shell sudo apt install debhelper ``` You will also need to install git, so that you can clone this repository: ```shell sudo apt install git git clone https://github.com/SpintroniK/libeXaDrums.git ``` ### Building libeXaDrums Now that you have all dependencies, you can build the Debian packages. Make sure you have dehelper installed, and then checkout the debian branch from your cloned repository: ```shell cd libeXaDrums git checkout debian ``` Then you can build the package: ```shell dpkg-buildpackage -b -uc -us ``` If you have multiple cores/threads, you can speed up the build process by appending the option -jn to dpkg-buildpackage, where n is the number of threads that you want to use for the compilation. Example, for four threads type: `dpkg-buildpackage -b -uc -us -j4`. ### Install The Debian packages are built in the parent directory, so you should be able to install them by using dpkg (don't forget to install them as root): ```shell cd .. sudo dpkg -i libexadrums0_[...].deb sudo dpkg -i libexadrums-dev[...].deb ``` ### Configuration ## Usage The library is self documented. libeXaDrums-0.4.2/Roadmap.md000066400000000000000000000024131354641705500156530ustar00rootroot00000000000000# LibeXaDrums roadmap This document outlines the development plan from a high level and will be updated as progress is made. ## Legend of annotations | Mark | Description | | ---------- | ------------------------------- | | open box | work not started - scheduled | | check mark | work completed | | ✍ | on-going work | ## Future versions ### 0.4.2 - [x] Build successfully with clang++-7. - [x] Version.h.in instead of eXaDrums.h.in. - [x] Fix Readme (installation procedure -- checkout debian branch first). ### 0.5.0 - [x] Add export configuration feature. - [x] Add import configuration feature. - [ ] Add GetVersion() to API. - [ ] ✍ Document API. - [ ] Bug fix: check if instrument's triggers exist. - [ ] Add trigger sensitivity. - [ ] Add score to rhythm coach window. - [ ] Create instrument only if enough triggers are available. - [ ] Fix metronome volume bug. ### 0.6.0 - [ ] Add recorder's sound export button and window. - [ ] Recorder can export to either xml or wav. - [ ] Calibration window. ### 0.7.0 ### 0.8.0 - [ ] Load instrument configuration from file. ### 0.9.0 - [ ] Instrument maker. ### 1.0.0 ## Documentation - [ ] Doxygen: document code. - [ ] API documentation. libeXaDrums-0.4.2/Sound/000077500000000000000000000000001354641705500150365ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/Alsa/000077500000000000000000000000001354641705500157165ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/Alsa/Alsa.cpp000066400000000000000000000152621354641705500173100ustar00rootroot00000000000000/* * Alsa.cpp * * Created on: 11 Apr 2015 * Author: jeremy */ #include "Alsa.h" #include "../../Util/Threading.h" #include "../../Util/ErrorHandling.h" #include #include #include #include #include #include #include using namespace Util; namespace Sound { Alsa::Alsa(const AlsaParams& parameters, std::shared_ptr const& mix) : params(parameters), mixer(mix), play(false), rec(false) { _snd_pcm_stream type = (params.capture)? SND_PCM_STREAM_CAPTURE:SND_PCM_STREAM_PLAYBACK; int err = snd_pcm_open(¶ms.handle, params.device.c_str(), type, 0); if(err >= 0) { snd_pcm_hw_params_alloca(¶ms.hwParams); SetHwParams(); snd_pcm_sw_params_alloca(¶ms.swParams); SetSwParams(); } else { throw Exception(snd_strerror(err), error_type_error); } auto devices = GetDevices(); auto itDev = std::find_if(devices.begin(), devices.end(), [&](const auto& d) { return d.second == params.device; }); if(itDev == devices.end()) { if(params.device == "default") { this->deviceName = devices.front().first; } else { throw Exception("Audio device not found.", error_type_error); // Audio device not found } } else { this->deviceName = itDev->first; } return; } Alsa::~Alsa() { params.buffer.clear(); // Close pcm handle //snd_pcm_drop(params.handle); snd_pcm_drain(params.handle); snd_pcm_close(params.handle); return; } std::vector> Alsa::GetDevices(const snd_pcm_stream_t type) { std::vector> devices; for(int card = 0; card >= 0; snd_card_next(&card)) { snd_ctl_t* handle; const std::string name("hw:" + std::to_string(card)); if(snd_ctl_open(&handle, name.data(), 0) < 0) { continue; } snd_ctl_card_info_t* cardInfo; snd_ctl_card_info_alloca(&cardInfo); if(snd_ctl_card_info(handle, cardInfo) < 0) { snd_ctl_close(handle); continue; } for(int dev = 0; dev >= 0; snd_ctl_pcm_next_device(handle, &dev)) { snd_pcm_info_t* pcmInfo; snd_pcm_info_alloca(&pcmInfo); snd_pcm_info_set_device(pcmInfo, dev); snd_pcm_info_set_subdevice(pcmInfo, 0); snd_pcm_info_set_stream(pcmInfo, type); if(snd_ctl_pcm_info(handle, pcmInfo) < 0) { continue; } if(dev == 0) { const std::string deviceId("plughw:" + std::to_string(card) + "," + std::to_string(dev)); const std::string deviceName(std::string(snd_ctl_card_info_get_name(cardInfo)) + " [hw:" + std::to_string(card) + "," + std::to_string(dev) + "]"); devices.push_back(std::make_pair(deviceName, deviceId)); } } snd_ctl_close(handle); } return devices; } void Alsa::Start() { auto sndErrorToException = [](auto code) { if(code != 0) { throw Exception(snd_strerror(code), error_type_error); } }; sndErrorToException(snd_pcm_drop(params.handle)); sndErrorToException(snd_pcm_prepare(params.handle)); //sndErrorToException(snd_pcm_start(params.handle)); if(params.capture) { rec = true; StartRecord(); } else { play = true; StartPlayback(); } return; } void Alsa::Stop() { if(params.capture) { rec = false; StopRecord(); } else { play = false; StopPlayback(); } return; } /// PRIVATE int Alsa::SetHwParams() { unsigned int realRate; snd_pcm_uframes_t size; int dir; snd_pcm_hw_params_any(params.handle, params.hwParams); snd_pcm_hw_params_set_rate_resample(params.handle, params.hwParams, 1); snd_pcm_hw_params_set_access(params.handle, params.hwParams, params.access); snd_pcm_hw_params_set_format(params.handle, params.hwParams, params.format); snd_pcm_hw_params_set_channels(params.handle, params.hwParams, params.nChannels); realRate = params.sampleRate; snd_pcm_hw_params_set_rate_near(params.handle, params.hwParams, &realRate, 0); //std::cout << "Real rate: " << realRate; snd_pcm_hw_params_set_buffer_time_near(params.handle, params.hwParams, ¶ms.bufferTime, &dir); snd_pcm_hw_params_get_buffer_size(params.hwParams, &size); params.bufferSize = size; snd_pcm_hw_params_set_period_time_near(params.handle, params.hwParams, ¶ms.periodTime, &dir); snd_pcm_hw_params_get_period_size(params.hwParams, &size, &dir); params.periodSize = size; params.buffer.resize(size); snd_pcm_hw_params(params.handle, params.hwParams); return 0; } int Alsa::SetSwParams() { snd_pcm_sw_params_current(params.handle, params.swParams); snd_pcm_sw_params_set_start_threshold(params.handle, params.swParams, (params.bufferSize / params.periodSize) * params.periodSize); snd_pcm_sw_params_set_avail_min(params.handle,params.swParams, params.periodSize); snd_pcm_sw_params(params.handle, params.swParams); return 0; } void Alsa::StartRecord() { recordThread = std::thread(&Alsa::Record, this); return; } void Alsa::StopRecord() { rec.store(false); recordThread.join(); return; } void Alsa::Record() { return; } void Alsa::StartPlayback() { playThread = std::thread(&Alsa::Playback, this); // // Set maximum priority to the thread // sched_param sch_params; // sch_params.sched_priority = sched_get_priority_max(SCHED_FIFO); // // pthread_setschedparam(playThread.native_handle(), SCHED_FIFO, &sch_params); Util::SetThreadPriority(playThread.native_handle(), 100); return; } void Alsa::StopPlayback() { play.store(false); playThread.join(); return; } void Alsa::Playback() { int err = 0; while(play.load()) { int frames = params.periodSize / params.nChannels; while(frames > 0) { //time_point t_start = high_resolution_clock::now(); mixer->Mix(params.buffer); /*time_point t_end = high_resolution_clock::now(); auto d = duration(t_end-t_start).count(); if(d > 20) { std::cout << std::fixed << std::setprecision(2) << "Wall clock time passed: " << d << " us" << std::endl; } */ err = snd_pcm_writei(params.handle, params.buffer.data(), frames); if (err == -EAGAIN) { continue; } if (err < 0) { XrunRecovery(err); } frames -= err; } } return; } void Alsa::XrunRecovery(int& err) { using namespace std::literals::chrono_literals; if (err == -EPIPE) { err = snd_pcm_prepare(params.handle); } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(params.handle)) == -EAGAIN) { std::this_thread::sleep_for(1ms); } if (err < 0) { err = snd_pcm_prepare(params.handle); } } return; } } libeXaDrums-0.4.2/Sound/Alsa/Alsa.h000066400000000000000000000021211354641705500167430ustar00rootroot00000000000000/* * Alsa.h * * Created on: 11 Apr 2015 * Author: jeremy */ #ifndef ALSA_H_ #define ALSA_H_ #define ALSA_PCM_NEW_HW_PARAMS_API #include "../Mixer/Mixer.h" #include "AlsaParams.h" #include #include #include namespace Sound { class Alsa { public: Alsa(const AlsaParams& parameters, std::shared_ptr const& mixer); virtual ~Alsa(); static std::vector> GetDevices(const snd_pcm_stream_t type = SND_PCM_STREAM_PLAYBACK); void Start(); void Stop(); std::string GetDeviceName() const noexcept { return deviceName; } AlsaParams GetParameters() const { return params; } private: int SetHwParams(); int SetSwParams(); void StartPlayback(); void StopPlayback(); void Playback(); void StartRecord(); void StopRecord(); void Record(); void XrunRecovery(int& err); std::thread playThread; std::thread recordThread; AlsaParams params; std::string deviceName; std::shared_ptr mixer; std::atomic play; std::atomic rec; }; } #endif /* ALSA_H_ */ libeXaDrums-0.4.2/Sound/Alsa/AlsaParameters.cpp000066400000000000000000000101701354641705500213250ustar00rootroot00000000000000/* * AlsaParameters.cpp * * Created on: 7 Feb 2016 * Author: jeremy */ #include "AlsaParameters.h" #include "../../Util/ErrorHandling.h" #include #include using namespace tinyxml2; using namespace Util; namespace Sound { void AlsaParameters::LoadAlsaParameters(const std::string& filePath, AlsaParams& parameters) { XMLDocument doc; if(doc.LoadFile(filePath.c_str()) != XML_SUCCESS) { throw Exception("Could not load sound card parameters.", error_type_error); } XMLElement* root = doc.RootElement(); XMLElement* device = root->FirstChildElement("device"); XMLElement* capture = root->FirstChildElement("capture"); XMLElement* format = root->FirstChildElement("format"); XMLElement* sampleRate = root->FirstChildElement("sampleRate"); XMLElement* nChannels = root->FirstChildElement("nChannels"); XMLElement* bufferTime = root->FirstChildElement("bufferTime"); XMLElement* periodTime = root->FirstChildElement("periodTime"); XMLElement* access = root->FirstChildElement("access"); parameters.device = device->GetText(); parameters.capture = (bool) std::stoi(capture->GetText()); parameters.format = GetSndFormat(format->GetText()); parameters.sampleRate = (unsigned int) std::stoi(sampleRate->GetText()); parameters.nChannels = (unsigned int) std::stoi(nChannels->GetText()); parameters.bufferTime = (unsigned int) std::stoi(bufferTime->GetText()); parameters.periodTime = (unsigned int) std::stoi(periodTime->GetText()); parameters.access = GetAccessType(access->GetText()); return; } void AlsaParameters::SaveAlsaParameters(const std::string& filePath, const AlsaParams& parameters) { // Create document XMLDocument doc; // Add root element XMLElement* root = doc.NewElement("root"); doc.InsertFirstChild(root); // Create Elements XMLElement* device = doc.NewElement("device"); XMLElement* capture = doc.NewElement("capture"); XMLElement* format = doc.NewElement("format"); XMLElement* sampleRate = doc.NewElement("sampleRate"); XMLElement* nChannels = doc.NewElement("nChannels"); XMLElement* bufferTime = doc.NewElement("bufferTime"); XMLElement* periodTime = doc.NewElement("periodTime"); XMLElement* access = doc.NewElement("access"); // Set values device->SetText(parameters.device.data()); capture->SetText(int(parameters.capture)); format->SetText("SND_PCM_FORMAT_S16_LE"); // XXX: temporary sampleRate->SetText(parameters.sampleRate); nChannels->SetText(parameters.nChannels); bufferTime->SetText(parameters.bufferTime); periodTime->SetText(parameters.periodTime); access->SetText("SND_PCM_ACCESS_RW_INTERLEAVED"); // XXX: temporary // Insert all elements root->InsertEndChild(device); root->InsertEndChild(capture); root->InsertEndChild(format); root->InsertEndChild(sampleRate); root->InsertEndChild(nChannels); root->InsertEndChild(bufferTime); root->InsertEndChild(periodTime); root->InsertEndChild(access); // Save modified file auto result = doc.SaveFile(filePath.data()); if(XML_SUCCESS != result) { throw Exception("Could not save triggers configuration.", error_type_error); } return; } // PRIVATE snd_pcm_format_t AlsaParameters::GetSndFormat(std::string formatName) { snd_pcm_format_t format; std::map dic; // Add definitions to dic dic["SND_PCM_FORMAT_S16_LE"] = SND_PCM_FORMAT_S16_LE; std::map< std::string, snd_pcm_format_t>::iterator i = dic.find(formatName); if(i != dic.end()) format = i->second; else format = SND_PCM_FORMAT_S8; // Default value return format; } snd_pcm_access_t AlsaParameters::GetAccessType(std::string accessName) { snd_pcm_access_t access; std::map dic; // Add definitions to dic dic["SND_PCM_ACCESS_RW_INTERLEAVED"] = SND_PCM_ACCESS_RW_INTERLEAVED; dic["SND_PCM_ACCESS_MMAP_INTERLEAVED"] = SND_PCM_ACCESS_MMAP_INTERLEAVED; std::map< std::string, snd_pcm_access_t>::iterator i = dic.find(accessName); if(i != dic.end()) access = i->second; else access = SND_PCM_ACCESS_RW_INTERLEAVED; // Default value return access; } } /* namespace Sound */ libeXaDrums-0.4.2/Sound/Alsa/AlsaParameters.h000066400000000000000000000013471354641705500210000ustar00rootroot00000000000000/* * AlsaParameters.h * * Created on: 7 Feb 2016 * Author: jeremy */ #ifndef SOURCE_SOUND_ALSA_ALSAPARAMETERS_H_ #define SOURCE_SOUND_ALSA_ALSAPARAMETERS_H_ #include "AlsaParams.h" #include #include namespace Sound { class AlsaParameters { public: static void LoadAlsaParameters(const std::string& filePath, AlsaParams& parameters); static void SaveAlsaParameters(const std::string& filePath, const AlsaParams& parameters); private: AlsaParameters() {}; virtual ~AlsaParameters() {}; static snd_pcm_format_t GetSndFormat(std::string formatName); static snd_pcm_access_t GetAccessType(std::string accessName); }; } /* namespace Sound */ #endif /* SOURCE_SOUND_ALSA_ALSAPARAMETERS_H_ */ libeXaDrums-0.4.2/Sound/Alsa/AlsaParams.h000066400000000000000000000013611354641705500201140ustar00rootroot00000000000000/* * AlsaParams.h * * Created on: 2 May 2015 * Author: jeremy */ #ifndef RASPIDRUMS_SOURCE_SOUND_ALSAPARAMS_H_ #define RASPIDRUMS_SOURCE_SOUND_ALSAPARAMS_H_ #include "alsa/asoundlib.h" #include #include namespace Sound { struct AlsaParams { std::string device; snd_pcm_t* handle; snd_pcm_hw_params_t* hwParams; snd_pcm_sw_params_t* swParams; bool capture; snd_pcm_format_t format; unsigned int sampleRate; unsigned int nChannels; unsigned int bufferTime; unsigned int periodTime; snd_pcm_sframes_t bufferSize; snd_pcm_sframes_t periodSize; snd_pcm_access_t access; std::vector buffer; }; } #endif /* RASPIDRUMS_SOURCE_SOUND_ALSAPARAMS_H_ */ libeXaDrums-0.4.2/Sound/InstrumentSoundType.h000066400000000000000000000025721354641705500212400ustar00rootroot00000000000000/* * InstrumentSoundType.h * * Created on: 15 Feb 2016 * Author: jeremy */ #ifndef SOURCE_SOUND_INSTRUMENTSOUNDTYPE_H_ #define SOURCE_SOUND_INSTRUMENTSOUNDTYPE_H_ #include "../Util/Enums.h" #include #include #include namespace Sound { enum class InstrumentSoundType { Default, RimShot, ClosingHiHat, First = Default, Last = ClosingHiHat }; inline std::ostream& operator<<(std::ostream& o, const InstrumentSoundType& x) { std::string os; switch (x) { case InstrumentSoundType::Default: os = "DrumHead"; break; case InstrumentSoundType::RimShot: os = "RimShot"; break; case InstrumentSoundType::ClosingHiHat: os = "ClosingHiHat";break; default: break; } return o << os; } inline InstrumentSoundType operator++(InstrumentSoundType& x) { return x = static_cast(std::underlying_type_t(x) + 1); }; inline InstrumentSoundType operator*(InstrumentSoundType x) { return x; }; inline InstrumentSoundType begin(InstrumentSoundType x) { return InstrumentSoundType::First; }; inline InstrumentSoundType end(InstrumentSoundType x) { InstrumentSoundType l = InstrumentSoundType::Last; return ++l; }; inline std::istream& operator>>(std::istream& is, InstrumentSoundType& x) { return Util::StreamToEnum(is, x); } } #endif /* SOURCE_SOUND_INSTRUMENTSOUNDTYPE_H_ */ libeXaDrums-0.4.2/Sound/Mixer/000077500000000000000000000000001354641705500161225ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/Mixer/Mixer.cpp000066400000000000000000000055671354641705500177270ustar00rootroot00000000000000/* * Mixer.cpp * * Created on: 11 Apr 2015 * Author: jeremy */ #include "Mixer.h" #include namespace Sound { Mixer::Mixer() noexcept { return; } Mixer::~Mixer() { return; } void Mixer::PlaySound(int id, float volume) { auto s = std::find_if(playList.begin(), playList.end(), [&id](SoundState& s) { return id == s.id && !s.isPlaying.load(std::memory_order_relaxed); }); if(s != playList.end()) { // The sound is already in playList //soundBank->sounds[s->id].Seek(0); s->volume = volume; s->index = 0; s->isPlaying.store(true, std::memory_order_release); } else { // Add sound to playList //playList.emplace_back(id, volume, true); const auto index = playListIndex.fetch_add(1, std::memory_order_relaxed); // Protect from overflow (ignore new sound...) if(index >= playList.size()) { return; } playList[index].id = id; playList[index].volume = volume; playList[index].isPlaying.store(true, std::memory_order_release); } return; } void Mixer::StopSound(int id) { // Stop sound in the play list for(auto& sound : playList) { if(sound.id == id) { sound.isPlaying.store(false, std::memory_order_relaxed); } } return; } void Mixer::Mix(std::vector& buffer) noexcept { // Fill buffer with zeros std::fill(buffer.begin(), buffer.end(), 0); std::size_t periodSize = buffer.size(); // Mix sounds for(std::size_t si = 0; si < playList.size(); si++) { if(playList[si].isPlaying.load(std::memory_order_acquire)) { SoundState& soundState = playList[si]; Sound& sound = soundBank->sounds[soundState.id]; if(sound.HasMoreData(soundState.index, periodSize)) { const float volume = sound.GetVolume(); const float mix_volume = soundState.volume; if(sound.IsLoop()) { std::size_t prevIdx = sound.LoadIndex(); if(prevIdx % sound.GetLength() < periodSize) { sound.SetStartTime(); } for(std::size_t i = 0; i < periodSize; i++) { buffer[i] += volume * mix_volume * sound.GetValue(i + soundState.index); } sound.StoreIndex(soundState.index); } else { const short* data = sound.GetData(); const std::size_t idx = soundState.index; for(std::size_t i = 0; i < periodSize; i++) { buffer[i] += volume * mix_volume * data[idx + i]; } } soundState.index += periodSize; //sound.AddToIndex(periodSize); } else { soundState.isPlaying.store(false, std::memory_order_relaxed); } } } return; } /** * @brief Stops all sounds (must be done after the mixer has been stopped). * */ void Mixer::Clear() noexcept { playListIndex.store(0, std::memory_order_relaxed); for(auto& s : playList) { s.isPlaying.store(false, std::memory_order_relaxed); } } } libeXaDrums-0.4.2/Sound/Mixer/Mixer.h000066400000000000000000000014231354641705500173570ustar00rootroot00000000000000/* * Mixer.h * * Created on: 11 Apr 2015 * Author: jeremy */ #ifndef MIXER_H_ #define MIXER_H_ #include "../SoundBank/SoundBank.h" #include "../SoundState.h" #include "../Sound.h" #include #include #include #include namespace Sound { class Mixer { public: Mixer() noexcept; virtual ~Mixer(); void PlaySound(int id, float volume); void LoopSound(int id, float volume); void StopSound(int id); void Mix(std::vector& buffer) noexcept; void Clear() noexcept; void SetSoundBank(std::shared_ptr& sb) noexcept { this->soundBank = sb; } private: std::shared_ptr soundBank; std::array playList; std::atomic playListIndex{0}; }; } #endif /* MIXER_H_ */ libeXaDrums-0.4.2/Sound/Sound.cpp000066400000000000000000000036701354641705500166400ustar00rootroot00000000000000/* * SoundSample.cpp * * Created on: 27 Feb 2016 * Author: jeremy */ #include "Sound.h" #include using namespace std::chrono; namespace Sound { Sound::Sound() : Sound(std::vector{}) { return; } Sound::Sound(Sound& s) : Sound() { swap(*this, s); return; } Sound::Sound(Sound&& s) : Sound() { swap(*this, s); return; } Sound::Sound(int id, const std::vector& soundData, float vol) : id(id), loop(false), data(soundData), length(data.size()) { volume.store(vol); idx.store(0); lastStartTime.store(time_point_cast(high_resolution_clock::now()).time_since_epoch().count(), std::memory_order_relaxed); return; } Sound::Sound(int id, const std::vector& soundData) : Sound(id, soundData, 1.0f) { return; } Sound::Sound(const std::vector& soundData, float volume) : Sound(-1, soundData, volume) { return; } Sound::Sound(const std::vector& soundData) : Sound(-1, soundData, 1.0f) { return; } Sound::~Sound() { return; } bool Sound::HasMoreData(std::size_t index, std::size_t length) const { if(loop) return true; if(index + length <= data.size()) { return true; } else { return false; } } void Sound::SetVolume(float volume) { float newVolume = std::min(std::max(0., volume), 1.); this->volume.store(newVolume); return; } void Sound::SetStartTime() { this->lastStartTime.store(time_point_cast(high_resolution_clock::now()).time_since_epoch().count(), std::memory_order_relaxed); return; } /*void Sound::AddToIndex(int offset) { if(!HasMoreData(offset)) { idx.store(0); } else { long prevIdx = idx.fetch_add(offset); if(prevIdx % length < offset) { this->lastStartTime.store(time_point_cast(high_resolution_clock::now()).time_since_epoch().count()); } } return; }*/ // PRIVATE } /* namespace Sound */ libeXaDrums-0.4.2/Sound/Sound.h000066400000000000000000000045431354641705500163050ustar00rootroot00000000000000/* * SoundSample.h * * Created on: 27 Feb 2016 * Author: jeremy */ #ifndef SOURCE_SOUND_SOUND_H_ #define SOURCE_SOUND_SOUND_H_ #include #include #include namespace Sound { class Sound { friend class SoundBank; friend class SoundProcessor; public: Sound(); Sound(Sound& s); Sound(Sound&& s); explicit Sound(const std::vector& soundData); Sound(const std::vector& soundData, float volume); Sound(int id, const std::vector& soundData); Sound(int id, const std::vector& soundData, float vol); virtual ~Sound(); friend void swap(Sound& first, Sound& second) noexcept { using std::swap; swap(first.id, second.id); swap(first.loop, second.loop); swap(first.data, second.data); swap(first.length, second.length); // "swap" atomics second.volume.store(first.volume.exchange(second.volume.load())); second.idx.store(first.idx.exchange(second.idx.load())); second.lastStartTime.store(first.lastStartTime.exchange(second.lastStartTime.load())); return; } Sound& operator=(Sound s) noexcept { swap(*this, s); return *this; } void SetVolume(float volume); //void AddToIndex(int offset); bool HasMoreData(std::size_t index, std::size_t length) const; //bool IsFinished() const { return idx.load() >= (int)data.size(); } inline void StoreIndex(long i) { idx.store(i); } void SetStartTime(); inline void SetLoop(bool s) noexcept { loop = s; } inline int GetId() const { return this->id; } inline float GetVolume() const noexcept { return volume.load(); } inline unsigned long LoadIndex() const noexcept { return idx.load(); } inline unsigned long long GetLastStartTime() const noexcept { return lastStartTime.load(std::memory_order_relaxed); } inline int GetLength() const noexcept { return length; } inline const short* GetData() const { return data.data(); } const std::vector& GetInternalData() const { return data; } inline const short GetValue(int i) const noexcept { return data[i % length]; } inline bool IsLoop() const { return loop; } private: int id; bool loop; std::atomic idx; std::atomic lastStartTime; std::vector data; int length; std::atomic volume; }; typedef std::shared_ptr SoundPtr; } /* namespace Sound */ #endif /* SOURCE_SOUND_SOUND_H_ */ libeXaDrums-0.4.2/Sound/SoundBank/000077500000000000000000000000001354641705500167225ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/SoundBank/SoundBank.cpp000066400000000000000000000070411354641705500213140ustar00rootroot00000000000000/* * SoundBank.cpp * * Created on: 14 Feb 2016 * Author: jeremy */ #include "SoundBank.h" #include "../Util/WavUtil.h" #include #include #include #include namespace Sound { SoundBank::SoundBank(const std::string& dataFolder) noexcept : soundBankFolder(dataFolder + "SoundBank/") { return; } SoundBank::~SoundBank() { return; } int SoundBank::AddSound(const std::vector& data) { return AddSound(data, 1.0f); } int SoundBank::AddSound(const std::vector& data, float volume) { // Add sound to collection std::size_t sId = sounds.size(); sounds.push_back(Sound(sId, data, volume)); return sounds.back().GetId(); } int SoundBank::AddSound(Sound&& sound, float volume) { // Add sound to collection sound.id = sounds.size(); sound.volume.store(volume); sounds.push_back(std::move(sound)); return sounds.back().GetId(); } void SoundBank::DeleteSound(int id) { auto it = std::remove_if(sounds.begin(), sounds.end(), [&id](Sound& sound) { return id == sound.GetId(); }); if(it != end(sounds)) { sounds.erase(it); } return; } void SoundBank::LoopSound(int id, bool s) { if(static_cast(id) < sounds.size()) { sounds[id].SetLoop(s); } } int SoundBank::LoadSound(const std::string& filename) { return LoadSound(filename, 1.0f); } int SoundBank::LoadSound(const std::string& filename, float volume) { std::string fileLocation = this->soundBankFolder + filename; // Open file std::ifstream soundFile(fileLocation); // Check file validity if(!soundFile.good()) { throw - 1; } soundFile.seekg(0, std::ios::end); // Get file size in bytes size_t fileSize = soundFile.tellg(); soundFile.seekg(0, std::ios::beg); // HEADER std::vector header_data(44); soundFile.read((char*)header_data.data(), header_data.size()); WavHeader header(header_data); size_t chunkLength = header.get_subchunk2_size(); size_t dataLength = 0; if(chunkLength + header_data.size() == fileSize) { dataLength = chunkLength; } else { std::string error{"Couldn't read sound file: " + fileLocation}; throw std::runtime_error(error); } uint32_t data_size_short = dataLength / sizeof(short); std::vector data(data_size_short); soundFile.read((char*)data.data(), dataLength); // Close file soundFile.close(); // Add sound to collection std::size_t sId = sounds.size(); sounds.push_back(Sound(sId, data, volume)); return sounds.back().GetId(); } std::vector SoundBank::GetSoundFiles(const std::string& dataFolder) { std::vector paths; std::string location = dataFolder + "SoundBank/"; struct dirent* ent; DIR* directory = opendir(location.c_str()); // Scan directory while((ent = readdir(directory)) != NULL) { // Check if entry is a directory if(ent->d_type == DT_DIR) { // Get directory path std::string soundsDirPath = location + std::string(ent->d_name) + "/"; std::string dirName = std::string(ent->d_name) + "/"; struct dirent* dir; DIR* soundsDir = opendir(soundsDirPath.c_str()); while((dir = readdir(soundsDir)) != NULL) { // Get file name and extension std::string fileName(dir->d_name); std::string fileExtension = fileName.substr(fileName.find_last_of(".") + 1); if(fileExtension == "raw") { paths.push_back(dirName + fileName); } } closedir(soundsDir); } } closedir(directory); return paths; } } /* namespace Sound */ libeXaDrums-0.4.2/Sound/SoundBank/SoundBank.h000066400000000000000000000022251354641705500207600ustar00rootroot00000000000000/* * SoundBank.h * * Created on: 14 Feb 2016 * Author: jeremy */ #ifndef SOURCE_SOUND_SOUNDBANK_SOUNDBANK_H_ #define SOURCE_SOUND_SOUNDBANK_SOUNDBANK_H_ #include "../Sound.h" #include #include namespace Sound { class Mixer; class SoundBank { friend class Mixer; public: explicit SoundBank(const std::string& dataFolder) noexcept; virtual ~SoundBank(); static std::vector GetSoundFiles(const std::string& dataFolder); int LoadSound(const std::string& filename); int LoadSound(const std::string& filename, float volume); int AddSound(const std::vector& soundData); int AddSound(const std::vector& soundData, float volume); int AddSound(Sound&& sound, float volume); void DeleteSound(int id); void LoopSound(int id, bool s); void Clear() noexcept { std::vector().swap(sounds); } void SetSoundVolume(int id, float volume) { sounds[id].SetVolume(volume); } const Sound& GetSound(int id) const { return sounds[id]; } private: std::string soundBankFolder; std::vector sounds; }; } /* namespace Sound */ #endif /* SOURCE_SOUND_SOUNDBANK_SOUNDBANK_H_ */ libeXaDrums-0.4.2/Sound/SoundProcessor/000077500000000000000000000000001354641705500200265ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/SoundProcessor/SoundProcessor.cpp000066400000000000000000000011731354641705500235240ustar00rootroot00000000000000/* * SoundProcessor.cpp * * Created on: 14 Nov 2015 * Author: jeremy */ #include "SoundProcessor.h" #include #include #include namespace Sound { Sound SoundProcessor::Muffle(const Sound& sound, float m) { //XXX Need to check m! const std::vector& soundData = sound.GetInternalData(); std::vector newSoundData(soundData.size()); const float gamma = -3.0f / (m * soundData.size()); for(std::size_t i = 0; i < newSoundData.size(); ++i) { newSoundData[i] = soundData[i] * std::exp(i * gamma); } return Sound(newSoundData); } } /* namespace Sound */ libeXaDrums-0.4.2/Sound/SoundProcessor/SoundProcessor.h000066400000000000000000000007421354641705500231720ustar00rootroot00000000000000/* * SoundProcessor.h * * Created on: 14 Nov 2015 * Author: jeremy */ #ifndef SOURCE_SOUND_SOUNDPROCESSOR_SOUNDPROCESSOR_H_ #define SOURCE_SOUND_SOUNDPROCESSOR_SOUNDPROCESSOR_H_ #include "../Sound.h" namespace Sound { class SoundProcessor { public: static Sound Muffle(const Sound& sound, float m); private: SoundProcessor() {}; virtual ~SoundProcessor() {}; }; } /* namespace Sound */ #endif /* SOURCE_SOUND_SOUNDPROCESSOR_SOUNDPROCESSOR_H_ */ libeXaDrums-0.4.2/Sound/SoundState.h000066400000000000000000000017121354641705500173010ustar00rootroot00000000000000/* * SoundState.h * * Created on: 30 Jul 2017 * Author: jeremy */ #ifndef SOURCE_SOUND_SOUNDSTATE_H_ #define SOURCE_SOUND_SOUNDSTATE_H_ #include namespace Sound { struct SoundState { SoundState() : id(0), volume(0.), index(0) { isPlaying.store(false); } SoundState(int i, float v, bool ip) : id(i), volume(v), index(0) { isPlaying.store(ip, std::memory_order_release); } SoundState(const SoundState& s) : id(s.id), volume(s.volume), index(s.index) { isPlaying.store(s.isPlaying.load(std::memory_order_acquire), std::memory_order_release); } SoundState& operator=(const SoundState& s) { this->id = s.id; this->volume = s.volume; this->index = s.index; this->isPlaying.store(s.isPlaying.load(std::memory_order_acquire), std::memory_order_release); return *this; } int id; float volume; std::size_t index; std::atomic isPlaying; }; } #endif /* SOURCE_SOUND_SOUNDSTATE_H_ */ libeXaDrums-0.4.2/Sound/Util/000077500000000000000000000000001354641705500157535ustar00rootroot00000000000000libeXaDrums-0.4.2/Sound/Util/WavUtil.h000066400000000000000000000112251354641705500175200ustar00rootroot00000000000000/* * WavUtil.h * * Created on: 12 Nov 2017 * Author: jeremy */ #ifndef SOURCE_SOUND_UTIL_WAVUTIL_H_ #define SOURCE_SOUND_UTIL_WAVUTIL_H_ #include #include #include #include #include #include #include namespace Sound { template inline T BytesToWord(const std::vector& bytes) { return std::accumulate(bytes.rbegin(), bytes.rend(), T{0}, [](T a, T b) { return a << 8 | b; }); } template inline std::vector SubVector(const std::vector& vec, size_t i, size_t j) { return std::vector(vec.begin() + i, vec.begin() + j); } inline std::string BytesToString(const std::vector& bytes, size_t start = 0, size_t stop = 0) { if(stop == 0) { stop = bytes.size(); } return std::string(bytes.begin() + start, bytes.begin() + stop); } template inline std::enable_if_t::value, void> CopyBytesToVector(const T& bytes, std::vector& vec, size_t offset) { std::copy(std::begin(bytes), std::end(bytes), vec.begin() + offset); } template inline std::enable_if_t::value, void> CopyBytesToVector(const T& bytes, std::vector& vec, size_t offset) { auto ptr = reinterpret_cast(&bytes); CopyBytesToVector(std::vector(ptr, ptr + sizeof(T)), vec, offset); } class WavHeader { public: explicit WavHeader(const std::vector& header_data) : chunk_id(BytesToString(header_data, 0, 4)), format(BytesToString(header_data, 8, 12)), subchunk1_id(BytesToString(header_data, 12, 16)), subchunk2_id(BytesToString(header_data, 36, 40)) { chunk_size = BytesToWord(SubVector(header_data, 4, 8)); subchunk1_size = BytesToWord(SubVector(header_data, 16, 20)); audio_format = BytesToWord(SubVector(header_data, 20, 22)); num_channels = BytesToWord(SubVector(header_data, 22, 24)); sample_rate = BytesToWord(SubVector(header_data, 24, 28)); byte_rate = BytesToWord(SubVector(header_data, 28, 32)); block_align = BytesToWord(SubVector(header_data, 32, 34)); bits_per_sample = BytesToWord(SubVector(header_data, 34, 36)); subchunk2_size = BytesToWord(SubVector(header_data, 40, 44)); } WavHeader() : chunk_id("RIFF"), chunk_size(0), format("WAVE"), subchunk1_id("fmt "), subchunk1_size(16), audio_format(1), num_channels(2), sample_rate(48000), byte_rate(192000), block_align(4), bits_per_sample(16), subchunk2_id("data"), subchunk2_size(0) {} void SetDataLength(size_t length) noexcept { subchunk2_size = length; chunk_size = subchunk2_size + 36; } std::vector ToBytes() const { std::vector headerData(44); CopyBytesToVector(chunk_id, headerData, 0); CopyBytesToVector(chunk_size, headerData, 4); CopyBytesToVector(format, headerData, 8); CopyBytesToVector(subchunk1_id, headerData, 12); CopyBytesToVector(subchunk1_size, headerData, 16); CopyBytesToVector(audio_format, headerData, 20); CopyBytesToVector(num_channels, headerData, 22); CopyBytesToVector(sample_rate, headerData, 24); CopyBytesToVector(byte_rate, headerData, 28); CopyBytesToVector(block_align, headerData, 32); CopyBytesToVector(bits_per_sample, headerData, 34); CopyBytesToVector(subchunk2_id, headerData, 36); CopyBytesToVector(subchunk2_size, headerData, 40); return headerData; } inline uint32_t get_subchunk2_size() const noexcept { return subchunk2_size; } ~WavHeader() = default; private: std::string chunk_id; uint32_t chunk_size; std::string format; std::string subchunk1_id; uint32_t subchunk1_size; uint16_t audio_format; uint16_t num_channels; uint32_t sample_rate; uint32_t byte_rate; uint16_t block_align; uint16_t bits_per_sample; std::string subchunk2_id; uint32_t subchunk2_size; }; // static std::vector load_wav_from_disk(const std::string& file_location) // { // // // Open file // std::ifstream file(file_location); // // // Check file validity // if(!file.good()) // { // throw std::runtime_error("Couldn't load file."); // } // // // HEADER // std::vector header_data(44); // file.read((char*)header_data.data(), header_data.size()); // wav_header header(header_data); // // // DATA // auto data_size{header.get_subchunk2_size()}; // // uint32_t data_size_short = data_size / sizeof(short); // std::vector data(data_size_short); // // file.read((char*)data.data(), data_size); // // return data; // } } #endif /* SOURCE_SOUND_UTIL_WAVUTIL_H_ */ libeXaDrums-0.4.2/Util/000077500000000000000000000000001354641705500146635ustar00rootroot00000000000000libeXaDrums-0.4.2/Util/Crypt.h000066400000000000000000000056001354641705500161360ustar00rootroot00000000000000/* * Crypt.h * * Created on: 26 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_CRYPT_H_ #define SOURCE_UTIL_CRYPT_H_ #include #include #include #include namespace Util { static constexpr char Base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static constexpr std::array Base64Indices = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }}; static std::string Base64Encode(const std::vector& str) { const auto len = str.size(); size_t d = len % 3; std::string str64(4 * (int(d > 0) + len / 3), '='); for(size_t i = 0, j = 0; i < len - d; i += 3) { int32_t n = int32_t(str[i]) << 16 | int32_t(str[i + 1]) << 8 | str[i + 2]; str64[j++] = Base64Chars[n >> 18]; str64[j++] = Base64Chars[n >> 12 & 0x3F]; str64[j++] = Base64Chars[n >> 6 & 0x3F]; str64[j++] = Base64Chars[n & 0x3F]; } if(d-- > 0) // Padding { int32_t n = d ? int32_t(str[len - 2]) << 8 | str[len - 1] : str[len - 1]; str64[str64.size() - 2] = d ? Base64Chars[(n & 0xF) << 2] : '='; str64[str64.size() - 3] = d ? Base64Chars[n >> 4 & 0x03F] : Base64Chars[(n & 3) << 4]; str64[str64.size() - 4] = d ? Base64Chars[n >> 10] : Base64Chars[n >> 2]; } return str64; } template static std::string Base64Encode(const std::vector& input) { std::vector str; str.reserve(sizeof(T) * input.size()); std::copy_n(reinterpret_cast(input.data()), sizeof(T) * input.size(), std::back_inserter(str)); return Base64Encode(str); } /*static std::string Base64Decode(const std::string& str64) { const auto len = str64.size(); const auto pad = len > 0 && (len % 4 || str64[len - 1] == '='); const size_t length = ((len + 3) / 4 - pad) * 4; std::string str(length / 4 * 3 + pad, '\0'); for(size_t i = 0, j = 0; i < length; i += 4) { int32_t n = Base64Indices[str64[i]] << 18 | Base64Indices[str64[i + 1]] << 12 | Base64Indices[str64[i + 2]] << 6 | Base64Indices[str64[i + 3]]; str[j++] = n >> 16; str[j++] = n >> 8 & 0xFF; str[j++] = n & 0xFF; } if(pad != 0) { int32_t n = Base64Indices[str64[length]] << 18 | Base64Indices[str64[length + 1]] << 12; str.back() = n >> 16; if (len > length + 2 && str64[length + 2] != '=') { n |= Base64Indices[str64[length + 2]] << 6; str.push_back(n >> 8 & 0xFF); } } return str; } */ } #endif /* SOURCE_UTIL_CRYPT_H_ */ libeXaDrums-0.4.2/Util/Enums.h000066400000000000000000000030321354641705500161210ustar00rootroot00000000000000/* * Enums.h * * Created on: 29 Sep 2016 * Author: jeremy */ #ifndef SOURCE_UTIL_ENUMS_H_ #define SOURCE_UTIL_ENUMS_H_ #include "ErrorHandling.h" #include #include #include #include namespace Util { /** * Helper function to make conversion to enums easier. * @param is Input stream. * @param x Enum type to convert the input stream to. * @return */ template inline std::istream& StreamToEnum(std::istream& is, T& x) { std::string s; is >> s; for(const auto& l : T()) { std::ostringstream os; os << l; if(os.str() == s) { x = l; } } return is; } class Enums { public: template static std::string ToString(const T& e) { for (const auto& c : T{}) { if(c == e) { std::stringstream ss; ss << e; return ss.str(); } } throw Exception("Could not convert enum to string.", error_type_error); return ""; } template static T ToElement(const std::string& s) { for (const auto& c : T{}) { std::stringstream ss; ss << c; if(ss.str() == s) { return c; } } throw Exception("Could not convert string " + s + " to enum.", error_type_error); return T::First; } template static std::vector GetEnumVector() { std::vector v; for (const auto& c : T{}) { v.push_back(c); } return v; } private: Enums() = delete; ~Enums() = delete; }; } #endif /* SOURCE_UTIL_ENUMS_H_ */ libeXaDrums-0.4.2/Util/ErrorHandling.h000066400000000000000000000076751354641705500176110ustar00rootroot00000000000000#ifndef LIBEXADRUMS_SOURCE_UTIL_ERROR_HANDLING_H_ #define LIBEXADRUMS_SOURCE_UTIL_ERROR_HANDLING_H_ #include #include namespace Util { #if __cplusplus__ extern "C" { #endif enum errorType : int32_t { error_type_success = 0, error_type_warning = 1, error_type_question = 2, error_type_error = 3, error_type_other = 4 }; typedef struct _error { char message[255]; int32_t type; } error; inline error make_error(const char* message, errorType error_type) { error e{"", error_type}; std::snprintf(e.message, sizeof e.message, "%s", message); // prevents overflow return e; } /** * @brief Merge two errors together * * @param e1 first erorr * @param e2 second error * @return error merged error */ inline error merge_errors(const error& e1, const error& e2) { error merged_error; if(e1.type >= e2.type) { std::snprintf(merged_error.message, sizeof merged_error.message, "%s", e1.message); merged_error.type = e1.type; } else { std::snprintf(merged_error.message, sizeof merged_error.message, "%s", e2.message); merged_error.type = e2.type; } return merged_error; } /** * @brief Update an error using another, newer, error. * * @param e error to be updated * @param new_error another error that alters the state of e * @return errorType error type */ inline errorType update_error(error& e, const error& new_error) { e = merge_errors(e, new_error); return errorType{static_cast(e.type)}; } #if __cplusplus__ } #endif class Exception : public std::exception { public: /** * @brief Construct a new Exception object from an error type. * * @param err */ explicit Exception(const error& err) noexcept : message{err.message}, error_type{static_cast(err.type)} {} Exception(const char* what_arg, errorType err_type) noexcept : message{what_arg}, error_type{err_type} {} Exception(std::string&& what_arg, errorType err_type) noexcept : message{std::move(what_arg)}, error_type{err_type} {} virtual const char* what() const noexcept final { return message.data(); } errorType type() const noexcept { return error_type; } private: std::string message; errorType error_type; }; /** * @brief Convert an error to an Exception. Throws if the error type is not error_type_success. * * @tparam F A callable type. * @param f A callable that returns an error. */ template void ErrorToException(F&& f) { error err = f(); if(err.type != error_type_success) { throw Exception(err); } } /** * @brief Convert an Exception to an error. * * @tparam F A callable type. * @param f A callable that throws the Exception that is to be converted. * @return error The error that corresponds to the Exception that has been thrown from the callable, or success if no exception was thrown. */ template error ExceptionToError(F&& f) noexcept { try { f(); } catch(const Exception& except) { return make_error(except.what(), except.type()); } catch(...) { return make_error("Unknown error.", error_type_error); } return error{"", error_type_success}; } } #endiflibeXaDrums-0.4.2/Util/Misc.h000066400000000000000000000047211354641705500157330ustar00rootroot00000000000000/* * Misc.h * * Created on: 11 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_MISC_H_ #define SOURCE_UTIL_MISC_H_ #include #include #include #include #include namespace Util { template inline typename std::enable_if_t for_each_tuple(std::tuple&, F) { return; } template inline typename std::enable_if_t<(I < sizeof...(T))> for_each_tuple(std::tuple& t, F f) { f(std::get(t)); for_each_tuple(t, f); } template inline void StrToValue(const std::string& is, T& val) { std::stringstream s(is); s >> val; } template inline void VectorOfStrToTuple(const std::vector& vec, std::tuple& tuple) { size_t i = 0; for_each_tuple(tuple, [&](auto& t){ StrToValue(vec[i++], t); }); } /** * Converts every element of input and concatenates the results to a string, where elements are separated by separator. * The last separator is removed. * @param input * @param separator * @return */ template static std::string JoinToStr(const T& input, std::string separator = ",") { std::string str = std::accumulate(std::begin(input), std::end(input), std::string{}, [&](const auto& a, const auto& b) { return a + std::to_string(b) + separator; }); return str.substr(0, str.size() - separator.size()); } /** * * @brief If v compares less than lo, returns lo; otherwise if hi compares less than v, returns hi; otherwise returns v. Uses comp to compare the values. * @param v the value to clamp. * @param lo the low boundary to clamp v to. * @param hi the high boundary to clamp v to. * @param comp Comparison function object. * @return Clamped value. */ template inline constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp ) { return comp(v, lo) ? lo : comp(hi, v) ? hi : v; } /** * @brief If v compares less than lo, returns lo; otherwise if hi compares less than v, returns hi; otherwise returns v. * @param v the value to clamp. * @param lo the low boundary to clamp v to. * @param hi the high boundary to clamp v to. * @return Clamped value. */ template inline constexpr const T& clamp( const T& v, const T& lo, const T& hi ) { return Util::clamp( v, lo, hi, std::less<>() ); } } #endif /* SOURCE_UTIL_MISC_H_ */ libeXaDrums-0.4.2/Util/Parsing.h000066400000000000000000000010401354641705500164320ustar00rootroot00000000000000/* * Parsing.h * * Created on: 25 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_PARSING_H_ #define SOURCE_UTIL_PARSING_H_ #include namespace Util { template class Token { public: friend std::istream& operator>>(std::istream& is, Token& t) { std::getline(is, t.data, delim); return is; } operator std::string() const { return data; } static constexpr char delimiter = delim; private: std::string data; }; using Line = Token<'\n'>; } #endif /* SOURCE_UTIL_PARSING_H_ */ libeXaDrums-0.4.2/Util/SimpleSafeQueue.h000066400000000000000000000040521354641705500200720ustar00rootroot00000000000000/* * SimpleSafeQueue.h * * Created on: 20 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_SIMPLESAFEQUEUE_H_ #define SOURCE_UTIL_SIMPLESAFEQUEUE_H_ #include #include #include namespace Util { /** * A thread-safe Single Producer Single Consumer queue. * Its size is fixed, it's a circular buffer. * Default size = 32. */ template class SimpleSafeQueue { public: /** * Pushes new value to the queue, and returns true if successful. * @param value * @return true if the queue isn't full, false otherwise. */ bool Push(const T& value) { const auto oldWriterIndex = writerIndex.load(std::memory_order_relaxed); const auto newWriterIndex = GetNextIndex(oldWriterIndex); // Is the queue full? if(newWriterIndex == readerIndex.load(std::memory_order_acquire)) { return false; } buffer[oldWriterIndex] = value; writerIndex.store(newWriterIndex, std::memory_order_release); return true; } /** * Pops an element from the queue, and returns true if successful. * @param value * @return true if the queue isn't empty, false otherwise. */ bool Pop(T& value) { const auto oldWriterIndex = writerIndex.load(std::memory_order_acquire); const auto oldReaderIndex = readerIndex.load(std::memory_order_relaxed); // Is the queue empty? if(oldWriterIndex == oldReaderIndex) { return false; } value = std::move(buffer[oldReaderIndex]); readerIndex.store(GetNextIndex(oldReaderIndex), std::memory_order_release); return true; } /** * Returns the number of elements that the queue can hold. * @return */ constexpr size_t Capacity() const { return Length; } private: static constexpr size_t GetNextIndex(size_t pos) noexcept { return (++pos == bufferSize)? 0 : pos; } static constexpr size_t bufferSize = Length + 1; std::array buffer; std::atomic writerIndex{0}; std::atomic readerIndex{0}; }; } #endif /* SOURCE_UTIL_SIMPLESAFEQUEUE_H_ */ libeXaDrums-0.4.2/Util/Threading.h000066400000000000000000000026321354641705500167440ustar00rootroot00000000000000/* * Threading.h * * Created on: 11 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_THREADING_H_ #define SOURCE_UTIL_THREADING_H_ #include "Misc.h" #include #include #include #include namespace Util { static constexpr size_t minNbThreads = 3; // Minimum number of threads available to enable threads priority. /** * @brief Gives a relative priority to a thread, only if more than minNbThreads threads are available. * @param threadHandle Native handle of the thread object. * @param p Priority in percent: 0 = min, 100 = max. * @param schedType Type of scheduler. */ template static void SetThreadPriority(const T& threadHandle, int p, int schedType = SCHED_FIFO) { if(std::thread::hardware_concurrency() >= minNbThreads) { p = Util::clamp(p, 0, 100); auto maxPriority{sched_get_priority_max(SCHED_FIFO)}; size_t priority = static_cast((p * maxPriority) / 100); sched_param sch_params; sch_params.sched_priority = priority; pthread_setschedparam(threadHandle, schedType, &sch_params); } } class SpinLock { public: void lock() { while(locked.test_and_set(std::memory_order_acquire)) { ; } } void unlock() { locked.clear(std::memory_order_release); } private: std::atomic_flag locked = ATOMIC_FLAG_INIT; }; } #endif /* SOURCE_UTIL_THREADING_H_ */ libeXaDrums-0.4.2/Util/Time.h000066400000000000000000000023321354641705500157320ustar00rootroot00000000000000/* * Timing.h * * Created on: 15 Sep 2017 * Author: jeremy */ #ifndef SOURCE_UTIL_TIME_H_ #define SOURCE_UTIL_TIME_H_ #include #include #include namespace Util { /** * Converts a timestamp (int64_t for instance) in a string that contains the corresponding date. * @param timestamp * @return */ template static std::string TimeStampToStr(T timestamp) { using namespace std::chrono; auto tp = time_point{U{timestamp}}; auto time_t = system_clock::to_time_t(tp); auto result = std::string{std::ctime(&time_t)}; result.pop_back(); return result; } /** * Very useful to easily benchmark things using lambda functions as parameter. * @param f Callable to be executed. * @return Execution time in units of T. */ template static double GetTime(const Func& f) { using namespace std::chrono; auto t_start = high_resolution_clock::now(); f(); auto t_end = high_resolution_clock::now(); auto d = duration>(t_end - t_start); return d.count(); } } #endif /* SOURCE_UTIL_TIME_H_ */ libeXaDrums-0.4.2/Util/Xml.h000066400000000000000000000065021354641705500155770ustar00rootroot00000000000000/* * Xml.h * * Created on: 11 Feb 2018 * Author: jeremy */ #ifndef SOURCE_UTIL_XML_H_ #define SOURCE_UTIL_XML_H_ #include #include #include #include namespace Util { /** * Xml Element wrapper, very useful for range-based for loops. */ class XmlElement { public: XmlElement(tinyxml2::XMLElement* element_, const std::string& name_) : element{element_}, name{name_} {} XmlElement(tinyxml2::XMLElement* element_) : element{element_}, name{} {} inline XmlElement begin() const { if(name.empty()) { return XmlElement{element->FirstChildElement()}; } return XmlElement{element->FirstChildElement(name.data())}; } inline XmlElement end() const { return XmlElement{nullptr}; } inline XmlElement operator++() { if(name.empty()) { element = element->NextSiblingElement(); } else { element = element->NextSiblingElement(name.data()); } return *this; } inline XmlElement operator*() const { return *this; } inline bool operator!=(const XmlElement& xe) const { return element != xe.element; } inline const char* GetText() const { return element->GetText(); } template inline void GetValue(T& value) const { auto text = element->GetText(); if(text == nullptr) { value = T{}; return; } std::istringstream iss{text}; iss >> value; } template inline T GetValue() const { T value{}; GetValue(value); return value; } template inline void Attribute(const std::string& name, T& value) const { std::istringstream iss{element->Attribute(name.data())}; iss >> value; } template inline T Attribute(const std::string& name) const { T value{}; Attribute(name, value); return value; } inline XmlElement FirstChildElement(const std::string& childName) const { return XmlElement{element->FirstChildElement(childName.data())}; } private: tinyxml2::XMLElement* element; std::string name; }; /** * Structure that holds an xml attribute: a name and a value. */ struct XmlAttr { template XmlAttr(std::string name_, const T& val) : name(std::move(name_)) { std::ostringstream oss; oss << val; value = oss.str(); } std::string name; std::string value; }; /** * Creates a new xml element. * @param doc Xml document in which the xml element is to be inserted. * @param name Tag name of the xml element. * @param text Contents. * @param attributes Xml attributes. * @return */ template tinyxml2::XMLElement* CreateXmlElement(tinyxml2::XMLDocument& doc, const std::string name, const T& text = "", const std::vector& attributes = {}) { namespace xml = tinyxml2; xml::XMLElement* element = doc.NewElement(name.data()); std::ostringstream oss; oss << text; if(!oss.str().empty()) { element->SetText(oss.str().data()); } for(const auto& itAttr : attributes) { element->SetAttribute(itAttr.name.data(), itAttr.value.data()); } return element; } } #endif /* SOURCE_UTIL_XML_H_ */ libeXaDrums-0.4.2/configure.ac000066400000000000000000000016011354641705500162320ustar00rootroot00000000000000# Process this file with autoconf to produce configure. # Copyright (C) 2018-2019 Jérémy Oden # Copyright (C) 2018-2019 Nicolas Boulenguez # https://www.gnu.org/software/autoconf/manual/autoconf.html AC_INIT([libeXaDrums], [0.4.2], [Jérémy Oden ], [], [http://www.freewebmaster.fr]) AC_CONFIG_SRCDIR([Api/eXaDrums.cpp]) AC_PROG_CXX AC_CONFIG_MACRO_DIRS([m4]) AC_CONFIG_HEADERS([config.h]) # https://www.gnu.org/software/automake/manual/automake.html AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AM_PROG_AR # https://www.gnu.org/software/libtool/manual/libtool.html LT_INIT # https://autotools.io/pkgconfig/pkg_check_modules.html PKG_CHECK_MODULES([alsa], [alsa]) PKG_CHECK_MODULES([tinyxml2], [tinyxml2]) AC_CONFIG_FILES([ Makefile exadrums.pc Api/Version.h ]) AC_OUTPUT libeXaDrums-0.4.2/exadrums.pc.in000066400000000000000000000003631354641705500165310ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@prefix@ Name: @PACKAGE_NAME@ Description: The eXaDrums software drum module library URL: @PACKAGE_URL@ Version: @PACKAGE_VERSION@ Requires.private: alsa tinyxml2 Cflags: -I@includedir@ Libs: -L@libdir@ -lexadrums