...
 
Commits (16)
......@@ -75,22 +75,47 @@ add_library(amuse
include/amuse/VolumeTable.hpp
)
if(NX)
target_sources(amuse PRIVATE include/switch_math.hpp)
endif()
target_atdna(amuse atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
target_atdna(amuse atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
target_atdna(amuse atdna_AudioGroupSampleDirectory.cpp include/amuse/AudioGroupSampleDirectory.hpp)
target_include_directories(amuse PUBLIC include)
target_link_libraries(amuse athena-core ${ZLIB_LIBRARIES} lzokay)
target_link_libraries(amuse
athena-core
lzokay
${ZLIB_LIBRARIES}
)
if(NX)
target_sources(amuse PRIVATE include/switch_math.hpp)
endif()
if(TARGET boo)
target_sources(amuse PRIVATE lib/BooBackend.cpp include/amuse/BooBackend.hpp)
target_link_libraries(amuse boo)
endif()
if (NOT MSVC)
if (MSVC)
target_compile_options(amuse PRIVATE
# Enforce various standards compliant behavior.
/permissive-
# Enable standard volatile semantics.
/volatile:iso
# Reports the proper value for the __cplusplus preprocessor macro.
/Zc:__cplusplus
# Allow constexpr variables to have explicit external linkage.
/Zc:externConstexpr
# Assume that new throws exceptions, allowing better code generation.
/Zc:throwingNew
)
else()
target_compile_options(amuse PRIVATE -Wno-unknown-pragmas)
endif()
if(COMMAND add_sanitizers)
add_sanitizers(amuse)
endif()
......
......@@ -81,6 +81,25 @@ target_compile_definitions(amuse-gui PRIVATE
-DQT_USE_QSTRINGBUILDER
)
if (MSVC)
target_compile_options(amuse-gui PRIVATE
# Enforce various standards compliant behavior.
/permissive-
# Enable standard volatile semantics.
/volatile:iso
# Reports the proper value for the __cplusplus preprocessor macro.
/Zc:__cplusplus
# Allow constexpr variables to have explicit external linkage.
/Zc:externConstexpr
# Assume that new throws exceptions, allowing better code generation.
/Zc:throwingNew
)
endif()
if(WIN32)
target_sources(amuse-gui PRIVATE
platforms/win/amuse-gui.rc
......
......@@ -239,14 +239,15 @@ CommandWidget::CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, amus
break;
}
case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice: {
FieldComboBox* cb = new FieldComboBox(this);
auto* const cb = new FieldComboBox(this);
cb->setFixedHeight(30);
cb->setProperty("fieldIndex", f);
cb->setProperty("fieldName", fieldName);
for (int j = 0; j < 4; ++j) {
if (field.m_choices[j].empty())
for (const auto choice : field.m_choices) {
if (choice.empty()) {
break;
cb->addItem(tr(field.m_choices[j].data()));
}
cb->addItem(tr(choice.data()));
}
cb->setCurrentIndex(int(amuse::AccessField<int8_t>(m_cmd, field)));
connect(cb, qOverload<int>(&FieldComboBox::currentIndexChanged), this, &CommandWidget::numChanged);
......
......@@ -150,12 +150,12 @@ struct SoundMacro {
size_t m_offset;
std::string_view m_name;
int64_t m_min, m_max, m_default;
std::string_view m_choices[4];
std::array<std::string_view, 4> m_choices;
};
CmdType m_tp;
std::string_view m_name;
std::string_view m_description;
Field m_fields[7];
std::array<Field, 7> m_fields;
};
/** Base command interface. All versions of MusyX encode little-endian parameters */
......
......@@ -45,7 +45,7 @@ class Sequencer : public Entity {
/** State of a single MIDI channel */
struct ChannelState {
Sequencer* m_parent = nullptr;
uint8_t m_chanId;
uint8_t m_chanId = 0;
const SongGroupIndex::MIDISetup* m_setup = nullptr; /* Channel defaults to program 0 if null */
const SongGroupIndex::PageEntry* m_page = nullptr;
~ChannelState();
......@@ -57,14 +57,14 @@ class Sequencer : public Entity {
std::unordered_map<uint8_t, ObjToken<Voice>> m_chanVoxs;
std::unordered_set<ObjToken<Voice>> m_keyoffVoxs;
ObjToken<Voice> m_lastVoice;
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
int8_t m_pitchWheelRange = -1; /**< Pitch wheel range settable by RPN 0 */
int8_t m_curProgram = 0; /**< MIDI program number */
float m_curVol = 1.f; /**< Current volume of channel */
float m_curPan = 0.f; /**< Current panning of channel */
uint16_t m_rpn = 0; /**< Current RPN (only pitch-range 0x0000 supported) */
double m_ticksPerSec = 1000.0; /**< Current ticks per second (tempo) for channel */
std::array<int8_t, 128> m_ctrlVals{}; /**< MIDI controller values */
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
int8_t m_pitchWheelRange = -1; /**< Pitch wheel range settable by RPN 0 */
int8_t m_curProgram = 0; /**< MIDI program number */
float m_curVol = 1.f; /**< Current volume of channel */
float m_curPan = 0.f; /**< Current panning of channel */
uint16_t m_rpn = 0; /**< Current RPN (only pitch-range 0x0000 supported) */
double m_ticksPerSec = 1000.0; /**< Current ticks per second (tempo) for channel */
void _bringOutYourDead();
size_t getVoiceCount() const;
......
......@@ -18,7 +18,7 @@ class Studio {
std::list<StudioSend> m_studiosOut;
#ifndef NDEBUG
bool _cyclicCheck(Studio* leaf);
bool _cyclicCheck(const Studio* leaf) const;
#endif
public:
......
......@@ -37,41 +37,42 @@ struct MakeDefaultCmdOp {
static std::unique_ptr<SoundMacro::ICmd> Do(R& r) {
std::unique_ptr<SoundMacro::ICmd> ret = std::make_unique<Tp>();
if (const SoundMacro::CmdIntrospection* introspection = SoundMacro::GetCmdIntrospection(r)) {
for (int f = 0; f < 7; ++f) {
const amuse::SoundMacro::CmdIntrospection::Field& field = introspection->m_fields[f];
if (!field.m_name.empty()) {
switch (field.m_tp) {
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
AccessField<bool>(ret.get(), field) = bool(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int8:
case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice:
AccessField<int8_t>(ret.get(), field) = int8_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt8:
AccessField<uint8_t>(ret.get(), field) = uint8_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int16:
AccessField<int16_t>(ret.get(), field) = int16_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt16:
AccessField<uint16_t>(ret.get(), field) = uint16_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32:
AccessField<int32_t>(ret.get(), field) = int32_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32:
AccessField<uint32_t>(ret.get(), field) = uint32_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId:
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroStep:
case amuse::SoundMacro::CmdIntrospection::Field::Type::TableId:
case amuse::SoundMacro::CmdIntrospection::Field::Type::SampleId:
AccessField<SoundMacroIdDNA<athena::Endian::Little>>(ret.get(), field).id = uint16_t(field.m_default);
break;
default:
break;
}
for (const auto& field : introspection->m_fields) {
if (field.m_name.empty()) {
continue;
}
switch (field.m_tp) {
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
AccessField<bool>(ret.get(), field) = bool(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int8:
case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice:
AccessField<int8_t>(ret.get(), field) = int8_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt8:
AccessField<uint8_t>(ret.get(), field) = uint8_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int16:
AccessField<int16_t>(ret.get(), field) = int16_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt16:
AccessField<uint16_t>(ret.get(), field) = uint16_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32:
AccessField<int32_t>(ret.get(), field) = int32_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32:
AccessField<uint32_t>(ret.get(), field) = uint32_t(field.m_default);
break;
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId:
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroStep:
case amuse::SoundMacro::CmdIntrospection::Field::Type::TableId:
case amuse::SoundMacro::CmdIntrospection::Field::Type::SampleId:
AccessField<SoundMacroIdDNA<athena::Endian::Little>>(ret.get(), field).id = uint16_t(field.m_default);
break;
default:
break;
}
}
}
......
......@@ -53,7 +53,7 @@ Sequencer::~Sequencer() {
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, GroupId groupId, const SongGroupIndex* songGroup,
SongId setupId, ObjToken<Studio> studio)
: Entity(engine, group, groupId), m_songGroup(songGroup), m_studio(studio) {
: Entity(engine, group, groupId), m_songGroup(songGroup), m_studio(std::move(studio)) {
auto it = m_songGroup->m_midiSetups.find(setupId);
if (it != m_songGroup->m_midiSetups.cend())
m_midiSetup = it->second.data();
......@@ -61,7 +61,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, GroupId groupId, c
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, GroupId groupId, const SFXGroupIndex* sfxGroup,
ObjToken<Studio> studio)
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup), m_studio(studio) {
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup), m_studio(std::move(studio)) {
std::map<ObjectId, const SFXGroupIndex::SFXEntry*> sortSFX;
for (const auto& sfx : sfxGroup->m_sfxEntries)
sortSFX[sfx.first] = &sfx.second;
......@@ -71,7 +71,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, GroupId groupId, c
m_sfxMappings.push_back(sfx.second);
}
Sequencer::ChannelState::~ChannelState() {}
Sequencer::ChannelState::~ChannelState() = default;
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_parent(&parent), m_chanId(chanId) {
if (m_parent->m_songGroup) {
......@@ -208,7 +208,7 @@ ObjToken<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity) {
if (*ret) {
(*ret)->m_sequencer = m_parent;
m_chanVoxs[note] = *ret;
(*ret)->installCtrlValues(m_ctrlVals);
(*ret)->installCtrlValues(m_ctrlVals.data());
ObjectId oid;
bool res;
......@@ -246,11 +246,13 @@ ObjToken<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity) {
}
ObjToken<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velocity) {
if (chan > 15)
if (chan >= m_chanStates.size()) {
return {};
}
if (!m_chanStates[chan])
if (!m_chanStates[chan]) {
m_chanStates[chan] = ChannelState(*this, chan);
}
return m_chanStates[chan].keyOn(note, velocity);
}
......@@ -268,8 +270,9 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity) {
}
void Sequencer::keyOff(uint8_t chan, uint8_t note, uint8_t velocity) {
if (chan > 15 || !m_chanStates[chan])
if (chan >= m_chanStates.size() || !m_chanStates[chan]) {
return;
}
m_chanStates[chan].keyOff(note, velocity);
}
......@@ -351,8 +354,9 @@ void Sequencer::ChannelState::prevProgram() {
}
void Sequencer::setCtrlValue(uint8_t chan, uint8_t ctrl, int8_t val) {
if (chan > 15)
if (chan >= m_chanStates.size()) {
return;
}
if (ctrl == 0x66) {
fmt::print(fmt("Loop Start\n"));
......@@ -360,8 +364,9 @@ void Sequencer::setCtrlValue(uint8_t chan, uint8_t ctrl, int8_t val) {
fmt::print(fmt("Loop End\n"));
}
if (!m_chanStates[chan])
if (!m_chanStates[chan]) {
m_chanStates[chan] = ChannelState(*this, chan);
}
m_chanStates[chan].setCtrlValue(ctrl, val);
}
......@@ -375,11 +380,13 @@ void Sequencer::ChannelState::setPitchWheel(float pitchWheel) {
}
void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel) {
if (chan > 15)
if (chan >= m_chanStates.size()) {
return;
}
if (!m_chanStates[chan])
if (!m_chanStates[chan]) {
m_chanStates[chan] = ChannelState(*this, chan);
}
m_chanStates[chan].setPitchWheel(pitchWheel);
}
......@@ -422,18 +429,22 @@ void Sequencer::allOff(bool now) {
}
void Sequencer::allOff(uint8_t chan, bool now) {
if (chan > 15 || !m_chanStates[chan])
if (chan >= m_chanStates.size() || !m_chanStates[chan]) {
return;
}
if (now) {
for (const auto& vox : m_chanStates[chan].m_chanVoxs)
for (const auto& vox : m_chanStates[chan].m_chanVoxs) {
vox.second->kill();
for (const auto& vox : m_chanStates[chan].m_keyoffVoxs)
}
for (const auto& vox : m_chanStates[chan].m_keyoffVoxs) {
vox->kill();
}
m_chanStates[chan].m_chanVoxs.clear();
m_chanStates[chan].m_keyoffVoxs.clear();
} else
} else {
m_chanStates[chan].allOff();
}
}
void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now) {
......@@ -575,12 +586,14 @@ void Sequencer::setVolume(float vol, float fadeTime) {
}
int8_t Sequencer::getChanProgram(int8_t chanId) const {
if (chanId > 15)
if (static_cast<size_t>(chanId) >= m_chanStates.size()) {
return 0;
}
if (!m_chanStates[chanId]) {
if (!m_midiSetup)
if (!m_midiSetup) {
return 0;
}
return m_midiSetup[chanId].programNo;
}
......@@ -588,31 +601,37 @@ int8_t Sequencer::getChanProgram(int8_t chanId) const {
}
bool Sequencer::setChanProgram(int8_t chanId, int8_t prog) {
if (chanId > 15)
if (static_cast<size_t>(chanId) >= m_chanStates.size()) {
return false;
}
if (!m_chanStates[chanId])
if (!m_chanStates[chanId]) {
m_chanStates[chanId] = ChannelState(*this, chanId);
}
return m_chanStates[chanId].programChange(prog);
}
void Sequencer::nextChanProgram(int8_t chanId) {
if (chanId > 15)
if (static_cast<size_t>(chanId) >= m_chanStates.size()) {
return;
}
if (!m_chanStates[chanId])
if (!m_chanStates[chanId]) {
m_chanStates[chanId] = ChannelState(*this, chanId);
}
return m_chanStates[chanId].nextProgram();
}
void Sequencer::prevChanProgram(int8_t chanId) {
if (chanId > 15)
if (static_cast<size_t>(chanId) >= m_chanStates.size()) {
return;
}
if (!m_chanStates[chanId])
if (!m_chanStates[chanId]) {
m_chanStates[chanId] = ChannelState(*this, chanId);
}
return m_chanStates[chanId].prevProgram();
}
......
#include "amuse/Studio.hpp"
#include <algorithm>
#include "amuse/Engine.hpp"
namespace amuse {
#ifndef NDEBUG
bool Studio::_cyclicCheck(Studio* leaf) {
for (auto it = m_studiosOut.begin(); it != m_studiosOut.end();) {
if (leaf == it->m_targetStudio.get() || it->m_targetStudio->_cyclicCheck(leaf))
return true;
++it;
}
return false;
bool Studio::_cyclicCheck(const Studio* leaf) const {
return std::any_of(m_studiosOut.cbegin(), m_studiosOut.cend(), [leaf](const auto& studio) {
return leaf == studio.m_targetStudio.get() || studio.m_targetStudio->_cyclicCheck(leaf);
});
}
#endif
......@@ -20,7 +20,7 @@ Studio::Studio(Engine& engine, bool mainOut) : m_engine(engine), m_master(engine
}
void Studio::addStudioSend(ObjToken<Studio> studio, float dry, float auxA, float auxB) {
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
m_studiosOut.emplace_back(std::move(studio), dry, auxA, auxB);
/* Cyclic check */
assert(!_cyclicCheck(this));
......
#include "amuse/VolumeTable.hpp"
#include <algorithm>
#include <array>
#include <cmath>
#include "amuse/Common.hpp"
namespace amuse {
static const float VolumeTable[] = {
constexpr std::array<float, 129> VolumeTable{
0.000000f, 0.000031f, 0.000153f, 0.000397f, 0.000702f, 0.001129f, 0.001648f, 0.002228f, 0.002930f, 0.003723f,
0.004608f, 0.005585f, 0.006653f, 0.007843f, 0.009125f, 0.010498f, 0.011963f, 0.013550f, 0.015198f, 0.016999f,
0.018860f, 0.020844f, 0.022919f, 0.025117f, 0.027406f, 0.029817f, 0.032319f, 0.034944f, 0.037660f, 0.040468f,
......@@ -19,9 +19,10 @@ static const float VolumeTable[] = {
0.452864f, 0.464217f, 0.475753f, 0.487442f, 0.499313f, 0.511399f, 0.523606f, 0.536027f, 0.548631f, 0.561419f,
0.574389f, 0.587542f, 0.600879f, 0.614399f, 0.628132f, 0.642018f, 0.656148f, 0.670431f, 0.684927f, 0.699637f,
0.714530f, 0.729637f, 0.744926f, 0.760430f, 0.776147f, 0.792077f, 0.808191f, 0.824549f, 0.841090f, 0.857845f,
0.874844f, 0.892056f, 0.909452f, 0.927122f, 0.945006f, 0.963073f, 0.981414f, 1.000000f, 1.000000f};
0.874844f, 0.892056f, 0.909452f, 0.927122f, 0.945006f, 0.963073f, 0.981414f, 1.000000f, 1.000000f,
};
static const float DLSVolumeTable[] = {
constexpr std::array<float, 129> DLSVolumeTable{
0.000000f, 0.000062f, 0.000248f, 0.000558f, 0.000992f, 0.001550f, 0.002232f, 0.003038f, 0.003968f, 0.005022f,
0.006200f, 0.007502f, 0.008928f, 0.010478f, 0.012152f, 0.013950f, 0.015872f, 0.017918f, 0.020088f, 0.022382f,
0.024800f, 0.027342f, 0.030008f, 0.032798f, 0.035712f, 0.038750f, 0.041912f, 0.045198f, 0.048608f, 0.052142f,
......@@ -34,7 +35,8 @@ static const float DLSVolumeTable[] = {
0.502201f, 0.513423f, 0.524769f, 0.536239f, 0.547833f, 0.559551f, 0.571393f, 0.583359f, 0.595449f, 0.607663f,
0.620001f, 0.632463f, 0.645049f, 0.657759f, 0.670593f, 0.683551f, 0.696633f, 0.709839f, 0.723169f, 0.736623f,
0.750202f, 0.763904f, 0.777730f, 0.791680f, 0.805754f, 0.819952f, 0.834274f, 0.848720f, 0.863290f, 0.877984f,
0.892802f, 0.907744f, 0.922810f, 0.938000f, 0.953314f, 0.968752f, 0.984314f, 1.000000f, 1.000000f};
0.892802f, 0.907744f, 0.922810f, 0.938000f, 0.953314f, 0.968752f, 0.984314f, 1.000000f, 1.000000f,
};
float LookupVolume(float vol) {
vol = std::clamp(vol * 127.f, 0.f, 127.f);
......