Compare commits
64 Commits
v1.13
...
77c7daa67c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77c7daa67c | ||
| e3c936648b | |||
|
|
1fefba66e7 | ||
|
|
594fb346e1 | ||
|
|
3833c137f6 | ||
|
|
912eb7950c | ||
| 4146cdd049 | |||
|
|
f5a0a46453 | ||
|
|
8f94bdd488 | ||
|
|
f37296d560 | ||
| fd292491c7 | |||
|
|
380381c7d1 | ||
|
|
3f9a91b0ab | ||
|
|
985994a291 | ||
|
|
e37128d657 | ||
|
|
4c2a262478 | ||
|
|
3eba4cc1ac | ||
|
|
91b88c0568 | ||
|
|
6f7d09ce45 | ||
|
|
5caf6bf017 | ||
|
|
d399f1d302 | ||
|
|
77215fc996 | ||
|
|
2f4d0e7541 | ||
|
|
89233e98b5 | ||
|
|
b890a76e20 | ||
|
|
3c7cf5515f | ||
|
|
ebe6f18898 | ||
|
|
cab7402104 | ||
|
|
862c618b7e | ||
|
|
448b212ad9 | ||
|
|
03d597b0ac | ||
|
|
75830dc6dd | ||
|
|
e18c0a62de | ||
|
|
047a91452e | ||
|
|
fdf07d6c33 | ||
|
|
4b2b86f420 | ||
|
|
c6781df90a | ||
|
|
aef2b2a707 | ||
| 0bace131e8 | |||
|
|
4e7c31849d | ||
|
|
3d56d5f0cc | ||
| 54bbc7399a | |||
|
|
a23af16349 | ||
|
|
5c8fa2e8ab | ||
|
|
aff8880595 | ||
|
|
2e7345f11d | ||
|
|
ecd990e94e | ||
|
|
2836e73812 | ||
|
|
df167556fb | ||
|
|
72d0df7d46 | ||
|
|
1dfdf4c392 | ||
|
|
9cf96ad6f9 | ||
|
|
eb948dfd63 | ||
| c886bfd7d2 | |||
|
|
3fd3f3edc5 | ||
|
|
7cb7ed73ea | ||
|
|
2521f37408 | ||
|
|
bfe6668d0c | ||
|
|
38f24ce3e4 | ||
|
|
218fad7541 | ||
| af68ee61e1 | |||
| b40b2c031a | |||
| aa32ff7e84 | |||
|
|
28cac7ff83 |
@@ -22,7 +22,6 @@ AlwaysBreakAfterDefinitionReturnType: None
|
|||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: All
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
ReflowComments: true
|
|
||||||
BinPackArguments: true
|
BinPackArguments: true
|
||||||
BinPackParameters: true
|
BinPackParameters: true
|
||||||
SortIncludes: false
|
SortIncludes: false
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
<string>group.com.axiodl.Amuse.AudioGroups</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
|
|
||||||
- (void)pumpTimer:(NSTimer*)timer
|
- (void)pumpTimer:(NSTimer*)timer
|
||||||
{
|
{
|
||||||
amuseEngine->pumpEngine();
|
booEngine->pumpAndMixVoices();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
{
|
{
|
||||||
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
||||||
if (result == NSFileHandlingPanelOKButton)
|
if (result == NSModalResponseOK)
|
||||||
{
|
{
|
||||||
[self importURL:panel.URL];
|
[self importURL:panel.URL];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
<string>group.com.axiodl.Amuse.AudioGroups</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ struct AudioGroupDataCollection
|
|||||||
bool loadSamp(AudioGroupFilePresenter* presenter);
|
bool loadSamp(AudioGroupFilePresenter* presenter);
|
||||||
bool loadMeta(AudioGroupFilePresenter* presenter);
|
bool loadMeta(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
AudioGroupDataCollection(std::string_view name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
||||||
bool isDataComplete() const
|
bool isDataComplete() const
|
||||||
{
|
{
|
||||||
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
|
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
|
||||||
@@ -88,7 +88,7 @@ struct AudioGroupCollection
|
|||||||
void addCollection(AudioGroupFilePresenter* presenter,
|
void addCollection(AudioGroupFilePresenter* presenter,
|
||||||
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void update(AudioGroupFilePresenter* presenter);
|
void update(AudioGroupFilePresenter* presenter);
|
||||||
bool doSearch(const std::string& str);
|
bool doSearch(std::string_view str);
|
||||||
bool doActiveFilter();
|
bool doActiveFilter();
|
||||||
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
||||||
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
||||||
|
|||||||
@@ -161,13 +161,13 @@ void AudioGroupCollection::update(AudioGroupFilePresenter* presenter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGroupCollection::doSearch(const std::string& str)
|
bool AudioGroupCollection::doSearch(std::string_view str)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
m_filterGroups.clear();
|
m_filterGroups.clear();
|
||||||
m_filterGroups.reserve(m_groups.size());
|
m_filterGroups.reserve(m_groups.size());
|
||||||
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
if (str.empty() || StrToLower(it->first).find(str) != std::string::npos)
|
if (str.empty() || StrToLower(it->first).find(str.data()) != std::string::npos)
|
||||||
{
|
{
|
||||||
m_filterGroups.push_back(it);
|
m_filterGroups.push_back(it);
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -239,7 +239,7 @@ void AudioGroupCollection::addSamples(std::vector<AudioGroupSampleToken*>& vecOu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool,
|
AudioGroupDataCollection::AudioGroupDataCollection(std::string_view name, NSURL* proj, NSURL* pool,
|
||||||
NSURL* sdir, NSURL* samp, NSURL* meta)
|
NSURL* sdir, NSURL* samp, NSURL* meta)
|
||||||
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
||||||
m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {}
|
m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {}
|
||||||
@@ -849,7 +849,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
||||||
{
|
{
|
||||||
m_audioGroupClient = client;
|
m_audioGroupClient = client;
|
||||||
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.axiodl.Amuse.AudioGroups"];
|
||||||
if (!m_groupURL)
|
if (!m_groupURL)
|
||||||
return nil;
|
return nil;
|
||||||
[NSFileCoordinator addFilePresenter:self];
|
[NSFileCoordinator addFilePresenter:self];
|
||||||
|
|||||||
@@ -112,11 +112,13 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
|||||||
m_mixInfo.m_periodFrames = periodFrames;
|
m_mixInfo.m_periodFrames = periodFrames;
|
||||||
m_mixInfo.m_sampleRate = sampleRate;
|
m_mixInfo.m_sampleRate = sampleRate;
|
||||||
_buildAudioRenderClient();
|
_buildAudioRenderClient();
|
||||||
|
|
||||||
for (boo::AudioVoice* vox : m_activeVoices)
|
if (m_voiceHead)
|
||||||
vox->_resetSampleRate(vox->m_sampleRateIn);
|
for (boo::AudioVoice& vox : *m_voiceHead)
|
||||||
for (boo::AudioSubmix* smx : m_activeSubmixes)
|
vox._resetSampleRate(vox.m_sampleRateIn);
|
||||||
smx->_resetOutputSampleRate();
|
if (m_submixHead)
|
||||||
|
for (boo::AudioSubmix& smx : *m_submixHead)
|
||||||
|
smx._resetOutputSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pumpAndMixVoices()
|
void pumpAndMixVoices()
|
||||||
@@ -281,7 +283,7 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
|||||||
/* Output buffers */
|
/* Output buffers */
|
||||||
voxEngine.m_renderFrames = frameCount;
|
voxEngine.m_renderFrames = frameCount;
|
||||||
voxEngine.m_outputData = outputData;
|
voxEngine.m_outputData = outputData;
|
||||||
amuseEngine.pumpEngine();
|
voxEngine.pumpAndMixVoices();
|
||||||
return noErr;
|
return noErr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,109 +1,113 @@
|
|||||||
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
|
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
|
||||||
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
|
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
|
||||||
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
|
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
|
||||||
find_library(AVFOUNDATION_LIBRARY AVFoundation)
|
if (APPLE_DEV_ID AND APPLE_TEAM_ID)
|
||||||
find_library(AUDIOUNIT_LIBRARY AudioUnit)
|
find_library(AVFOUNDATION_LIBRARY AVFoundation)
|
||||||
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
|
find_library(AUDIOUNIT_LIBRARY AudioUnit)
|
||||||
if (NOT (AUDIOUNIT_LIBRARY STREQUAL AUDIOUNIT_LIBRARY-NOTFOUND))
|
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
|
||||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}")
|
if (NOT (AUDIOUNIT_LIBRARY STREQUAL AUDIOUNIT_LIBRARY-NOTFOUND))
|
||||||
|
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
|
||||||
# Search for provision profile to make AudioUnit extension on OS X
|
# Search for provision profile to make AudioUnit extension on OS X
|
||||||
unset(PROV_PROFILE)
|
unset(PROV_PROFILE)
|
||||||
file(GLOB PROV_FILES "$ENV{HOME}/Library/MobileDevice/Provisioning Profiles/*.provisionprofile")
|
file(GLOB PROV_FILES "$ENV{HOME}/Library/MobileDevice/Provisioning Profiles/*.provisionprofile")
|
||||||
foreach(FILE ${PROV_FILES})
|
foreach(FILE ${PROV_FILES})
|
||||||
file(STRINGS "${FILE}" NAME REGEX ${APPLE_TEAM_ID})
|
file(STRINGS "${FILE}" NAME REGEX ${APPLE_TEAM_ID})
|
||||||
if(NAME)
|
if(NAME)
|
||||||
set(PROV_PROFILE "${FILE}")
|
set(PROV_PROFILE "${FILE}")
|
||||||
break()
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(EXISTS "${PROV_PROFILE}")
|
||||||
|
|
||||||
|
# Extension App
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
COMMAND ibtool --errors --warnings --notices --module amuse_au --auto-activate-custom-fonts
|
||||||
|
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
)
|
||||||
|
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
AudioUnitViewController.nib)
|
||||||
|
|
||||||
|
set(APPLE_BUNDLE_ID "com.axiodl.Amuse.AudioUnit")
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
|
||||||
|
|
||||||
|
target_link_libraries(amuse-au amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
||||||
|
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
|
||||||
|
set_target_properties(amuse-au PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ExtensionInfo.plist"
|
||||||
|
BUNDLE_EXTENSION "appex" BUNDLE TRUE
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}"
|
||||||
|
LINK_FLAGS "-e _NSExtensionMain -fobjc-arc -fobjc-link-runtime -fapplication-extension")
|
||||||
|
|
||||||
|
|
||||||
|
# Containing App
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
|
||||||
|
COMMAND ibtool --errors --warnings --notices --module amuse_au_container --auto-activate-custom-fonts
|
||||||
|
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
|
)
|
||||||
|
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.hpp AmuseContainingApp.mm
|
||||||
|
AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
AmuseContainerMainMenu.nib)
|
||||||
|
set_source_files_properties(AudioUnitBackend.mm AudioUnitViewController.mm
|
||||||
|
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
||||||
|
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
|
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
||||||
|
${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${LZO_LIB} ${BOO_SYS_LIBS} logvisor athena-core)
|
||||||
|
|
||||||
|
set(APPLE_BUNDLE_ID "com.axiodl.Amuse")
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
|
||||||
|
|
||||||
|
set_target_properties(amuse-au-container PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ContainerInfo.plist"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
||||||
|
|
||||||
|
add_custom_command(TARGET amuse-au POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib"
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au>/../Resources/AudioUnitViewController.nib"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
||||||
|
COMMAND codesign --force --sign
|
||||||
|
${APPLE_DEV_ID} --entitlements "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
||||||
|
COMMAND codesign --force --sign ${APPLE_DEV_ID}
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au-container>/../.."
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(TARGET amuse-au-container POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib"
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au-container>/../Resources/AmuseContainerMainMenu.nib"
|
||||||
|
COMMAND codesign --force --sign
|
||||||
|
${APPLE_DEV_ID} "$<TARGET_FILE_DIR:amuse-au-container>/../.."
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
else()
|
||||||
|
message(WARNING "Unable to find developer provisioning profile; skipping Amuse-AU")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(EXISTS "${PROV_PROFILE}")
|
|
||||||
|
|
||||||
# Extension App
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
|
||||||
COMMAND ibtool --errors --warnings --notices --module amuse_au --auto-activate-custom-fonts
|
|
||||||
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
|
||||||
)
|
|
||||||
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
|
||||||
AudioUnitViewController.nib)
|
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
|
|
||||||
|
|
||||||
target_link_libraries(amuse-au amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
|
||||||
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
|
|
||||||
set_target_properties(amuse-au PROPERTIES
|
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ExtensionInfo.plist"
|
|
||||||
BUNDLE_EXTENSION "appex" BUNDLE TRUE
|
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
|
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}"
|
|
||||||
LINK_FLAGS "-e _NSExtensionMain -fobjc-arc -fobjc-link-runtime -fapplication-extension")
|
|
||||||
|
|
||||||
|
|
||||||
# Containing App
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
|
|
||||||
COMMAND ibtool --errors --warnings --notices --module amuse_au_container --auto-activate-custom-fonts
|
|
||||||
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
|
||||||
)
|
|
||||||
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.hpp AmuseContainingApp.mm
|
|
||||||
AudioUnitBackend.hpp AudioUnitBackend.mm
|
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
|
||||||
AmuseContainerMainMenu.nib)
|
|
||||||
set_source_files_properties(AudioUnitBackend.mm AudioUnitViewController.mm
|
|
||||||
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
|
||||||
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
|
||||||
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
|
||||||
${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS} logvisor athena-core)
|
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
|
|
||||||
|
|
||||||
set_target_properties(amuse-au-container PROPERTIES
|
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ContainerInfo.plist"
|
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements"
|
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
|
||||||
|
|
||||||
add_custom_command(TARGET amuse-au POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib"
|
|
||||||
"$<TARGET_FILE_DIR:amuse-au>/../Resources/AudioUnitViewController.nib"
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
|
||||||
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
|
||||||
COMMAND codesign --force --sign
|
|
||||||
${APPLE_DEV_ID} --entitlements "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
|
|
||||||
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
|
||||||
COMMAND codesign --force --sign ${APPLE_DEV_ID}
|
|
||||||
"$<TARGET_FILE_DIR:amuse-au-container>/../.."
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(TARGET amuse-au-container POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib"
|
|
||||||
"$<TARGET_FILE_DIR:amuse-au-container>/../Resources/AmuseContainerMainMenu.nib"
|
|
||||||
COMMAND codesign --force --sign
|
|
||||||
${APPLE_DEV_ID} "$<TARGET_FILE_DIR:amuse-au-container>/../.."
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
|
|
||||||
else()
|
|
||||||
message(WARNING "Unable to find developer provision profile; skipping Amuse-AU")
|
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "APPLE_DEV_ID and/or APPLE_TEAM_ID not set; skipping Amuse-AU")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>io.github.axiodl.Amuse</string>
|
<string>com.axiodl.Amuse</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>amuse-au</string>
|
<string>amuse-au</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>io.github.axiodl.Amuse.AudioUnit</string>
|
<string>com.axiodl.Amuse.AudioUnit</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
|
||||||
|
|
||||||
project(amuse)
|
project(amuse)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/boo AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/athena)
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/boo AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/athena)
|
||||||
message(STATUS "Preparing standalone build")
|
message(STATUS "Preparing standalone build")
|
||||||
if (NOT MSVC)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wno-narrowing")
|
|
||||||
endif()
|
|
||||||
add_subdirectory(boo)
|
add_subdirectory(boo)
|
||||||
add_subdirectory(athena)
|
add_subdirectory(athena)
|
||||||
include_directories(athena/include)
|
include_directories(athena/include)
|
||||||
@@ -27,13 +32,11 @@ set(SOURCES
|
|||||||
lib/SongConverter.cpp
|
lib/SongConverter.cpp
|
||||||
lib/SongState.cpp
|
lib/SongState.cpp
|
||||||
lib/Voice.cpp
|
lib/Voice.cpp
|
||||||
lib/VolumeLUT.c
|
|
||||||
lib/Submix.cpp
|
lib/Submix.cpp
|
||||||
lib/Studio.cpp
|
lib/Studio.cpp
|
||||||
lib/EffectReverb.cpp
|
lib/EffectReverb.cpp
|
||||||
lib/EffectChorus.cpp
|
lib/EffectChorus.cpp
|
||||||
lib/EffectDelay.cpp
|
lib/EffectDelay.cpp
|
||||||
lib/SurroundProfiles.cpp
|
|
||||||
lib/ContainerRegistry.cpp
|
lib/ContainerRegistry.cpp
|
||||||
lib/DSPCodec.c
|
lib/DSPCodec.c
|
||||||
lib/N64MusyXCodec.c)
|
lib/N64MusyXCodec.c)
|
||||||
@@ -64,7 +67,6 @@ set(HEADERS
|
|||||||
include/amuse/EffectReverb.hpp
|
include/amuse/EffectReverb.hpp
|
||||||
include/amuse/EffectChorus.hpp
|
include/amuse/EffectChorus.hpp
|
||||||
include/amuse/EffectDelay.hpp
|
include/amuse/EffectDelay.hpp
|
||||||
include/amuse/SurroundProfiles.hpp
|
|
||||||
include/amuse/ContainerRegistry.hpp
|
include/amuse/ContainerRegistry.hpp
|
||||||
include/amuse/Common.hpp
|
include/amuse/Common.hpp
|
||||||
include/amuse/amuse.hpp
|
include/amuse/amuse.hpp
|
||||||
@@ -74,7 +76,7 @@ set(HEADERS
|
|||||||
unset(EXTRAS)
|
unset(EXTRAS)
|
||||||
if(TARGET boo)
|
if(TARGET boo)
|
||||||
include_directories(${BOO_INCLUDE_DIR} ${BOO_INCLUDE_DIR}/../lib ${BOO_INCLUDE_DIR}/../soxr/src
|
include_directories(${BOO_INCLUDE_DIR} ${BOO_INCLUDE_DIR}/../lib ${BOO_INCLUDE_DIR}/../soxr/src
|
||||||
${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${LZO_INCLUDE_DIR})
|
||||||
list(APPEND EXTRAS lib/BooBackend.cpp include/amuse/BooBackend.hpp)
|
list(APPEND EXTRAS lib/BooBackend.cpp include/amuse/BooBackend.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -85,8 +87,15 @@ add_library(amuse
|
|||||||
${SOURCES}
|
${SOURCES}
|
||||||
${HEADERS}
|
${HEADERS}
|
||||||
${EXTRAS})
|
${EXTRAS})
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuse)
|
||||||
|
endif()
|
||||||
|
if(COMMAND cotire)
|
||||||
|
set_target_properties(amuse PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(amuse)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(TARGET boo)
|
if(TARGET boo AND NOT WINDOWS_STORE)
|
||||||
# AudioUnit Target (OS X only)
|
# AudioUnit Target (OS X only)
|
||||||
add_subdirectory(AudioUnit)
|
add_subdirectory(AudioUnit)
|
||||||
|
|
||||||
@@ -97,13 +106,28 @@ if(TARGET boo)
|
|||||||
|
|
||||||
# Player
|
# Player
|
||||||
add_executable(amuseplay WIN32 driver/amuseplay.cpp)
|
add_executable(amuseplay WIN32 driver/amuseplay.cpp)
|
||||||
target_link_libraries(amuseplay amuse boo ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
|
target_link_libraries(amuseplay amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
# Converter
|
# Converter
|
||||||
add_executable(amuseconv driver/amuseconv.cpp)
|
add_executable(amuseconv driver/amuseconv.cpp)
|
||||||
target_link_libraries(amuseconv amuse ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
|
target_link_libraries(amuseconv amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
# Renderer
|
# Renderer
|
||||||
add_executable(amuserender driver/amuserender.cpp)
|
add_executable(amuserender driver/amuserender.cpp)
|
||||||
target_link_libraries(amuserender amuse boo ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
|
target_link_libraries(amuserender amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuseplay)
|
||||||
|
add_sanitizers(amuseconv)
|
||||||
|
add_sanitizers(amuserender)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
find_package(Qt5Widgets)
|
||||||
|
if (Qt5Widgets_FOUND)
|
||||||
|
message(STATUS "Qt5 found, amuse-gui will be built")
|
||||||
|
add_subdirectory(Editor)
|
||||||
|
else()
|
||||||
|
message(STATUS "Qt5 not found, amuse-gui will not be built")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
35
Editor/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
find_package(Qt5Widgets)
|
||||||
|
find_package(Qt5Network)
|
||||||
|
find_package(Qt5Xml)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND PLAT_SRCS platforms/win/amuse-gui.rc platforms/win/amuse-gui.manifest)
|
||||||
|
elseif(APPLE)
|
||||||
|
list(APPEND PLAT_SRCS platforms/mac/mainicon.icns)
|
||||||
|
set_source_files_properties(platforms/mac/mainicon.icns PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(platforms/freedesktop)
|
||||||
|
declare_qticon_target()
|
||||||
|
list(APPEND PLAT_SRCS mainicon_qt.cpp)
|
||||||
|
|
||||||
|
add_executable(amuse-gui WIN32 MACOSX_BUNDLE
|
||||||
|
MainWindow.ui MainWindow.hpp MainWindow.cpp
|
||||||
|
${PLAT_SRCS}
|
||||||
|
main.cpp)
|
||||||
|
|
||||||
|
set_target_properties(amuse-gui PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
|
||||||
|
|
||||||
|
target_link_libraries(amuse-gui ${PLAT_LIBS}
|
||||||
|
${Qt5Widgets_LIBRARIES}
|
||||||
|
${Qt5Network_LIBRARIES}
|
||||||
|
${Qt5Xml_LIBRARIES}
|
||||||
|
boo logvisor zeus athena-core athena-libyaml xxhash z)
|
||||||
5
Editor/MainWindow.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by Jack Andersen on 3/5/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MainWindow.hpp"
|
||||||
15
Editor/MainWindow.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by Jack Andersen on 3/5/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef URDE_MAINWINDOW_HPP
|
||||||
|
#define URDE_MAINWINDOW_HPP
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //URDE_MAINWINDOW_HPP
|
||||||
24
Editor/MainWindow.ui
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<author></author>
|
||||||
|
<comment></comment>
|
||||||
|
<exportmacro></exportmacro>
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenuBar" name="menubar" />
|
||||||
|
<widget class="QWidget" name="centralwidget" />
|
||||||
|
<widget class="QStatusBar" name="statusbar" />
|
||||||
|
</widget>
|
||||||
|
<pixmapfunction></pixmapfunction>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
8
Editor/main.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
//
|
||||||
|
// Created by Jack Andersen on 3/5/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// TODO: Do
|
||||||
|
}
|
||||||
BIN
Editor/platforms/freedesktop/1024x1024/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
Editor/platforms/freedesktop/128x128/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Editor/platforms/freedesktop/16x16/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 924 B |
BIN
Editor/platforms/freedesktop/256x256/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
Editor/platforms/freedesktop/32x32/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Editor/platforms/freedesktop/48x48/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
Editor/platforms/freedesktop/512x512/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
Editor/platforms/freedesktop/64x64/apps/amuse.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
18
Editor/platforms/freedesktop/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
include_directories(${LIBPNG_INCLUDE_DIR})
|
||||||
|
add_executable(amuse-mkqticon mkqticon.c)
|
||||||
|
target_link_libraries(amuse-mkqticon ${PNG_LIB} ${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
|
macro(declare_qticon_target)
|
||||||
|
add_custom_command(OUTPUT ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin
|
||||||
|
COMMAND $<TARGET_FILE:amuse-mkqticon>
|
||||||
|
ARGS ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin
|
||||||
|
DEPENDS
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/128x128/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/64x64/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/48x48/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/32x32/apps/amuse.png
|
||||||
|
${amuse_SOURCE_DIR}/Editor/platforms/freedesktop/16x16/apps/amuse.png
|
||||||
|
WORKING_DIRECTORY ${amuse_SOURCE_DIR}/Editor/platforms/freedesktop
|
||||||
|
COMMENT "Generating mainicon_qt.bin")
|
||||||
|
bintoc(mainicon_qt.cpp ${amuse_BINARY_DIR}/Editor/platforms/freedesktop/mainicon_qt.bin MAINICON_QT)
|
||||||
|
endmacro()
|
||||||
9
Editor/platforms/freedesktop/amuse.desktop
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=Amuse
|
||||||
|
GenericName=MusyX Game Audio Editor
|
||||||
|
Comment=Edit Audio Data of MusyX Sound Groups
|
||||||
|
Exec=amuse-gui
|
||||||
|
Icon=amuse
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Audio
|
||||||
71
Editor/platforms/freedesktop/mkqticon.c
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const int DIMS[] =
|
||||||
|
{
|
||||||
|
16,
|
||||||
|
32,
|
||||||
|
48,
|
||||||
|
64,
|
||||||
|
128,
|
||||||
|
256,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: makeqticon <out.bin>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* ofp = fopen(argv[1], "wb");
|
||||||
|
if (!ofp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "'%s' is not able to be opened for writing as a regular file\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char command[2048];
|
||||||
|
|
||||||
|
for (const int* d = DIMS ; *d != 0 ; ++d)
|
||||||
|
{
|
||||||
|
printf("Rendering main icon @%dx%d\n", *d, *d);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
snprintf(command, 2048, "%dx%d/apps/amuse.png", *d, *d);
|
||||||
|
FILE* fp = fopen(command, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unable to open '%s' for reading\n", command);
|
||||||
|
fclose(ofp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
uint32_t size = (uint32_t)ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
fwrite(&size, 1, 4, ofp);
|
||||||
|
|
||||||
|
uint8_t buf[1024];
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
long thisSize = size;
|
||||||
|
if (thisSize > 1024)
|
||||||
|
thisSize = 1024;
|
||||||
|
|
||||||
|
fread(buf, 1, (size_t)thisSize, fp);
|
||||||
|
fwrite(buf, 1, (size_t)thisSize, ofp);
|
||||||
|
size -= thisSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(ofp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
Editor/platforms/mac/Info.plist
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>amuse-gui</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>Version BETA</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>BETA</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>2015-2018 Antidote / Jackoalan</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>mainicon.icns</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.axiodl.Amuse</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>Amuse</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>BETA</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
Editor/platforms/mac/mainicon.icns
Normal file
23
Editor/platforms/win/amuse-gui.manifest
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<description>Amuse</description>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
<!-- Windows Vista -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||||
|
<dpiAware>true/PM</dpiAware>
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
33
Editor/platforms/win/amuse-gui.rc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "winver.h"
|
||||||
|
#define IDI_ICON1 101
|
||||||
|
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "mainicon.ico"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 1,0,0,0
|
||||||
|
PRODUCTVERSION 1,0,0,0
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
FILEOS 0x00040004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "000004b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Antidote / Jackoalan"
|
||||||
|
VALUE "FileDescription", "Amuse"
|
||||||
|
VALUE "FileVersion", "BETA"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 2015-2018 Antidote / Jackoalan"
|
||||||
|
VALUE "InternalName", "amuse"
|
||||||
|
VALUE "OriginalFilename", "amuse-gui.exe"
|
||||||
|
VALUE "ProductName", "Amuse"
|
||||||
|
VALUE "ProductVersion", "BETA"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x0, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
BIN
Editor/platforms/win/mainicon.ico
Normal file
|
After Width: | Height: | Size: 118 KiB |
@@ -217,7 +217,7 @@ bool AudioGroupDataCollection::loadMeta()
|
|||||||
return ret.operator bool();
|
return ret.operator bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::wstring& path, const std::wstring& name)
|
AudioGroupDataCollection::AudioGroupDataCollection(std::wstring_view path, std::wstring_view name)
|
||||||
: m_path(path), m_name(name)
|
: m_path(path), m_name(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -295,7 +295,7 @@ void AudioGroupDataCollection::addToEngine(amuse::Engine& engine)
|
|||||||
|
|
||||||
void AudioGroupDataCollection::removeFromEngine(amuse::Engine& engine) const { engine.removeAudioGroup(*m_loadedData); }
|
void AudioGroupDataCollection::removeFromEngine(amuse::Engine& engine) const { engine.removeAudioGroup(*m_loadedData); }
|
||||||
|
|
||||||
AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::wstring& name)
|
AudioGroupCollection::AudioGroupCollection(std::wstring_view path, std::wstring_view name)
|
||||||
: m_path(path), m_name(name)
|
: m_path(path), m_name(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@ void AudioGroupFilePresenter::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupFilePresenter::addCollection(
|
void AudioGroupFilePresenter::addCollection(
|
||||||
const std::wstring& name, std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
|
std::wstring_view name, std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||||
{
|
{
|
||||||
std::wstring path = m_backend.getUserDir() + L'\\' + name;
|
std::wstring path = m_backend.getUserDir() + L'\\' + name;
|
||||||
AudioGroupCollection& insert =
|
AudioGroupCollection& insert =
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ struct AudioGroupDataCollection
|
|||||||
bool loadSamp();
|
bool loadSamp();
|
||||||
bool loadMeta();
|
bool loadMeta();
|
||||||
|
|
||||||
AudioGroupDataCollection(const std::wstring& path, const std::wstring& name);
|
AudioGroupDataCollection(std::wstring_view path, std::wstring_view name);
|
||||||
bool isDataComplete() const
|
bool isDataComplete() const
|
||||||
{
|
{
|
||||||
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
|
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
|
||||||
@@ -82,7 +82,7 @@ struct AudioGroupCollection
|
|||||||
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
||||||
std::vector<GroupIterator> m_iteratorVec;
|
std::vector<GroupIterator> m_iteratorVec;
|
||||||
|
|
||||||
AudioGroupCollection(const std::wstring& path, const std::wstring& name);
|
AudioGroupCollection(std::wstring_view path, std::wstring_view name);
|
||||||
void addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
void addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void update(AudioGroupFilePresenter& presenter);
|
void update(AudioGroupFilePresenter& presenter);
|
||||||
void populateFiles(VSTEditor& editor, HTREEITEM colHandle, size_t parentIdx);
|
void populateFiles(VSTEditor& editor, HTREEITEM colHandle, size_t parentIdx);
|
||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
void populateCollectionColumn(VSTEditor& editor);
|
void populateCollectionColumn(VSTEditor& editor);
|
||||||
void populateGroupColumn(VSTEditor& editor, int collectionIdx, int fileIdx);
|
void populateGroupColumn(VSTEditor& editor, int collectionIdx, int fileIdx);
|
||||||
void populatePageColumn(VSTEditor& editor, int collectionIdx, int fileIdx, int groupIdx);
|
void populatePageColumn(VSTEditor& editor, int collectionIdx, int fileIdx, int groupIdx);
|
||||||
void addCollection(const std::wstring& name,
|
void addCollection(std::wstring_view name,
|
||||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void removeCollection(unsigned idx);
|
void removeCollection(unsigned idx);
|
||||||
VSTBackend& getBackend() { return m_backend; }
|
VSTBackend& getBackend() { return m_backend; }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ if (WIN32 AND (EXISTS ${VST3_SDK_ROOT}))
|
|||||||
${VST2_DIR}/audioeffect.cpp
|
${VST2_DIR}/audioeffect.cpp
|
||||||
${VST2_DIR}/audioeffectx.cpp
|
${VST2_DIR}/audioeffectx.cpp
|
||||||
FileOpenDialog.hpp FileOpenDialog.cpp)
|
FileOpenDialog.hpp FileOpenDialog.cpp)
|
||||||
target_link_libraries(amuse-vst amuse boo soxr ${ZLIB_LIBRARIES} Winmm soxr
|
target_link_libraries(amuse-vst amuse boo soxr ${ZLIB_LIBRARIES} ${LZO_LIB} Winmm soxr
|
||||||
Msimg32 Shlwapi logvisor athena-core)
|
Msimg32 Shlwapi logvisor athena-core)
|
||||||
set_target_properties(amuse-vst PROPERTIES LINK_FLAGS "/EXPORT:VSTPluginMain")
|
set_target_properties(amuse-vst PROPERTIES LINK_FLAGS "/EXPORT:VSTPluginMain")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "VSTBackend.hpp"
|
#include "VSTBackend.hpp"
|
||||||
#include "audiodev/AudioVoiceEngine.hpp"
|
#include "audiodev/AudioVoiceEngine.hpp"
|
||||||
|
#include "logvisor/logvisor.hpp"
|
||||||
#include <Shlobj.h>
|
#include <Shlobj.h>
|
||||||
#include <logvisor/logvisor.hpp>
|
|
||||||
|
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
void setBlockSize(VstInt32 blockSize);
|
void setBlockSize(VstInt32 blockSize);
|
||||||
|
|
||||||
amuse::Engine& getAmuseEngine() { return *m_engine; }
|
amuse::Engine& getAmuseEngine() { return *m_engine; }
|
||||||
const std::wstring& getUserDir() const { return m_userDir; }
|
std::wstring_view getUserDir() const { return m_userDir; }
|
||||||
AudioGroupFilePresenter& getFilePresenter() { return m_filePresenter; }
|
AudioGroupFilePresenter& getFilePresenter() { return m_filePresenter; }
|
||||||
|
|
||||||
void loadGroupFile(int collectionIdx, int fileIdx);
|
void loadGroupFile(int collectionIdx, int fileIdx);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#include "athena/FileReader.hpp"
|
#include "athena/FileReader.hpp"
|
||||||
#include "athena/DNAYaml.hpp"
|
#include "athena/DNAYaml.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
static logvisor::Module Log("amuseconv");
|
static logvisor::Module Log("amuseconv");
|
||||||
|
|
||||||
@@ -31,22 +31,22 @@ static void ReportConvType(ConvType tp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BuildAudioGroup(const amuse::SystemString& groupBase, const amuse::SystemString& targetPath)
|
static bool BuildAudioGroup(amuse::SystemStringView groupBase, amuse::SystemStringView targetPath)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ExtractAudioGroup(const amuse::SystemString& inPath, const amuse::SystemString& targetPath)
|
static bool ExtractAudioGroup(amuse::SystemStringView inPath, amuse::SystemStringView targetPath)
|
||||||
{
|
{
|
||||||
amuse::ContainerRegistry::Type type;
|
amuse::ContainerRegistry::Type type;
|
||||||
auto groups = amuse::ContainerRegistry::LoadContainer(inPath.c_str(), type);
|
auto groups = amuse::ContainerRegistry::LoadContainer(inPath.data(), type);
|
||||||
|
|
||||||
if (groups.size())
|
if (groups.size())
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Info, _S("Found '%s'"), amuse::ContainerRegistry::TypeToName(type));
|
Log.report(logvisor::Info, _S("Found '%s'"), amuse::ContainerRegistry::TypeToName(type));
|
||||||
|
|
||||||
amuse::Mkdir(targetPath.c_str(), 0755);
|
amuse::Mkdir(targetPath.data(), 0755);
|
||||||
Log.report(logvisor::Info, _S("Established directory at %s"), targetPath.c_str());
|
Log.report(logvisor::Info, _S("Established directory at %s"), targetPath.data());
|
||||||
|
|
||||||
for (auto& group : groups)
|
for (auto& group : groups)
|
||||||
{
|
{
|
||||||
@@ -54,14 +54,14 @@ static bool ExtractAudioGroup(const amuse::SystemString& inPath, const amuse::Sy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto songs = amuse::ContainerRegistry::LoadSongs(inPath.c_str());
|
auto songs = amuse::ContainerRegistry::LoadSongs(inPath.data());
|
||||||
amuse::SystemString songsDir = targetPath + _S("/midifiles");
|
amuse::SystemString songsDir = amuse::SystemString(targetPath) + _S("/midifiles");
|
||||||
bool madeDir = false;
|
bool madeDir = false;
|
||||||
for (auto& pair : songs)
|
for (auto& pair : songs)
|
||||||
{
|
{
|
||||||
if (!madeDir)
|
if (!madeDir)
|
||||||
{
|
{
|
||||||
amuse::Mkdir(targetPath.c_str(), 0755);
|
amuse::Mkdir(targetPath.data(), 0755);
|
||||||
amuse::Mkdir(songsDir.c_str(), 0755);
|
amuse::Mkdir(songsDir.c_str(), 0755);
|
||||||
madeDir = true;
|
madeDir = true;
|
||||||
}
|
}
|
||||||
@@ -83,9 +83,9 @@ static bool ExtractAudioGroup(const amuse::SystemString& inPath, const amuse::Sy
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BuildSNG(const amuse::SystemString& inPath, const amuse::SystemString& targetPath, int version, bool big)
|
static bool BuildSNG(amuse::SystemStringView inPath, amuse::SystemStringView targetPath, int version, bool big)
|
||||||
{
|
{
|
||||||
FILE* fp = amuse::FOpen(inPath.c_str(), _S("rb"));
|
FILE* fp = amuse::FOpen(inPath.data(), _S("rb"));
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -100,16 +100,16 @@ static bool BuildSNG(const amuse::SystemString& inPath, const amuse::SystemStrin
|
|||||||
if (out.empty())
|
if (out.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fp = amuse::FOpen(targetPath.c_str(), _S("wb"));
|
fp = amuse::FOpen(targetPath.data(), _S("wb"));
|
||||||
fwrite(out.data(), 1, out.size(), fp);
|
fwrite(out.data(), 1, out.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ExtractSNG(const amuse::SystemString& inPath, const amuse::SystemString& targetPath)
|
static bool ExtractSNG(amuse::SystemStringView inPath, amuse::SystemStringView targetPath)
|
||||||
{
|
{
|
||||||
FILE* fp = amuse::FOpen(inPath.c_str(), _S("rb"));
|
FILE* fp = amuse::FOpen(inPath.data(), _S("rb"));
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ static bool ExtractSNG(const amuse::SystemString& inPath, const amuse::SystemStr
|
|||||||
if (out.empty())
|
if (out.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fp = amuse::FOpen(targetPath.c_str(), _S("wb"));
|
fp = amuse::FOpen(targetPath.data(), _S("wb"));
|
||||||
fwrite(out.data(), 1, out.size(), fp);
|
fwrite(out.data(), 1, out.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
#include "amuse/amuse.hpp"
|
#include "amuse/amuse.hpp"
|
||||||
#include "amuse/BooBackend.hpp"
|
#include "amuse/BooBackend.hpp"
|
||||||
#include "athena/FileReader.hpp"
|
|
||||||
#include "boo/boo.hpp"
|
#include "boo/boo.hpp"
|
||||||
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include "optional.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
#define EMITTER_TEST 0
|
||||||
#include <unordered_map>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
static logvisor::Module Log("amuseplay");
|
static logvisor::Module Log("amuseplay");
|
||||||
|
|
||||||
@@ -31,58 +24,6 @@ SNPrintf(boo::SystemChar* str, size_t maxlen, const boo::SystemChar* format, ...
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
#include <DbgHelp.h>
|
|
||||||
#pragma comment(lib, "Dbghelp.lib")
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
static void abortHandler(int signum)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
void* stack[100];
|
|
||||||
unsigned short frames;
|
|
||||||
SYMBOL_INFO* symbol;
|
|
||||||
HANDLE process;
|
|
||||||
|
|
||||||
process = GetCurrentProcess();
|
|
||||||
SymInitialize(process, NULL, TRUE);
|
|
||||||
frames = CaptureStackBackTrace(0, 100, stack, NULL);
|
|
||||||
symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
|
||||||
symbol->MaxNameLen = 255;
|
|
||||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
||||||
|
|
||||||
for (i = 0; i < frames; i++)
|
|
||||||
{
|
|
||||||
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
|
|
||||||
|
|
||||||
printf("%i: %s - 0x%0llX", frames - i - 1, symbol->Name, symbol->Address);
|
|
||||||
|
|
||||||
DWORD dwDisplacement;
|
|
||||||
IMAGEHLP_LINE64 line;
|
|
||||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
|
||||||
|
|
||||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
|
||||||
if (SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &dwDisplacement, &line))
|
|
||||||
{
|
|
||||||
// SymGetLineFromAddr64 returned success
|
|
||||||
printf(" LINE %d\n", line.LineNumber);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(symbol);
|
|
||||||
|
|
||||||
// If you caught one of the above signals, it is likely you just
|
|
||||||
// want to quit your program right now.
|
|
||||||
system("PAUSE");
|
|
||||||
exit(signum);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct AppCallback;
|
struct AppCallback;
|
||||||
|
|
||||||
struct EventCallback : boo::IWindowCallback
|
struct EventCallback : boo::IWindowCallback
|
||||||
@@ -95,7 +36,7 @@ public:
|
|||||||
void charKeyUp(unsigned long charCode, boo::EModifierKey mods);
|
void charKeyUp(unsigned long charCode, boo::EModifierKey mods);
|
||||||
void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat);
|
void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat);
|
||||||
void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods);
|
void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods);
|
||||||
void resized(const boo::SWindowRect&, const boo::SWindowRect&) {}
|
void resized(const boo::SWindowRect&, bool) {}
|
||||||
|
|
||||||
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
||||||
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
||||||
@@ -112,10 +53,11 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
/* Boo window and events */
|
/* Boo window and events */
|
||||||
EventCallback m_eventRec;
|
EventCallback m_eventRec;
|
||||||
boo::DeferredWindowEvents<EventCallback> m_events;
|
boo::DeferredWindowEvents<EventCallback> m_events;
|
||||||
boo::IWindow* m_win = nullptr;
|
std::shared_ptr<boo::IWindow> m_win;
|
||||||
|
|
||||||
/* Amuse engine */
|
/* Amuse engine */
|
||||||
std::experimental::optional<amuse::Engine> m_engine;
|
std::unique_ptr<amuse::BooBackendVoiceAllocator> m_booBackend;
|
||||||
|
std::unique_ptr<amuse::Engine> m_engine;
|
||||||
int m_groupId = -1;
|
int m_groupId = -1;
|
||||||
bool m_sfxGroup;
|
bool m_sfxGroup;
|
||||||
|
|
||||||
@@ -144,6 +86,14 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
bool m_breakout = false;
|
bool m_breakout = false;
|
||||||
int m_panicCount = 0;
|
int m_panicCount = 0;
|
||||||
|
|
||||||
|
#if EMITTER_TEST
|
||||||
|
amuse::Vector3f m_pos = {};
|
||||||
|
amuse::Vector3f m_dir = {0.f, 0.f, 0.f};
|
||||||
|
amuse::Vector3f m_listenerDir = {0.f, 40.f, 0.f};
|
||||||
|
std::shared_ptr<amuse::Emitter> m_emitter;
|
||||||
|
std::shared_ptr<amuse::Listener> m_listener;
|
||||||
|
#endif
|
||||||
|
|
||||||
void UpdateSongDisplay()
|
void UpdateSongDisplay()
|
||||||
{
|
{
|
||||||
size_t voxCount = 0;
|
size_t voxCount = 0;
|
||||||
@@ -165,7 +115,7 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
m_setupId = setupId;
|
m_setupId = setupId;
|
||||||
if (m_seq)
|
if (m_seq)
|
||||||
{
|
{
|
||||||
m_seq->stopSong(true);
|
m_seq->stopSong(0.f, true);
|
||||||
m_seq->kill();
|
m_seq->kill();
|
||||||
}
|
}
|
||||||
m_seq = m_engine->seqPlay(m_groupId, setupId, nullptr);
|
m_seq = m_engine->seqPlay(m_groupId, setupId, nullptr);
|
||||||
@@ -177,7 +127,7 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
UpdateSongDisplay();
|
UpdateSongDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SongLoop(const amuse::SongGroupIndex& index)
|
void SongLoop(const amuse::SongGroupIndex& index, boo::IAudioVoiceEngine& booEngine)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n"
|
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n"
|
||||||
@@ -254,7 +204,7 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
UpdateSongDisplay();
|
UpdateSongDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_engine->pumpEngine();
|
m_win->waitForRetrace(&booEngine);
|
||||||
|
|
||||||
size_t voxCount;
|
size_t voxCount;
|
||||||
int8_t progId;
|
int8_t progId;
|
||||||
@@ -283,18 +233,23 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
m_seq.reset();
|
m_seq.reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_win->waitForRetrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateSFXDisplay()
|
void UpdateSFXDisplay()
|
||||||
{
|
{
|
||||||
bool playing = m_vox && m_vox->state() == amuse::VoiceState::Playing;
|
bool playing = m_vox && m_vox->state() == amuse::VoiceState::Playing;
|
||||||
|
#if EMITTER_TEST
|
||||||
|
printf(
|
||||||
|
"\r "
|
||||||
|
"\r %c SFX %d, VOL: %d%% POS: (%f,%f)\r",
|
||||||
|
playing ? '>' : ' ', m_sfxId, int(std::rint(m_volume * 100)), m_pos[0], m_pos[1]);
|
||||||
|
#else
|
||||||
printf(
|
printf(
|
||||||
"\r "
|
"\r "
|
||||||
"\r %c SFX %d, VOL: %d%%\r",
|
"\r %c SFX %d, VOL: %d%%\r",
|
||||||
playing ? '>' : ' ', m_sfxId, int(std::rint(m_volume * 100)));
|
playing ? '>' : ' ', m_sfxId, int(std::rint(m_volume * 100)));
|
||||||
|
#endif
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,25 +260,52 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
bool playing = m_vox && m_vox->state() == amuse::VoiceState::Playing;
|
bool playing = m_vox && m_vox->state() == amuse::VoiceState::Playing;
|
||||||
if (playing)
|
if (playing)
|
||||||
{
|
{
|
||||||
|
#if EMITTER_TEST
|
||||||
|
if (m_emitter)
|
||||||
|
m_emitter->getVoice()->keyOff();
|
||||||
|
m_emitter = m_engine->addEmitter(m_pos, m_dir, 100.f, 0.f, m_sfxId, 0.f, 1.f, true);
|
||||||
|
m_vox = m_emitter->getVoice();
|
||||||
|
#else
|
||||||
m_vox->keyOff();
|
m_vox->keyOff();
|
||||||
m_vox = m_engine->fxStart(m_sfxId, m_volume, 0.f);
|
m_vox = m_engine->fxStart(m_sfxId, m_volume, 0.f);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateSFXDisplay();
|
UpdateSFXDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFXLoop(const amuse::SFXGroupIndex& index)
|
void SFXLoop(const amuse::SFXGroupIndex& index, boo::IAudioVoiceEngine& booEngine)
|
||||||
{
|
{
|
||||||
printf("<space>: keyon/keyoff, <left/right>: cycle SFX, <up/down>: volume, <Q>: quit\n");
|
printf("<space>: keyon/keyoff, <left/right>: cycle SFX, <up/down>: volume, <Q>: quit\n");
|
||||||
|
|
||||||
|
m_seq = m_engine->seqPlay(m_groupId, 0, nullptr);
|
||||||
|
|
||||||
std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries(index.m_sfxEntries.cbegin(),
|
std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries(index.m_sfxEntries.cbegin(),
|
||||||
index.m_sfxEntries.cend());
|
index.m_sfxEntries.cend());
|
||||||
auto sfxIt = sortEntries.cbegin();
|
auto sfxIt = sortEntries.cbegin();
|
||||||
if (sfxIt != sortEntries.cend())
|
if (sfxIt != sortEntries.cend())
|
||||||
SelectSFX(sfxIt->first);
|
SelectSFX(sfxIt->first);
|
||||||
|
|
||||||
|
#if EMITTER_TEST
|
||||||
|
float emitterTheta = 0.f;
|
||||||
|
float zeroVec[3] = {};
|
||||||
|
float heading[3] = {0.f, 1.f, 0.f};
|
||||||
|
float up[3] = {0.f, 0.f, 1.f};
|
||||||
|
m_listener = m_engine->addListener(zeroVec, m_listenerDir, heading, up, 5.f, 5.f, 1000.f, 1.f);
|
||||||
|
#endif
|
||||||
|
|
||||||
while (m_running)
|
while (m_running)
|
||||||
{
|
{
|
||||||
|
#if EMITTER_TEST
|
||||||
|
//float dist = std::sin(emitterTheta * 0.25f);
|
||||||
|
m_pos[0] = std::cos(emitterTheta) * 5.f;
|
||||||
|
m_pos[1] = std::sin(emitterTheta) * 5.f;
|
||||||
|
if (m_emitter)
|
||||||
|
m_emitter->setVectors(m_pos, m_dir);
|
||||||
|
emitterTheta += 1.f / 60.f;
|
||||||
|
m_updateDisp = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
m_events.dispatchEvents();
|
m_events.dispatchEvents();
|
||||||
|
|
||||||
if (m_wantsNext)
|
if (m_wantsNext)
|
||||||
@@ -356,11 +338,14 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
UpdateSFXDisplay();
|
UpdateSFXDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_engine->pumpEngine();
|
m_win->waitForRetrace(&booEngine);
|
||||||
|
|
||||||
if (m_vox && m_vox->state() == amuse::VoiceState::Dead)
|
if (m_vox && m_vox->state() == amuse::VoiceState::Dead)
|
||||||
{
|
{
|
||||||
m_vox.reset();
|
m_vox.reset();
|
||||||
|
#if EMITTER_TEST
|
||||||
|
m_emitter.reset();
|
||||||
|
#endif
|
||||||
UpdateSFXDisplay();
|
UpdateSFXDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,11 +353,19 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
{
|
{
|
||||||
m_breakout = false;
|
m_breakout = false;
|
||||||
m_vox.reset();
|
m_vox.reset();
|
||||||
|
#if EMITTER_TEST
|
||||||
|
m_emitter.reset();
|
||||||
|
#endif
|
||||||
|
m_seq->allOff(true);
|
||||||
|
m_seq.reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_win->waitForRetrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if EMITTER_TEST
|
||||||
|
m_engine->removeListener(m_listener.get());
|
||||||
|
m_listener.reset();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void charKeyDownRepeat(unsigned long charCode)
|
void charKeyDownRepeat(unsigned long charCode)
|
||||||
@@ -435,10 +428,19 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
switch (charCode)
|
switch (charCode)
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
|
if (m_seq)
|
||||||
|
m_seq->allOff(true);
|
||||||
if (m_vox && m_vox->state() == amuse::VoiceState::Playing)
|
if (m_vox && m_vox->state() == amuse::VoiceState::Playing)
|
||||||
m_vox->keyOff();
|
m_vox->keyOff();
|
||||||
else if (m_sfxId != -1)
|
else if (m_sfxId != -1)
|
||||||
|
{
|
||||||
|
#if EMITTER_TEST
|
||||||
|
m_emitter = m_engine->addEmitter(m_pos, m_dir, 100.f, 0.f, m_sfxId, 0.f, 1.f, true);
|
||||||
|
m_vox = m_emitter->getVoice();
|
||||||
|
#else
|
||||||
m_vox = m_engine->fxStart(m_sfxId, m_volume, 0.f);
|
m_vox = m_engine->fxStart(m_sfxId, m_volume, 0.f);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
m_updateDisp = true;
|
m_updateDisp = true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -622,17 +624,16 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
int appMain(boo::IApplication* app)
|
int appMain(boo::IApplication* app)
|
||||||
{
|
{
|
||||||
/* Event window */
|
/* Event window */
|
||||||
m_win = app->newWindow(_S("amuseplay"), 1);
|
m_win = app->newWindow(_S("amuseplay"));
|
||||||
m_win->setCallback(&m_events);
|
m_win->setCallback(&m_events);
|
||||||
m_win->setWindowFrame(100, 100, 100, 100);
|
m_win->setWindowFrame(100, 100, 100, 100);
|
||||||
m_win->setStyle(~boo::EWindowStyle::Resize);
|
m_win->setStyle(~boo::EWindowStyle::Resize);
|
||||||
m_win->showWindow();
|
m_win->showWindow();
|
||||||
boo::ITextureR* tex = nullptr;
|
boo::ObjToken<boo::ITextureR> tex;
|
||||||
boo::GraphicsDataToken gfxToken =
|
m_win->getMainContextDataFactory()->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) {
|
||||||
m_win->getMainContextDataFactory()->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool {
|
tex = ctx.newRenderTexture(100, 100, boo::TextureClampMode::Repeat, 1, 0);
|
||||||
tex = ctx.newRenderTexture(100, 100, false, false);
|
return true;
|
||||||
return true;
|
} BooTrace);
|
||||||
});
|
|
||||||
boo::IGraphicsCommandQueue* q = m_win->getCommandQueue();
|
boo::IGraphicsCommandQueue* q = m_win->getCommandQueue();
|
||||||
q->setRenderTarget(tex);
|
q->setRenderTarget(tex);
|
||||||
q->clearTarget();
|
q->clearTarget();
|
||||||
@@ -909,8 +910,8 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
|
|
||||||
/* Build voice engine */
|
/* Build voice engine */
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> voxEngine = boo::NewAudioVoiceEngine();
|
std::unique_ptr<boo::IAudioVoiceEngine> voxEngine = boo::NewAudioVoiceEngine();
|
||||||
amuse::BooBackendVoiceAllocator booBackend(*voxEngine);
|
m_booBackend.reset(new amuse::BooBackendVoiceAllocator(*voxEngine));
|
||||||
m_engine.emplace(booBackend, amuse::AmplitudeMode::PerSample);
|
m_engine.reset(new amuse::Engine(*m_booBackend, amuse::AmplitudeMode::PerSample));
|
||||||
|
|
||||||
/* Load group into engine */
|
/* Load group into engine */
|
||||||
const amuse::AudioGroup* group = m_engine->addAudioGroup(*selData);
|
const amuse::AudioGroup* group = m_engine->addAudioGroup(*selData);
|
||||||
@@ -922,10 +923,14 @@ struct AppCallback : boo::IApplicationCallback
|
|||||||
|
|
||||||
/* Enter playback loop */
|
/* Enter playback loop */
|
||||||
if (m_sfxGroup)
|
if (m_sfxGroup)
|
||||||
SFXLoop(*sfxIndex);
|
SFXLoop(*sfxIndex, *voxEngine);
|
||||||
else
|
else
|
||||||
SongLoop(*songIndex);
|
SongLoop(*songIndex, *voxEngine);
|
||||||
|
|
||||||
|
m_vox.reset();
|
||||||
|
m_seq.reset();
|
||||||
|
m_engine.reset();
|
||||||
|
m_booBackend.reset();
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,21 +1031,19 @@ int main(int argc, const boo::SystemChar** argv)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
|
logvisor::RegisterStandardExceptions();
|
||||||
AppCallback app(argc, argv);
|
AppCallback app(argc, argv);
|
||||||
int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, app, _S("amuseplay"), _S("Amuse Player"),
|
int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, app,
|
||||||
argc, argv, false);
|
_S("amuseplay"), _S("Amuse Player"),
|
||||||
|
argc, argv, {}, 1, 1, false);
|
||||||
printf("IM DYING!!\n");
|
printf("IM DYING!!\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
#include <shellapi.h>
|
||||||
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
|
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
|
||||||
{
|
{
|
||||||
signal(SIGABRT, abortHandler);
|
|
||||||
signal(SIGSEGV, abortHandler);
|
|
||||||
signal(SIGILL, abortHandler);
|
|
||||||
signal(SIGFPE, abortHandler);
|
|
||||||
|
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
const boo::SystemChar** argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc));
|
const boo::SystemChar** argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc));
|
||||||
static boo::SystemChar selfPath[1024];
|
static boo::SystemChar selfPath[1024];
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include "optional.hpp"
|
#include "optional.hpp"
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <stdarg.h>
|
#include <cstdarg>
|
||||||
|
|
||||||
static logvisor::Module Log("amuserender");
|
static logvisor::Module Log("amuserender");
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ int main(int argc, const boo::SystemChar** argv)
|
|||||||
|
|
||||||
std::vector<boo::SystemString> m_args;
|
std::vector<boo::SystemString> m_args;
|
||||||
m_args.reserve(argc);
|
m_args.reserve(argc);
|
||||||
double rate = 32000.0;
|
double rate = NativeSampleRate;
|
||||||
for (int i = 1; i < argc; ++i)
|
for (int i = 1; i < argc; ++i)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@@ -470,7 +470,7 @@ int main(int argc, const boo::SystemChar** argv)
|
|||||||
signal(SIGINT, SIGINTHandler);
|
signal(SIGINT, SIGINTHandler);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
engine.pumpEngine();
|
voxEngine->pumpAndMixVoices();
|
||||||
wroteFrames += voxEngine->get5MsFrames();
|
wroteFrames += voxEngine->get5MsFrames();
|
||||||
printf("\rFrame %" PRISize, wroteFrames);
|
printf("\rFrame %" PRISize, wroteFrames);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -481,6 +481,7 @@ int main(int argc, const boo::SystemChar** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
#include <shellapi.h>
|
||||||
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
|
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
|
||||||
{
|
{
|
||||||
signal(SIGABRT, abortHandler);
|
signal(SIGABRT, abortHandler);
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ public:
|
|||||||
IntrusiveAudioGroupData(const IntrusiveAudioGroupData&) = delete;
|
IntrusiveAudioGroupData(const IntrusiveAudioGroupData&) = delete;
|
||||||
IntrusiveAudioGroupData& operator=(const IntrusiveAudioGroupData&) = delete;
|
IntrusiveAudioGroupData& operator=(const IntrusiveAudioGroupData&) = delete;
|
||||||
|
|
||||||
IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other);
|
IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other) noexcept;
|
||||||
IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other);
|
IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other) noexcept;
|
||||||
|
|
||||||
void dangleOwnership() { m_owns = false; }
|
void dangleOwnership() { m_owns = false; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef __AMUSE_AUDIOGROUPPOOL_HPP__
|
#ifndef __AMUSE_AUDIOGROUPPOOL_HPP__
|
||||||
#define __AMUSE_AUDIOGROUPPOOL_HPP__
|
#define __AMUSE_AUDIOGROUPPOOL_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -22,22 +22,15 @@ static inline double TimeCentsToSeconds(int32_t tc)
|
|||||||
/** Defines phase-based volume curve for macro volume control */
|
/** Defines phase-based volume curve for macro volume control */
|
||||||
struct ADSR
|
struct ADSR
|
||||||
{
|
{
|
||||||
uint8_t attackFine; /* 0-255ms */
|
uint16_t attack;
|
||||||
uint8_t attackCoarse; /* 0-65280ms */
|
uint16_t decay;
|
||||||
uint8_t decayFine; /* 0-255ms */
|
uint16_t sustain; /* 0x1000 == 100% */
|
||||||
uint8_t decayCoarse; /* 0-65280ms */
|
uint16_t release; /* milliseconds */
|
||||||
uint8_t sustainFine; /* multiply by 0.0244 for percentage */
|
|
||||||
uint8_t sustainCoarse; /* multiply by 6.25 for percentage */
|
|
||||||
uint8_t releaseFine; /* 0-255ms */
|
|
||||||
uint8_t releaseCoarse; /* 0-65280ms */
|
|
||||||
|
|
||||||
double getAttack() const { return (attackCoarse * 255 + attackFine) / 1000.0; }
|
double getAttack() const { return attack / 1000.0; }
|
||||||
double getDecay() const { return decayCoarse == 128 ? 0.0 : ((decayCoarse * 255 + decayFine) / 1000.0); }
|
double getDecay() const { return (decay == 0x8000) ? 0.0 : (decay / 1000.0); }
|
||||||
double getSustain() const
|
double getSustain() const { return sustain / double(0x1000); }
|
||||||
{
|
double getRelease() const { return release / 1000.0; }
|
||||||
return decayCoarse == 128 ? 1.0 : ((sustainCoarse * 6.25 + sustainFine * 0.0244) / 100.0);
|
|
||||||
}
|
|
||||||
double getRelease() const { return (releaseCoarse * 255 + releaseFine) / 1000.0; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Defines phase-based volume curve for macro volume control (modified DLS standard) */
|
/** Defines phase-based volume curve for macro volume control (modified DLS standard) */
|
||||||
@@ -53,7 +46,7 @@ struct ADSRDLS
|
|||||||
double getAttack() const { return TimeCentsToSeconds(attack); }
|
double getAttack() const { return TimeCentsToSeconds(attack); }
|
||||||
double getDecay() const { return TimeCentsToSeconds(decay); }
|
double getDecay() const { return TimeCentsToSeconds(decay); }
|
||||||
double getSustain() const { return sustain / double(0x1000); }
|
double getSustain() const { return sustain / double(0x1000); }
|
||||||
double getRelease() const { return release / double(1000); }
|
double getRelease() const { return release / 1000.0; }
|
||||||
double getVelToAttack(int8_t vel) const
|
double getVelToAttack(int8_t vel) const
|
||||||
{
|
{
|
||||||
if (velToAttack == 0x80000000)
|
if (velToAttack == 0x80000000)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
|
#define __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ class BooBackendVoice : public IBackendVoice
|
|||||||
BooBackendVoice& m_parent;
|
BooBackendVoice& m_parent;
|
||||||
void preSupplyAudio(boo::IAudioVoice& voice, double dt);
|
void preSupplyAudio(boo::IAudioVoice& voice, double dt);
|
||||||
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data);
|
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data);
|
||||||
void routeAudio(size_t frames, double dt, int busId, int16_t* in, int16_t* out);
|
void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out);
|
||||||
void routeAudio(size_t frames, double dt, int busId, int32_t* in, int32_t* out);
|
void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out);
|
||||||
void routeAudio(size_t frames, double dt, int busId, float* in, float* out);
|
void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out);
|
||||||
VoiceCallback(BooBackendVoice& parent) : m_parent(parent) {}
|
VoiceCallback(BooBackendVoice& parent) : m_parent(parent) {}
|
||||||
} m_cb;
|
} m_cb;
|
||||||
std::unique_ptr<boo::IAudioVoice> m_booVoice;
|
boo::ObjToken<boo::IAudioVoice> m_booVoice;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch);
|
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch);
|
||||||
@@ -58,7 +58,7 @@ class BooBackendSubmix : public IBackendSubmix
|
|||||||
void resetOutputSampleRate(double sampleRate);
|
void resetOutputSampleRate(double sampleRate);
|
||||||
SubmixCallback(BooBackendSubmix& parent) : m_parent(parent) {}
|
SubmixCallback(BooBackendSubmix& parent) : m_parent(parent) {}
|
||||||
} m_cb;
|
} m_cb;
|
||||||
std::unique_ptr<boo::IAudioSubmix> m_booSubmix;
|
boo::ObjToken<boo::IAudioSubmix> m_booSubmix;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId);
|
BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId);
|
||||||
@@ -116,10 +116,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Backend voice allocator implementation for boo mixer */
|
/** Backend voice allocator implementation for boo mixer */
|
||||||
class BooBackendVoiceAllocator : public IBackendVoiceAllocator
|
class BooBackendVoiceAllocator : public IBackendVoiceAllocator, public boo::IAudioVoiceEngineCallback
|
||||||
{
|
{
|
||||||
friend class BooBackendMIDIReader;
|
friend class BooBackendMIDIReader;
|
||||||
boo::IAudioVoiceEngine& m_booEngine;
|
boo::IAudioVoiceEngine& m_booEngine;
|
||||||
|
Engine* m_cbInterface = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
||||||
@@ -127,10 +128,11 @@ public:
|
|||||||
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut, int busId);
|
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut, int busId);
|
||||||
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices();
|
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices();
|
||||||
std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name = nullptr);
|
std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name = nullptr);
|
||||||
void register5MsCallback(std::function<void(double)>&& callback);
|
void setCallbackInterface(Engine* engine);
|
||||||
AudioChannelSet getAvailableSet();
|
AudioChannelSet getAvailableSet();
|
||||||
void pumpAndMixVoices();
|
|
||||||
void setVolume(float vol);
|
void setVolume(float vol);
|
||||||
|
void on5MsInterval(boo::IAudioVoiceEngine& engine, double dt);
|
||||||
|
void onPumpCycleComplete(boo::IAudioVoiceEngine& engine);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,29 @@
|
|||||||
#define __AMUSE_COMMON_HPP__
|
#define __AMUSE_COMMON_HPP__
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits.h>
|
#include <limits>
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <stdarg.h>
|
#include <cstdarg>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _WIN32
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
#endif
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
constexpr float NativeSampleRate = 32000.0f;
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -27,6 +39,7 @@ namespace amuse
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
using SystemString = std::wstring;
|
using SystemString = std::wstring;
|
||||||
|
using SystemStringView = std::wstring_view;
|
||||||
using SystemChar = wchar_t;
|
using SystemChar = wchar_t;
|
||||||
#ifndef _S
|
#ifndef _S
|
||||||
#define _S(val) L##val
|
#define _S(val) L##val
|
||||||
@@ -36,6 +49,7 @@ static inline int Mkdir(const wchar_t* path, int) { return _wmkdir(path); }
|
|||||||
static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstat(path, statout); }
|
static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstat(path, statout); }
|
||||||
#else
|
#else
|
||||||
using SystemString = std::string;
|
using SystemString = std::string;
|
||||||
|
using SystemStringView = std::string_view;
|
||||||
using SystemChar = char;
|
using SystemChar = char;
|
||||||
#ifndef _S
|
#ifndef _S
|
||||||
#define _S(val) val
|
#define _S(val) val
|
||||||
@@ -65,35 +79,24 @@ static inline T clamp(T a, T val, T b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T ClampFull(float in)
|
inline T ClampFull(float in)
|
||||||
{
|
{
|
||||||
return in;
|
if (std::is_floating_point<T>())
|
||||||
}
|
{
|
||||||
|
return std::min<T>(std::max<T>(in, -1.f), 1.f);
|
||||||
template <>
|
}
|
||||||
inline int16_t ClampFull<int16_t>(float in)
|
else
|
||||||
{
|
{
|
||||||
if (in < SHRT_MIN)
|
constexpr T MAX = std::numeric_limits<T>::max();
|
||||||
return SHRT_MIN;
|
constexpr T MIN = std::numeric_limits<T>::min();
|
||||||
else if (in > SHRT_MAX)
|
|
||||||
return SHRT_MAX;
|
if (in < MIN)
|
||||||
return in;
|
return MIN;
|
||||||
}
|
else if (in > MAX)
|
||||||
|
return MAX;
|
||||||
template <>
|
else
|
||||||
inline int32_t ClampFull<int32_t>(float in)
|
return in;
|
||||||
{
|
}
|
||||||
if (in < INT_MIN)
|
|
||||||
return INT_MIN;
|
|
||||||
else if (in > INT_MAX)
|
|
||||||
return INT_MAX;
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline float ClampFull<float>(float in)
|
|
||||||
{
|
|
||||||
return in;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef M_PIF
|
#ifndef M_PIF
|
||||||
@@ -186,6 +189,15 @@ static inline FILE* FOpen(const SystemChar* path, const SystemChar* mode)
|
|||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void Unlink(const SystemChar* file)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
_wunlink(file);
|
||||||
|
#else
|
||||||
|
unlink(file);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#undef bswap16
|
#undef bswap16
|
||||||
#undef bswap32
|
#undef bswap32
|
||||||
#undef bswap64
|
#undef bswap64
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ namespace amuse
|
|||||||
|
|
||||||
struct CaseInsensitiveCompare
|
struct CaseInsensitiveCompare
|
||||||
{
|
{
|
||||||
bool operator()(const std::string& lhs, const std::string& rhs) const
|
bool operator()(std::string_view lhs, std::string_view rhs) const
|
||||||
{
|
{
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
if (_stricmp(lhs.c_str(), rhs.c_str()) < 0)
|
if (_stricmp(lhs.data(), rhs.data()) < 0)
|
||||||
#else
|
#else
|
||||||
if (strcasecmp(lhs.c_str(), rhs.c_str()) < 0)
|
if (strcasecmp(lhs.data(), rhs.data()) < 0)
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
bool operator()(const std::wstring& lhs, const std::wstring& rhs) const
|
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const
|
||||||
{
|
{
|
||||||
if (_wcsicmp(lhs.c_str(), rhs.c_str()) < 0)
|
if (_wcsicmp(lhs.data(), rhs.data()) < 0)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -47,24 +47,15 @@ public:
|
|||||||
size_t m_fileSz;
|
size_t m_fileSz;
|
||||||
bool m_isDir;
|
bool m_isDir;
|
||||||
|
|
||||||
private:
|
Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
|
||||||
friend class DirectoryEnumerator;
|
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
||||||
Entry(SystemString&& path, const SystemChar* name, size_t sz, bool isDir)
|
|
||||||
: m_path(std::move(path)), m_name(name), m_fileSz(sz), m_isDir(isDir)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Entry> m_entries;
|
std::vector<Entry> m_entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirectoryEnumerator(const SystemString& path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
||||||
bool reverse = false, bool noHidden = false)
|
|
||||||
: DirectoryEnumerator(path.c_str(), mode, sizeSort, reverse, noHidden)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
DirectoryEnumerator(const SystemChar* path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
|
||||||
bool reverse = false, bool noHidden = false);
|
bool reverse = false, bool noHidden = false);
|
||||||
|
|
||||||
operator bool() const { return m_entries.size() != 0; }
|
operator bool() const { return m_entries.size() != 0; }
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef __AMUSE_EFFECTBASE_HPP__
|
#ifndef __AMUSE_EFFECTBASE_HPP__
|
||||||
#define __AMUSE_EFFECTBASE_HPP__
|
#define __AMUSE_EFFECTBASE_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "EffectBase.hpp"
|
#include "EffectBase.hpp"
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -12,6 +12,18 @@ class EffectChorusImp;
|
|||||||
|
|
||||||
#define AMUSE_CHORUS_NUM_BLOCKS 3
|
#define AMUSE_CHORUS_NUM_BLOCKS 3
|
||||||
|
|
||||||
|
/** Parameters needed to create EffectChorus */
|
||||||
|
struct EffectChorusInfo
|
||||||
|
{
|
||||||
|
uint32_t baseDelay = 5; /**< [5, 15] minimum value (in ms) for computed delay */
|
||||||
|
uint32_t variation = 0; /**< [0, 5] time error (in ms) to set delay within */
|
||||||
|
uint32_t period = 500; /**< [500, 10000] time (in ms) of one delay-shift cycle */
|
||||||
|
|
||||||
|
EffectChorusInfo() = default;
|
||||||
|
EffectChorusInfo(uint32_t baseDelay, uint32_t variation, uint32_t period)
|
||||||
|
: baseDelay(baseDelay), variation(variation), period(period) {}
|
||||||
|
};
|
||||||
|
|
||||||
/** Mixes the audio back into itself after continuously-varying delay */
|
/** Mixes the audio back into itself after continuously-varying delay */
|
||||||
class EffectChorus
|
class EffectChorus
|
||||||
{
|
{
|
||||||
@@ -48,6 +60,13 @@ public:
|
|||||||
x98_period = period;
|
x98_period = period;
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateParams(const EffectChorusInfo& info)
|
||||||
|
{
|
||||||
|
setBaseDelay(info.baseDelay);
|
||||||
|
setVariation(info.variation);
|
||||||
|
setPeriod(info.period);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Type-specific implementation of chorus effect */
|
/** Type-specific implementation of chorus effect */
|
||||||
@@ -91,6 +110,9 @@ class EffectChorusImp : public EffectBase<T>, public EffectChorus
|
|||||||
public:
|
public:
|
||||||
~EffectChorusImp();
|
~EffectChorusImp();
|
||||||
EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate);
|
EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate);
|
||||||
|
EffectChorusImp(const EffectChorusInfo& info, double sampleRate)
|
||||||
|
: EffectChorusImp(info.baseDelay, info.variation, info.period, sampleRate) {}
|
||||||
|
|
||||||
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
||||||
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
#define __AMUSE_EFFECTDELAY_HPP__
|
#define __AMUSE_EFFECTDELAY_HPP__
|
||||||
|
|
||||||
#include "EffectBase.hpp"
|
#include "EffectBase.hpp"
|
||||||
|
#include "IBackendVoice.hpp"
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
@@ -11,6 +12,38 @@ namespace amuse
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class EffectDelayImp;
|
class EffectDelayImp;
|
||||||
|
|
||||||
|
/** Parameters needed to create EffectDelay */
|
||||||
|
struct EffectDelayInfo
|
||||||
|
{
|
||||||
|
uint32_t delay[8]; /**< [10, 5000] time in ms of each channel's delay */
|
||||||
|
uint32_t feedback[8] = {}; /**< [0, 100] percent to mix delayed signal with input signal */
|
||||||
|
uint32_t output[8] = {}; /**< [0, 100] total output percent */
|
||||||
|
|
||||||
|
static uint32_t lerp(uint32_t v0, uint32_t v1, float t) { return (1.f - t) * v0 + t * v1; }
|
||||||
|
|
||||||
|
static void Interp3To8(uint32_t arr[8], uint32_t L, uint32_t R, uint32_t S)
|
||||||
|
{
|
||||||
|
arr[int(AudioChannel::FrontLeft)] = L;
|
||||||
|
arr[int(AudioChannel::FrontRight)] = R;
|
||||||
|
arr[int(AudioChannel::RearLeft)] = lerp(L, S, 0.75f);
|
||||||
|
arr[int(AudioChannel::RearRight)] = lerp(R, S, 0.75f);
|
||||||
|
arr[int(AudioChannel::FrontCenter)] = lerp(L, R, 0.5f);
|
||||||
|
arr[int(AudioChannel::LFE)] = arr[int(AudioChannel::FrontCenter)];
|
||||||
|
arr[int(AudioChannel::SideLeft)] = lerp(L, S, 0.5f);
|
||||||
|
arr[int(AudioChannel::SideRight)] = lerp(R, S, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectDelayInfo() { std::fill_n(delay, 8, 10); }
|
||||||
|
EffectDelayInfo(uint32_t delayL, uint32_t delayR, uint32_t delayS,
|
||||||
|
uint32_t feedbackL, uint32_t feedbackR, uint32_t feedbackS,
|
||||||
|
uint32_t outputL, uint32_t outputR, uint32_t outputS)
|
||||||
|
{
|
||||||
|
Interp3To8(delay, delayL, delayR, delayS);
|
||||||
|
Interp3To8(feedback, feedbackL, feedbackR, feedbackS);
|
||||||
|
Interp3To8(output, outputL, outputR, outputS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Mixes the audio back into itself after specified delay */
|
/** Mixes the audio back into itself after specified delay */
|
||||||
class EffectDelay
|
class EffectDelay
|
||||||
{
|
{
|
||||||
@@ -59,12 +92,24 @@ public:
|
|||||||
x54_output[i] = output;
|
x54_output[i] = output;
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setChanOutput(int chanIdx, uint32_t output)
|
void setChanOutput(int chanIdx, uint32_t output)
|
||||||
{
|
{
|
||||||
output = clamp(0u, output, 100u);
|
output = clamp(0u, output, 100u);
|
||||||
x54_output[chanIdx] = output;
|
x54_output[chanIdx] = output;
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setParams(const EffectDelayInfo& info)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
x3c_delay[i] = clamp(10u, info.delay[i], 5000u);
|
||||||
|
x48_feedback[i] = clamp(0u, info.feedback[i], 100u);
|
||||||
|
x54_output[i] = clamp(0u, info.output[i], 100u);
|
||||||
|
}
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Type-specific implementation of delay effect */
|
/** Type-specific implementation of delay effect */
|
||||||
@@ -85,6 +130,8 @@ class EffectDelayImp : public EffectBase<T>, public EffectDelay
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate);
|
EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate);
|
||||||
|
EffectDelayImp(const EffectDelayInfo& info, double sampleRate);
|
||||||
|
|
||||||
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
||||||
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,35 @@
|
|||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** Parameters needed to create EffectReverbStd */
|
||||||
|
struct EffectReverbStdInfo
|
||||||
|
{
|
||||||
|
float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */
|
||||||
|
float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */
|
||||||
|
float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */
|
||||||
|
float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
|
||||||
|
float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */
|
||||||
|
|
||||||
|
EffectReverbStdInfo() = default;
|
||||||
|
EffectReverbStdInfo(float coloration, float mix, float time, float damping, float preDelay)
|
||||||
|
: coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Parameters needed to create EffectReverbHi */
|
||||||
|
struct EffectReverbHiInfo
|
||||||
|
{
|
||||||
|
float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */
|
||||||
|
float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */
|
||||||
|
float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */
|
||||||
|
float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
|
||||||
|
float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */
|
||||||
|
float crosstalk = 0.f; /**< [0.0, 1.0] factor defining how much reflections are allowed to bleed to other channels */
|
||||||
|
|
||||||
|
EffectReverbHiInfo() = default;
|
||||||
|
EffectReverbHiInfo(float coloration, float mix, float time, float damping, float preDelay, float crosstalk)
|
||||||
|
: coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay), crosstalk(crosstalk) {}
|
||||||
|
};
|
||||||
|
|
||||||
/** Delay state for one 'tap' of the reverb effect */
|
/** Delay state for one 'tap' of the reverb effect */
|
||||||
struct ReverbDelayLine
|
struct ReverbDelayLine
|
||||||
{
|
{
|
||||||
@@ -78,6 +107,15 @@ public:
|
|||||||
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
|
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setParams(const EffectReverbStdInfo& info)
|
||||||
|
{
|
||||||
|
setColoration(info.coloration);
|
||||||
|
setMix(info.mix);
|
||||||
|
setTime(info.time);
|
||||||
|
setDamping(info.damping);
|
||||||
|
setPreDelay(info.preDelay);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Reverb effect with configurable reflection filtering, adds per-channel low-pass and crosstalk */
|
/** Reverb effect with configurable reflection filtering, adds per-channel low-pass and crosstalk */
|
||||||
@@ -98,6 +136,16 @@ public:
|
|||||||
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
|
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setParams(const EffectReverbHiInfo& info)
|
||||||
|
{
|
||||||
|
setColoration(info.coloration);
|
||||||
|
setMix(info.mix);
|
||||||
|
setTime(info.time);
|
||||||
|
setDamping(info.damping);
|
||||||
|
setPreDelay(info.preDelay);
|
||||||
|
setCrosstalk(info.crosstalk);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Standard-quality 2-stage reverb */
|
/** Standard-quality 2-stage reverb */
|
||||||
@@ -121,6 +169,9 @@ class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate);
|
EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate);
|
||||||
|
EffectReverbStdImp(const EffectReverbStdInfo& info, double sampleRate)
|
||||||
|
: EffectReverbStdImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, sampleRate) {}
|
||||||
|
|
||||||
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
||||||
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
||||||
};
|
};
|
||||||
@@ -151,6 +202,9 @@ class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi
|
|||||||
public:
|
public:
|
||||||
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
|
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
|
||||||
double sampleRate);
|
double sampleRate);
|
||||||
|
EffectReverbHiImp(const EffectReverbHiInfo& info, double sampleRate)
|
||||||
|
: EffectReverbHiImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, info.crosstalk, sampleRate) {}
|
||||||
|
|
||||||
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
|
||||||
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,34 +2,65 @@
|
|||||||
#define __AMUSE_EMITTER_HPP__
|
#define __AMUSE_EMITTER_HPP__
|
||||||
|
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class Voice;
|
class Voice;
|
||||||
|
class Listener;
|
||||||
|
|
||||||
using Vector3f = float[3];
|
using Vector3f = float[3];
|
||||||
|
|
||||||
|
static inline float Dot(const Vector3f& a, const Vector3f& b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; }
|
||||||
|
|
||||||
|
static inline float Length(const Vector3f& a)
|
||||||
|
{
|
||||||
|
if (std::fabs(a[0]) <= FLT_EPSILON && std::fabs(a[1]) <= FLT_EPSILON && std::fabs(a[2]) <= FLT_EPSILON)
|
||||||
|
return 0.f;
|
||||||
|
return std::sqrt(Dot(a, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float Normalize(Vector3f& out)
|
||||||
|
{
|
||||||
|
float dist = Length(out);
|
||||||
|
if (dist == 0.f)
|
||||||
|
return 0.f;
|
||||||
|
out[0] /= dist;
|
||||||
|
out[1] /= dist;
|
||||||
|
out[2] /= dist;
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
/** Voice wrapper with positional-3D level control */
|
/** Voice wrapper with positional-3D level control */
|
||||||
class Emitter : public Entity
|
class Emitter : public Entity
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> m_vox;
|
std::shared_ptr<Voice> m_vox;
|
||||||
|
Vector3f m_pos = {};
|
||||||
|
Vector3f m_dir = {};
|
||||||
|
float m_maxDist;
|
||||||
|
float m_maxVol = 1.f;
|
||||||
|
float m_minVol;
|
||||||
|
float m_falloff;
|
||||||
|
bool m_doppler;
|
||||||
|
bool m_dirty = true;
|
||||||
|
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
void _destroy();
|
void _destroy();
|
||||||
|
float _attenuationCurve(float dist) const;
|
||||||
|
void _update();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Emitter();
|
~Emitter();
|
||||||
Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox);
|
Emitter(Engine& engine, const AudioGroup& group, const std::shared_ptr<Voice>& vox,
|
||||||
|
float maxDist, float minVol, float falloff, bool doppler);
|
||||||
|
|
||||||
void setPos(const Vector3f& pos);
|
void setVectors(const float* pos, const float* dir);
|
||||||
void setDir(const Vector3f& dir);
|
void setMaxVol(float maxVol) { m_maxVol = clamp(0.f, maxVol, 1.f); m_dirty = true; }
|
||||||
void setMaxDist(float maxDist);
|
|
||||||
void setMaxVol(float maxVol);
|
|
||||||
void setMinVol(float minVol);
|
|
||||||
void setFalloff(float falloff);
|
|
||||||
|
|
||||||
std::shared_ptr<Voice>& getVoice() { return m_vox; }
|
const std::shared_ptr<Voice>& getVoice() const { return m_vox; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "Emitter.hpp"
|
#include "Emitter.hpp"
|
||||||
|
#include "Listener.hpp"
|
||||||
#include "AudioGroupSampleDirectory.hpp"
|
#include "AudioGroupSampleDirectory.hpp"
|
||||||
#include "Sequencer.hpp"
|
#include "Sequencer.hpp"
|
||||||
#include "Studio.hpp"
|
#include "Studio.hpp"
|
||||||
|
#include "IBackendVoiceAllocator.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -42,6 +44,7 @@ class Engine
|
|||||||
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
||||||
std::list<std::shared_ptr<Voice>> m_activeVoices;
|
std::list<std::shared_ptr<Voice>> m_activeVoices;
|
||||||
std::list<std::shared_ptr<Emitter>> m_activeEmitters;
|
std::list<std::shared_ptr<Emitter>> m_activeEmitters;
|
||||||
|
std::list<std::shared_ptr<Listener>> m_activeListeners;
|
||||||
std::list<std::shared_ptr<Sequencer>> m_activeSequencers;
|
std::list<std::shared_ptr<Sequencer>> m_activeSequencers;
|
||||||
std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
|
std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
|
||||||
bool m_defaultStudioReady = false;
|
bool m_defaultStudioReady = false;
|
||||||
@@ -49,6 +52,8 @@ class Engine
|
|||||||
std::unordered_map<uint16_t, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
std::unordered_map<uint16_t, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
||||||
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
||||||
int m_nextVid = 0;
|
int m_nextVid = 0;
|
||||||
|
float m_masterVolume = 1.f;
|
||||||
|
AudioChannelSet m_channelSet = AudioChannelSet::Unknown;
|
||||||
|
|
||||||
AudioGroup* _addAudioGroup(const AudioGroupData& data, std::unique_ptr<AudioGroup>&& grp);
|
AudioGroup* _addAudioGroup(const AudioGroupData& data, std::unique_ptr<AudioGroup>&& grp);
|
||||||
std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const;
|
std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const;
|
||||||
@@ -64,7 +69,6 @@ class Engine
|
|||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
std::list<std::shared_ptr<Sequencer>>::iterator
|
||||||
_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
|
_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
void _5MsCallback(double dt);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Engine();
|
~Engine();
|
||||||
@@ -73,9 +77,6 @@ public:
|
|||||||
/** Access voice backend of engine */
|
/** Access voice backend of engine */
|
||||||
IBackendVoiceAllocator& getBackend() { return m_backend; }
|
IBackendVoiceAllocator& getBackend() { return m_backend; }
|
||||||
|
|
||||||
/** Update all active audio entities and fill OS audio buffers as needed */
|
|
||||||
void pumpEngine();
|
|
||||||
|
|
||||||
/** Add audio group data pointers to engine; must remain resident! */
|
/** Add audio group data pointers to engine; must remain resident! */
|
||||||
const AudioGroup* addAudioGroup(const AudioGroupData& data);
|
const AudioGroup* addAudioGroup(const AudioGroupData& data);
|
||||||
|
|
||||||
@@ -96,8 +97,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist, float falloff,
|
std::shared_ptr<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
int sfxId, float minVol, float maxVol, std::weak_ptr<Studio> smx);
|
int sfxId, float minVol, float maxVol, bool doppler,
|
||||||
|
std::weak_ptr<Studio> smx);
|
||||||
|
std::shared_ptr<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
|
int sfxId, float minVol, float maxVol, bool doppler)
|
||||||
|
{
|
||||||
|
return addEmitter(pos, dir, maxDist, falloff, sfxId, minVol, maxVol, doppler, m_defaultStudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build listener and add to engine's listener list */
|
||||||
|
std::shared_ptr<Listener> addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
||||||
|
float frontDiff, float backDiff, float soundSpeed, float volume);
|
||||||
|
|
||||||
|
/** Remove listener from engine's listener list */
|
||||||
|
void removeListener(Listener* listener);
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData,
|
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData,
|
||||||
@@ -124,6 +138,14 @@ public:
|
|||||||
|
|
||||||
/** Obtain list of active sequencers */
|
/** Obtain list of active sequencers */
|
||||||
std::list<std::shared_ptr<Sequencer>>& getActiveSequencers() { return m_activeSequencers; }
|
std::list<std::shared_ptr<Sequencer>>& getActiveSequencers() { return m_activeSequencers; }
|
||||||
|
|
||||||
|
/** All mixing occurs in virtual 5ms intervals;
|
||||||
|
* this is called at the start of each interval for all mixable entities */
|
||||||
|
void _on5MsInterval(IBackendVoiceAllocator& engine, double dt);
|
||||||
|
|
||||||
|
/** When a pumping cycle is complete this is called to allow the client to
|
||||||
|
* perform periodic cleanup tasks */
|
||||||
|
void _onPumpCycleComplete(IBackendVoiceAllocator& engine);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef __AMUSE_ENTITY_HPP__
|
#ifndef __AMUSE_ENTITY_HPP__
|
||||||
#define __AMUSE_ENTITY_HPP__
|
#define __AMUSE_ENTITY_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -26,9 +26,7 @@ protected:
|
|||||||
bool m_destroyed = false;
|
bool m_destroyed = false;
|
||||||
void _destroy()
|
void _destroy()
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
#endif
|
|
||||||
m_destroyed = true;
|
m_destroyed = true;
|
||||||
}
|
}
|
||||||
Engine& m_engine;
|
Engine& m_engine;
|
||||||
@@ -42,10 +40,8 @@ public:
|
|||||||
}
|
}
|
||||||
~Entity()
|
~Entity()
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
/* Ensure proper destruction procedure followed */
|
/* Ensure proper destruction procedure followed */
|
||||||
assert(m_destroyed);
|
assert(m_destroyed);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine& getEngine() { return m_engine; }
|
Engine& getEngine() { return m_engine; }
|
||||||
|
|||||||
@@ -53,14 +53,11 @@ public:
|
|||||||
/** Amuse obtains speaker-configuration from the platform this way */
|
/** Amuse obtains speaker-configuration from the platform this way */
|
||||||
virtual AudioChannelSet getAvailableSet() = 0;
|
virtual AudioChannelSet getAvailableSet() = 0;
|
||||||
|
|
||||||
/** Amuse flushes voice samples to the backend this way */
|
|
||||||
virtual void pumpAndMixVoices() = 0;
|
|
||||||
|
|
||||||
/** Set volume of main mix out */
|
/** Set volume of main mix out */
|
||||||
virtual void setVolume(float vol) = 0;
|
virtual void setVolume(float vol) = 0;
|
||||||
|
|
||||||
/** Amuse may request callbacks 200-updates-per-second virtually */
|
/** Amuse registers for key callback events from the mixing engine this way */
|
||||||
virtual void register5MsCallback(std::function<void(double dt)>&& callback) = 0;
|
virtual void setCallbackInterface(Engine* engine) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
#ifndef __AMUSE_LISTENER_HPP__
|
#ifndef __AMUSE_LISTENER_HPP__
|
||||||
#define __AMUSE_LISTENER_HPP__
|
#define __AMUSE_LISTENER_HPP__
|
||||||
|
|
||||||
#include "Entity.hpp"
|
#include "amuse/Emitter.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
class Listener
|
||||||
class Listener : public Entity
|
|
||||||
{
|
{
|
||||||
|
friend class Emitter;
|
||||||
|
friend class Engine;
|
||||||
|
Vector3f m_pos = {};
|
||||||
|
Vector3f m_dir = {};
|
||||||
|
Vector3f m_heading = {};
|
||||||
|
Vector3f m_up = {};
|
||||||
|
Vector3f m_right = {};
|
||||||
|
float m_volume;
|
||||||
|
float m_frontDiff;
|
||||||
|
float m_backDiff;
|
||||||
|
float m_soundSpeed;
|
||||||
|
bool m_dirty = true;
|
||||||
|
public:
|
||||||
|
Listener(float volume, float frontDiff, float backDiff, float soundSpeed)
|
||||||
|
: m_volume(clamp(0.f, volume, 1.f)), m_frontDiff(frontDiff), m_backDiff(backDiff), m_soundSpeed(soundSpeed) {}
|
||||||
|
void setVectors(const float* pos, const float* dir, const float* heading, const float* up);
|
||||||
|
void setVolume(float vol) { m_volume = clamp(0.f, vol, 1.f); m_dirty = true; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "AudioGroupProject.hpp"
|
#include "AudioGroupProject.hpp"
|
||||||
#include "SongState.hpp"
|
#include "SongState.hpp"
|
||||||
#include "optional.hpp"
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -40,16 +39,23 @@ class Sequencer : public Entity
|
|||||||
bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */
|
bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */
|
||||||
|
|
||||||
float m_curVol = 1.f; /**< Current volume of sequencer */
|
float m_curVol = 1.f; /**< Current volume of sequencer */
|
||||||
|
float m_volFadeTime = 0.f;
|
||||||
|
float m_volFadeTarget = 0.f;
|
||||||
|
float m_volFadeStart = 0.f;
|
||||||
|
float m_stopFadeTime = 0.f;
|
||||||
|
float m_stopFadeBeginVol = 0.f;
|
||||||
|
|
||||||
/** State of a single MIDI channel */
|
/** State of a single MIDI channel */
|
||||||
struct ChannelState
|
struct ChannelState
|
||||||
{
|
{
|
||||||
Sequencer& m_parent;
|
Sequencer* m_parent = nullptr;
|
||||||
uint8_t m_chanId;
|
uint8_t m_chanId;
|
||||||
const SongGroupIndex::MIDISetup* m_setup = nullptr; /* Channel defaults to program 0 if null */
|
const SongGroupIndex::MIDISetup* m_setup = nullptr; /* Channel defaults to program 0 if null */
|
||||||
const SongGroupIndex::PageEntry* m_page = nullptr;
|
const SongGroupIndex::PageEntry* m_page = nullptr;
|
||||||
~ChannelState();
|
~ChannelState();
|
||||||
|
ChannelState() = default;
|
||||||
ChannelState(Sequencer& parent, uint8_t chanId);
|
ChannelState(Sequencer& parent, uint8_t chanId);
|
||||||
|
operator bool() const { return m_parent != nullptr; }
|
||||||
|
|
||||||
/** Voices corresponding to currently-pressed keys in channel */
|
/** Voices corresponding to currently-pressed keys in channel */
|
||||||
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
||||||
@@ -77,7 +83,7 @@ class Sequencer : public Entity
|
|||||||
std::shared_ptr<Voice> findVoice(int vid);
|
std::shared_ptr<Voice> findVoice(int vid);
|
||||||
void sendMacroMessage(ObjectId macroId, int32_t val);
|
void sendMacroMessage(ObjectId macroId, int32_t val);
|
||||||
};
|
};
|
||||||
std::array<std::experimental::optional<ChannelState>, 16> m_chanStates; /**< Lazily-allocated channel states */
|
std::array<ChannelState, 16> m_chanStates; /**< Lazily-allocated channel states */
|
||||||
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
void _destroy();
|
void _destroy();
|
||||||
@@ -135,10 +141,10 @@ public:
|
|||||||
void playSong(const unsigned char* arrData, bool dieOnEnd = true);
|
void playSong(const unsigned char* arrData, bool dieOnEnd = true);
|
||||||
|
|
||||||
/** Stop current MIDI arrangement */
|
/** Stop current MIDI arrangement */
|
||||||
void stopSong(bool now = false);
|
void stopSong(float fadeTime = 0.f, bool now = false);
|
||||||
|
|
||||||
/** Set total volume of sequencer */
|
/** Set total volume of sequencer */
|
||||||
void setVolume(float vol);
|
void setVolume(float vol, float fadeTime = 0.f);
|
||||||
|
|
||||||
/** Get current program number of channel */
|
/** Get current program number of channel */
|
||||||
int8_t getChanProgram(int8_t chanId) const;
|
int8_t getChanProgram(int8_t chanId) const;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define __AMUSE_SONGCONVERTER_HPP__
|
#define __AMUSE_SONGCONVERTER_HPP__
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#ifndef __AMUSE_SONGSTATE_HPP__
|
#ifndef __AMUSE_SONGSTATE_HPP__
|
||||||
#define __AMUSE_SONGSTATE_HPP__
|
#define __AMUSE_SONGSTATE_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "optional.hpp"
|
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
@@ -71,7 +70,7 @@ class SongState
|
|||||||
void swapBig();
|
void swapBig();
|
||||||
};
|
};
|
||||||
|
|
||||||
SongState& m_parent;
|
SongState* m_parent = nullptr;
|
||||||
uint8_t m_midiChan; /**< MIDI channel number of song channel */
|
uint8_t m_midiChan; /**< MIDI channel number of song channel */
|
||||||
const TrackRegion* m_curRegion; /**< Pointer to currently-playing track region */
|
const TrackRegion* m_curRegion; /**< Pointer to currently-playing track region */
|
||||||
const TrackRegion* m_nextRegion; /**< Pointer to next-queued track region */
|
const TrackRegion* m_nextRegion; /**< Pointer to next-queued track region */
|
||||||
@@ -89,12 +88,14 @@ class SongState
|
|||||||
int32_t m_lastN64EventTick =
|
int32_t m_lastN64EventTick =
|
||||||
0; /**< Last command time on this channel (for computing delta times from absolute times in N64 songs) */
|
0; /**< Last command time on this channel (for computing delta times from absolute times in N64 songs) */
|
||||||
|
|
||||||
|
Track() = default;
|
||||||
Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions);
|
Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions);
|
||||||
|
operator bool() const { return m_parent != nullptr; }
|
||||||
void setRegion(Sequencer* seq, const TrackRegion* region);
|
void setRegion(Sequencer* seq, const TrackRegion* region);
|
||||||
void advanceRegion(Sequencer* seq);
|
void advanceRegion(Sequencer* seq);
|
||||||
bool advance(Sequencer& seq, int32_t ticks);
|
bool advance(Sequencer& seq, int32_t ticks);
|
||||||
};
|
};
|
||||||
std::array<std::experimental::optional<Track>, 64> m_tracks;
|
std::array<Track, 64> m_tracks;
|
||||||
const uint32_t* m_regionIdx; /**< Table of offsets to song-region data */
|
const uint32_t* m_regionIdx; /**< Table of offsets to song-region data */
|
||||||
|
|
||||||
/** Current pointer to tempo control, iterated over playback */
|
/** Current pointer to tempo control, iterated over playback */
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
#ifndef __AMUSE_SOUNDMACROSTATE_HPP__
|
#ifndef __AMUSE_SOUNDMACROSTATE_HPP__
|
||||||
#define __AMUSE_SOUNDMACROSTATE_HPP__
|
#define __AMUSE_SOUNDMACROSTATE_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
/* Squelch Win32 macro pollution >.< */
|
||||||
|
#undef SendMessage
|
||||||
|
#undef GetMessage
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -76,7 +81,7 @@ class SoundMacroState
|
|||||||
SetAgeCount, /* unimplemented */
|
SetAgeCount, /* unimplemented */
|
||||||
SendFlag, /* unimplemented */
|
SendFlag, /* unimplemented */
|
||||||
PitchWheelR,
|
PitchWheelR,
|
||||||
SetPriority, /* unimplemented */
|
SetPriority = 0x36, /* unimplemented */
|
||||||
AddPriority, /* unimplemented */
|
AddPriority, /* unimplemented */
|
||||||
AgeCntSpeed, /* unimplemented */
|
AgeCntSpeed, /* unimplemented */
|
||||||
AgeCntVel, /* unimplemented */
|
AgeCntVel, /* unimplemented */
|
||||||
@@ -119,6 +124,17 @@ class SoundMacroState
|
|||||||
/** 'program counter' stack for the active SoundMacro */
|
/** 'program counter' stack for the active SoundMacro */
|
||||||
std::vector<std::pair<const unsigned char*, int>> m_pc;
|
std::vector<std::pair<const unsigned char*, int>> m_pc;
|
||||||
|
|
||||||
|
static int _assertPC(int pc, uint32_t size);
|
||||||
|
static int _assertPC(int pc, uint32_t size, bool swapSize)
|
||||||
|
{
|
||||||
|
return _assertPC(pc, swapSize ? SBig(size) : size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setPC(int pc)
|
||||||
|
{
|
||||||
|
m_pc.back().second = _assertPC(pc, m_header.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
double m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */
|
double m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */
|
||||||
uint8_t m_initVel; /**< Velocity played for this macro invocation */
|
uint8_t m_initVel; /**< Velocity played for this macro invocation */
|
||||||
uint8_t m_initMod; /**< Modulation played for this macro invocation */
|
uint8_t m_initMod; /**< Modulation played for this macro invocation */
|
||||||
|
|||||||
@@ -60,16 +60,28 @@ public:
|
|||||||
/** Add new chorus effect to effect stack and assume ownership */
|
/** Add new chorus effect to effect stack and assume ownership */
|
||||||
EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
|
EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
|
||||||
|
|
||||||
|
/** Add new chorus effect to effect stack and assume ownership */
|
||||||
|
EffectChorus& makeChorus(const EffectChorusInfo& info);
|
||||||
|
|
||||||
/** Add new delay effect to effect stack and assume ownership */
|
/** Add new delay effect to effect stack and assume ownership */
|
||||||
EffectDelay& makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput);
|
EffectDelay& makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput);
|
||||||
|
|
||||||
|
/** Add new delay effect to effect stack and assume ownership */
|
||||||
|
EffectDelay& makeDelay(const EffectDelayInfo& info);
|
||||||
|
|
||||||
/** Add new standard-quality reverb effect to effect stack and assume ownership */
|
/** Add new standard-quality reverb effect to effect stack and assume ownership */
|
||||||
EffectReverbStd& makeReverbStd(float coloration, float mix, float time, float damping, float preDelay);
|
EffectReverbStd& makeReverbStd(float coloration, float mix, float time, float damping, float preDelay);
|
||||||
|
|
||||||
|
/** Add new standard-quality reverb effect to effect stack and assume ownership */
|
||||||
|
EffectReverbStd& makeReverbStd(const EffectReverbStdInfo& info);
|
||||||
|
|
||||||
/** Add new high-quality reverb effect to effect stack and assume ownership */
|
/** Add new high-quality reverb effect to effect stack and assume ownership */
|
||||||
EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
|
EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
|
||||||
float crosstalk);
|
float crosstalk);
|
||||||
|
|
||||||
|
/** Add new high-quality reverb effect to effect stack and assume ownership */
|
||||||
|
EffectReverbHi& makeReverbHi(const EffectReverbHiInfo& info);
|
||||||
|
|
||||||
/** Remove and deallocate all effects from effect stack */
|
/** Remove and deallocate all effects from effect stack */
|
||||||
void clearEffects() { m_effectStack.clear(); }
|
void clearEffects() { m_effectStack.clear(); }
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#ifndef __AMUSE_SURROUNDPROFILES_HPP__
|
|
||||||
#define __AMUSE_SURROUNDPROFILES_HPP__
|
|
||||||
|
|
||||||
#include "IBackendVoice.hpp"
|
|
||||||
#include "IBackendVoiceAllocator.hpp"
|
|
||||||
#include "Emitter.hpp"
|
|
||||||
|
|
||||||
namespace amuse
|
|
||||||
{
|
|
||||||
struct ReferenceVector;
|
|
||||||
|
|
||||||
/** Support class for attenuating channel audio based on speaker 'positions' */
|
|
||||||
class SurroundProfiles
|
|
||||||
{
|
|
||||||
static void SetupRefs(float matOut[8], const ChannelMap& map, const Vector3f& listenEmit,
|
|
||||||
const ReferenceVector refs[]);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void SetupMatrix(float matOut[8], const ChannelMap& map, AudioChannelSet set, const Vector3f& emitPos,
|
|
||||||
const Vector3f& listenPos, const Vector3f& listenDir, const Vector3f& listenUp);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __AMUSE_SURROUNDPROFILES_HPP__
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef __AMUSE_VOICE_HPP__
|
#ifndef __AMUSE_VOICE_HPP__
|
||||||
#define __AMUSE_VOICE_HPP__
|
#define __AMUSE_VOICE_HPP__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "SoundMacroState.hpp"
|
#include "SoundMacroState.hpp"
|
||||||
@@ -33,6 +33,7 @@ class Voice : public Entity
|
|||||||
friend class Sequencer;
|
friend class Sequencer;
|
||||||
friend class SoundMacroState;
|
friend class SoundMacroState;
|
||||||
friend class Envelope;
|
friend class Envelope;
|
||||||
|
friend class Emitter;
|
||||||
int m_vid; /**< VoiceID of this voice instance */
|
int m_vid; /**< VoiceID of this voice instance */
|
||||||
bool m_emitter; /**< Voice is part of an Emitter */
|
bool m_emitter; /**< Voice is part of an Emitter */
|
||||||
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
|
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
|
||||||
@@ -62,7 +63,8 @@ class Voice : public Entity
|
|||||||
uint32_t m_lastSamplePos = 0; /**< Last sample position (or last loop sample) */
|
uint32_t m_lastSamplePos = 0; /**< Last sample position (or last loop sample) */
|
||||||
int16_t m_prev1 = 0; /**< DSPADPCM prev sample */
|
int16_t m_prev1 = 0; /**< DSPADPCM prev sample */
|
||||||
int16_t m_prev2 = 0; /**< DSPADPCM prev-prev sample */
|
int16_t m_prev2 = 0; /**< DSPADPCM prev-prev sample */
|
||||||
double m_sampleRate = 32000.0; /**< Current sample rate computed from relative sample key or SETPITCH */
|
double m_dopplerRatio = 1.0; /**< Current ratio to mix with chromatic pitch for doppler effects */
|
||||||
|
double m_sampleRate = NativeSampleRate; /**< Current sample rate computed from relative sample key or SETPITCH */
|
||||||
double m_voiceTime = 0.0; /**< Current seconds of voice playback (per-sample resolution) */
|
double m_voiceTime = 0.0; /**< Current seconds of voice playback (per-sample resolution) */
|
||||||
uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */
|
uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */
|
||||||
float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */
|
float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */
|
||||||
@@ -80,8 +82,8 @@ class Voice : public Entity
|
|||||||
float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
|
float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
|
||||||
float m_userPan = 0.f; /**< User pan of voice */
|
float m_userPan = 0.f; /**< User pan of voice */
|
||||||
float m_curPan = 0.f; /**< Current pan of voice */
|
float m_curPan = 0.f; /**< Current pan of voice */
|
||||||
float m_userSpan = 0.f; /**< User span of voice */
|
float m_userSpan = -1.f; /**< User span of voice */
|
||||||
float m_curSpan = 0.f; /**< Current surround pan of voice */
|
float m_curSpan = -1.f; /**< Current surround pan of voice */
|
||||||
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */
|
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */
|
||||||
int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */
|
int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */
|
||||||
int32_t m_pitchWheelDown = 600; /**< Down range for pitchwheel control in cents */
|
int32_t m_pitchWheelDown = 600; /**< Down range for pitchwheel control in cents */
|
||||||
@@ -104,8 +106,8 @@ class Voice : public Entity
|
|||||||
float m_portamentoTime = -1.f; /**< time since last portamento invocation, -1 for no active portamento-glide */
|
float m_portamentoTime = -1.f; /**< time since last portamento invocation, -1 for no active portamento-glide */
|
||||||
int32_t m_portamentoTarget; /**< destination pitch for latest portamento invocation */
|
int32_t m_portamentoTarget; /**< destination pitch for latest portamento invocation */
|
||||||
|
|
||||||
uint32_t m_pitchSweep1 = 0; /**< Current value of PITCHSWEEP1 controller (in cents) */
|
int32_t m_pitchSweep1 = 0; /**< Current value of PITCHSWEEP1 controller (in cents) */
|
||||||
uint32_t m_pitchSweep2 = 0; /**< Current value of PITCHSWEEP2 controller (in cents) */
|
int32_t m_pitchSweep2 = 0; /**< Current value of PITCHSWEEP2 controller (in cents) */
|
||||||
int16_t m_pitchSweep1Add = 0; /**< Value to add to PITCHSWEEP1 controller each cycle */
|
int16_t m_pitchSweep1Add = 0; /**< Value to add to PITCHSWEEP1 controller each cycle */
|
||||||
int16_t m_pitchSweep2Add = 0; /**< Value to add to PITCHSWEEP2 controller each cycle */
|
int16_t m_pitchSweep2Add = 0; /**< Value to add to PITCHSWEEP2 controller each cycle */
|
||||||
uint8_t m_pitchSweep1Times = 0; /**< Remaining times to advance PITCHSWEEP1 controller */
|
uint8_t m_pitchSweep1Times = 0; /**< Remaining times to advance PITCHSWEEP1 controller */
|
||||||
@@ -123,6 +125,7 @@ class Voice : public Entity
|
|||||||
uint8_t m_spanPos; /**< initial pan value of last SPANNING command */
|
uint8_t m_spanPos; /**< initial pan value of last SPANNING command */
|
||||||
int8_t m_spanWidth; /**< delta pan value to target of last SPANNING command */
|
int8_t m_spanWidth; /**< delta pan value to target of last SPANNING command */
|
||||||
|
|
||||||
|
float m_vibratoTime = -1.f; /**< time since last VIBRATO command, -1 for no active vibrato */
|
||||||
int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */
|
int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */
|
||||||
int32_t m_vibratoModLevel = 0; /**< scale of vibrato mod-wheel influence (in cents) */
|
int32_t m_vibratoModLevel = 0; /**< scale of vibrato mod-wheel influence (in cents) */
|
||||||
float m_vibratoPeriod = 0.f; /**< vibrato wave period-time, 0.f will disable vibrato */
|
float m_vibratoPeriod = 0.f; /**< vibrato wave period-time, 0.f will disable vibrato */
|
||||||
@@ -166,8 +169,10 @@ class Voice : public Entity
|
|||||||
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
|
|
||||||
|
void _panLaw(float coefsOut[8], float frontPan, float backPan, float totalSpan) const;
|
||||||
void _setPan(float pan);
|
void _setPan(float pan);
|
||||||
void _setSurroundPan(float span);
|
void _setSurroundPan(float span);
|
||||||
|
void _setChannelCoefs(const float coefs[8]);
|
||||||
void _setPitchWheel(float pitchWheel);
|
void _setPitchWheel(float pitchWheel);
|
||||||
void _notifyCtrlChange(uint8_t ctrl, int8_t val);
|
void _notifyCtrlChange(uint8_t ctrl, int8_t val);
|
||||||
|
|
||||||
@@ -231,6 +236,9 @@ public:
|
|||||||
/** Set current voice surround-panning immediately */
|
/** Set current voice surround-panning immediately */
|
||||||
void setSurroundPan(float span);
|
void setSurroundPan(float span);
|
||||||
|
|
||||||
|
/** Set current voice channel coefficients immediately */
|
||||||
|
void setChannelCoefs(const float coefs[8]);
|
||||||
|
|
||||||
/** Start volume envelope to specified level */
|
/** Start volume envelope to specified level */
|
||||||
void startEnvelope(double dur, float vol, const Curve* envCurve);
|
void startEnvelope(double dur, float vol, const Curve* envCurve);
|
||||||
|
|
||||||
@@ -253,7 +261,7 @@ public:
|
|||||||
void setDoppler(float doppler);
|
void setDoppler(float doppler);
|
||||||
|
|
||||||
/** Set vibrato parameters for voice */
|
/** Set vibrato parameters for voice */
|
||||||
void setVibrato(int32_t level, int32_t modLevel, float period);
|
void setVibrato(int32_t level, bool modScale, float period);
|
||||||
|
|
||||||
/** Configure modwheel influence range over vibrato */
|
/** Configure modwheel influence range over vibrato */
|
||||||
void setMod2VibratoRange(int32_t modLevel);
|
void setMod2VibratoRange(int32_t modLevel);
|
||||||
@@ -312,7 +320,7 @@ public:
|
|||||||
if (!m_extCtrlVals)
|
if (!m_extCtrlVals)
|
||||||
{
|
{
|
||||||
if (m_ctrlValsSelf)
|
if (m_ctrlValsSelf)
|
||||||
m_ctrlValsSelf[ctrl];
|
return m_ctrlValsSelf[ctrl];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_extCtrlVals[ctrl];
|
return m_extCtrlVals[ctrl];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef __AMUSE_AMUSE_HPP__
|
#ifndef __AMUSE_AMUSE_HPP__
|
||||||
#define __AMUSE_AMUSE_HPP__
|
#define __AMUSE_AMUSE_HPP__
|
||||||
|
|
||||||
|
|
||||||
#include "AudioGroup.hpp"
|
#include "AudioGroup.hpp"
|
||||||
#include "AudioGroupData.hpp"
|
#include "AudioGroupData.hpp"
|
||||||
#include "AudioGroupPool.hpp"
|
#include "AudioGroupPool.hpp"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other)
|
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other) noexcept
|
||||||
: AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz, other.m_sdir, other.m_sdirSz, other.m_samp,
|
: AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz, other.m_sdir, other.m_sdirSz, other.m_samp,
|
||||||
other.m_sampSz, other.m_fmt, other.m_absOffs)
|
other.m_sampSz, other.m_fmt, other.m_absOffs)
|
||||||
{
|
{
|
||||||
@@ -22,7 +22,7 @@ IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other
|
|||||||
other.m_owns = false;
|
other.m_owns = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntrusiveAudioGroupData& IntrusiveAudioGroupData::operator=(IntrusiveAudioGroupData&& other)
|
IntrusiveAudioGroupData& IntrusiveAudioGroupData::operator=(IntrusiveAudioGroupData&& other) noexcept
|
||||||
{
|
{
|
||||||
if (m_owns)
|
if (m_owns)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||||||
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur + 8));
|
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur + 8));
|
||||||
mappingsOut.reserve(count);
|
mappingsOut.reserve(count);
|
||||||
const unsigned char* subcur = cur + 12;
|
const unsigned char* subcur = cur + 12;
|
||||||
for (int i = 0; i < count; ++i)
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
||||||
|
|
||||||
cur += size;
|
cur += size;
|
||||||
@@ -133,7 +133,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data, PCDataTag)
|
|||||||
uint32_t count = *reinterpret_cast<const uint32_t*>(cur + 8);
|
uint32_t count = *reinterpret_cast<const uint32_t*>(cur + 8);
|
||||||
mappingsOut.reserve(count);
|
mappingsOut.reserve(count);
|
||||||
const unsigned char* subcur = cur + 12;
|
const unsigned char* subcur = cur + 12;
|
||||||
for (int i = 0; i < count; ++i)
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
||||||
|
|
||||||
cur += size;
|
cur += size;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "amuse/AudioGroupSampleDirectory.hpp"
|
#include "amuse/AudioGroupSampleDirectory.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&, size_t fra
|
|||||||
return m_parent.m_clientVox.supplyAudio(frames, data);
|
return m_parent.m_clientVox.supplyAudio(frames, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, double dt, int busId, int16_t* in, int16_t* out)
|
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out)
|
||||||
{
|
{
|
||||||
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, double dt, int busId, int32_t* in, int32_t* out)
|
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out)
|
||||||
{
|
{
|
||||||
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, double dt, int busId, float* in, float* out)
|
void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out)
|
||||||
{
|
{
|
||||||
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,11 @@ void BooBackendMIDIReader::stopSeq() {}
|
|||||||
|
|
||||||
void BooBackendMIDIReader::reset() {}
|
void BooBackendMIDIReader::reset() {}
|
||||||
|
|
||||||
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : m_booEngine(booEngine) {}
|
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
||||||
|
: m_booEngine(booEngine)
|
||||||
|
{
|
||||||
|
booEngine.setCallbackInterface(this);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IBackendVoice> BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate,
|
std::unique_ptr<IBackendVoice> BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate,
|
||||||
bool dynamicPitch)
|
bool dynamicPitch)
|
||||||
@@ -280,14 +284,24 @@ std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoiceAllocator::register5MsCallback(std::function<void(double)>&& callback)
|
void BooBackendVoiceAllocator::setCallbackInterface(Engine* engine)
|
||||||
{
|
{
|
||||||
m_booEngine.register5MsCallback(std::move(callback));
|
m_cbInterface = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); }
|
AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); }
|
||||||
|
|
||||||
void BooBackendVoiceAllocator::pumpAndMixVoices() { m_booEngine.pumpAndMixVoices(); }
|
|
||||||
|
|
||||||
void BooBackendVoiceAllocator::setVolume(float vol) { m_booEngine.setVolume(vol); }
|
void BooBackendVoiceAllocator::setVolume(float vol) { m_booEngine.setVolume(vol); }
|
||||||
|
|
||||||
|
void BooBackendVoiceAllocator::on5MsInterval(boo::IAudioVoiceEngine& engine, double dt)
|
||||||
|
{
|
||||||
|
if (m_cbInterface)
|
||||||
|
m_cbInterface->_on5MsInterval(*this, dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooBackendVoiceAllocator::onPumpCycleComplete(boo::IAudioVoiceEngine& engine)
|
||||||
|
{
|
||||||
|
if (m_cbInterface)
|
||||||
|
m_cbInterface->_onPumpCycleComplete(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#include "amuse/ContainerRegistry.hpp"
|
#include "amuse/ContainerRegistry.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <string.h>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <lzo/lzo1x.h>
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
@@ -420,9 +422,6 @@ static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadMP1
|
|||||||
|
|
||||||
static bool ValidateMP2(FILE* fp)
|
static bool ValidateMP2(FILE* fp)
|
||||||
{
|
{
|
||||||
if (FileLength(fp) > 40 * 1024 * 1024)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
fread(&magic, 1, 4, fp);
|
fread(&magic, 1, 4, fp);
|
||||||
magic = SBig(magic);
|
magic = SBig(magic);
|
||||||
@@ -448,7 +447,8 @@ static bool ValidateMP2(FILE* fp)
|
|||||||
resCount = SBig(resCount);
|
resCount = SBig(resCount);
|
||||||
for (uint32_t i = 0; i < resCount; ++i)
|
for (uint32_t i = 0; i < resCount; ++i)
|
||||||
{
|
{
|
||||||
FSeek(fp, 4, SEEK_CUR);
|
uint32_t compressed;
|
||||||
|
fread(&compressed, 1, 4, fp);
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
fread(&type, 1, 4, fp);
|
fread(&type, 1, 4, fp);
|
||||||
type = SBig(type);
|
type = SBig(type);
|
||||||
@@ -462,13 +462,28 @@ static bool ValidateMP2(FILE* fp)
|
|||||||
int64_t origPos = FTell(fp);
|
int64_t origPos = FTell(fp);
|
||||||
FSeek(fp, offset, SEEK_SET);
|
FSeek(fp, offset, SEEK_SET);
|
||||||
char testBuf[4];
|
char testBuf[4];
|
||||||
if (fread(testBuf, 1, 4, fp) == 4)
|
if (!compressed)
|
||||||
{
|
{
|
||||||
if (amuse::SBig(*reinterpret_cast<uint32_t*>(testBuf)) == 0x1)
|
if (fread(testBuf, 1, 4, fp) != 4)
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FSeek(fp, 4, SEEK_CUR);
|
||||||
|
uint16_t chunkSz;
|
||||||
|
fread(&chunkSz, 1, 2, fp);
|
||||||
|
chunkSz = SBig(chunkSz);
|
||||||
|
uint8_t compBuf[0x8000];
|
||||||
|
uint8_t destBuf[0x8000 * 2];
|
||||||
|
fread(compBuf, 1, chunkSz, fp);
|
||||||
|
lzo_uint dsz = 0x8000 * 2;
|
||||||
|
lzo1x_decompress(compBuf, chunkSz, destBuf, &dsz, nullptr);
|
||||||
|
memcpy(testBuf, destBuf, 4);
|
||||||
|
}
|
||||||
|
if (amuse::SBig(*reinterpret_cast<uint32_t*>(testBuf)) == 0x1)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
FSeek(fp, origPos, SEEK_SET);
|
FSeek(fp, origPos, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,7 +523,8 @@ static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadMP2(FIL
|
|||||||
ret.reserve(resCount);
|
ret.reserve(resCount);
|
||||||
for (uint32_t i = 0; i < resCount; ++i)
|
for (uint32_t i = 0; i < resCount; ++i)
|
||||||
{
|
{
|
||||||
FSeek(fp, 4, SEEK_CUR);
|
uint32_t compressed;
|
||||||
|
fread(&compressed, 1, 4, fp);
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
fread(&type, 1, 4, fp);
|
fread(&type, 1, 4, fp);
|
||||||
type = SBig(type);
|
type = SBig(type);
|
||||||
@@ -522,6 +538,33 @@ static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadMP2(FIL
|
|||||||
int64_t origPos = FTell(fp);
|
int64_t origPos = FTell(fp);
|
||||||
FSeek(fp, offset, SEEK_SET);
|
FSeek(fp, offset, SEEK_SET);
|
||||||
char testBuf[4];
|
char testBuf[4];
|
||||||
|
FILE* old_fp = fp;
|
||||||
|
if (compressed)
|
||||||
|
{
|
||||||
|
uint32_t decompSz;
|
||||||
|
fread(&decompSz, 1, 4, fp);
|
||||||
|
decompSz = SBig(decompSz);
|
||||||
|
uint8_t compBuf[0x8000];
|
||||||
|
uint8_t* buf = new uint8_t[decompSz];
|
||||||
|
uint8_t* bufCur = buf;
|
||||||
|
uint32_t rem = decompSz;
|
||||||
|
while (rem)
|
||||||
|
{
|
||||||
|
uint16_t chunkSz;
|
||||||
|
fread(&chunkSz, 1, 2, fp);
|
||||||
|
chunkSz = SBig(chunkSz);
|
||||||
|
fread(compBuf, 1, chunkSz, fp);
|
||||||
|
lzo_uint dsz = rem;
|
||||||
|
lzo1x_decompress(compBuf, chunkSz, bufCur, &dsz, nullptr);
|
||||||
|
bufCur += dsz;
|
||||||
|
rem -= dsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = FOpen(_S("amuse_tmp.dat"), _S("rw"));
|
||||||
|
rewind(fp);
|
||||||
|
fwrite(buf, 1, decompSz, fp);
|
||||||
|
rewind(fp);
|
||||||
|
}
|
||||||
if (fread(testBuf, 1, 4, fp) == 4)
|
if (fread(testBuf, 1, 4, fp) == 4)
|
||||||
{
|
{
|
||||||
if (amuse::SBig(*reinterpret_cast<uint32_t*>(testBuf)) == 0x1)
|
if (amuse::SBig(*reinterpret_cast<uint32_t*>(testBuf)) == 0x1)
|
||||||
@@ -567,6 +610,12 @@ static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadMP2(FIL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (compressed)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
Unlink(_S("amuse_tmp.dat"));
|
||||||
|
}
|
||||||
|
fp = old_fp;
|
||||||
FSeek(fp, origPos, SEEK_SET);
|
FSeek(fp, origPos, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1753,7 +1802,6 @@ static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadPap
|
|||||||
if (songDesc.name[0] == 0)
|
if (songDesc.name[0] == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint32_t i = 0;
|
|
||||||
songDescs.push_back(songDesc);
|
songDescs.push_back(songDesc);
|
||||||
}
|
}
|
||||||
size_t endPos = FileLength(midifp);
|
size_t endPos = FileLength(midifp);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ unsigned DSPDecompressFrame(int16_t* out, const uint8_t* in,
|
|||||||
int32_t factor2 = coefs[cIdx][1];
|
int32_t factor2 = coefs[cIdx][1];
|
||||||
uint8_t exp = in[0] & 0xf;
|
uint8_t exp = in[0] & 0xf;
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
for (unsigned s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
{
|
{
|
||||||
int32_t sampleData = (s&1)?
|
int32_t sampleData = (s&1)?
|
||||||
NibbleToInt[(in[s/2+1])&0xf]:
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
@@ -41,7 +41,7 @@ unsigned DSPDecompressFrameStereoStride(int16_t* out, const uint8_t* in,
|
|||||||
int32_t factor2 = coefs[cIdx][1];
|
int32_t factor2 = coefs[cIdx][1];
|
||||||
uint32_t exp = in[0] & 0xf;
|
uint32_t exp = in[0] & 0xf;
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
for (unsigned s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
{
|
{
|
||||||
int32_t sampleData = (s&1)?
|
int32_t sampleData = (s&1)?
|
||||||
NibbleToInt[(in[s/2+1])&0xf]:
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
@@ -71,7 +71,7 @@ unsigned DSPDecompressFrameStereoDupe(int16_t* out, const uint8_t* in,
|
|||||||
int32_t factor2 = coefs[cIdx][1];
|
int32_t factor2 = coefs[cIdx][1];
|
||||||
uint8_t exp = in[0] & 0xf;
|
uint8_t exp = in[0] & 0xf;
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
for (unsigned s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
{
|
{
|
||||||
int32_t sampleData = (s&1)?
|
int32_t sampleData = (s&1)?
|
||||||
NibbleToInt[(in[s/2+1])&0xf]:
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
@@ -102,7 +102,7 @@ unsigned DSPDecompressFrameRanged(int16_t* out, const uint8_t* in,
|
|||||||
int32_t factor2 = coefs[cIdx][1];
|
int32_t factor2 = coefs[cIdx][1];
|
||||||
uint8_t exp = in[0] & 0xf;
|
uint8_t exp = in[0] & 0xf;
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (int s=firstSample ; s<14 && s<lastSample ; ++s)
|
for (unsigned s=firstSample ; s<14 && s<lastSample ; ++s)
|
||||||
{
|
{
|
||||||
int32_t sampleData = (s&1)?
|
int32_t sampleData = (s&1)?
|
||||||
NibbleToInt[(in[s/2+1])&0xf]:
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
@@ -132,7 +132,7 @@ unsigned DSPDecompressFrameStateOnly(const uint8_t* in,
|
|||||||
int32_t factor2 = coefs[cIdx][1];
|
int32_t factor2 = coefs[cIdx][1];
|
||||||
uint8_t exp = in[0] & 0xf;
|
uint8_t exp = in[0] & 0xf;
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
for (unsigned s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
{
|
{
|
||||||
int32_t sampleData = (s&1)?
|
int32_t sampleData = (s&1)?
|
||||||
NibbleToInt[(in[s/2+1])&0xf]:
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool sizeSort, bool reverse, bool noHidden)
|
DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, bool noHidden)
|
||||||
{
|
{
|
||||||
Sstat theStat;
|
Sstat theStat;
|
||||||
if (Stat(path, &theStat) || !S_ISDIR(theStat.st_mode))
|
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@@ -60,7 +60,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
|
m_entries.emplace_back(fp, d.cFileName, sz, isDir);
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
break;
|
break;
|
||||||
case Mode::DirsThenFilesSorted:
|
case Mode::DirsThenFilesSorted:
|
||||||
@@ -79,9 +79,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
|
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, 0, true)));
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
@@ -114,9 +115,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
|
sort.emplace(std::make_pair(st.st_size, Entry(fp, d.cFileName, st.st_size, false)));
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
@@ -139,9 +141,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
|
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, st.st_size, false)));
|
||||||
} while (FindNextFileW(dir, &d));
|
} while (FindNextFileW(dir, &d));
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
@@ -157,7 +160,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
DIR* dir = opendir(path);
|
DIR* dir = opendir(path.data());
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return;
|
return;
|
||||||
const dirent* d;
|
const dirent* d;
|
||||||
@@ -186,7 +189,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_entries.push_back(std::move(Entry(std::move(fp), d->d_name, sz, isDir)));
|
m_entries.emplace_back(fp, d->d_name, sz, isDir);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Mode::DirsThenFilesSorted:
|
case Mode::DirsThenFilesSorted:
|
||||||
@@ -205,9 +208,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, 0, true)));
|
sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, 0, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
@@ -239,9 +243,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d->d_name, st.st_size, false)));
|
sort.emplace(std::make_pair(st.st_size, Entry(fp, d->d_name, st.st_size, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
@@ -264,9 +269,10 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, bool
|
|||||||
Sstat st;
|
Sstat st;
|
||||||
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||||
continue;
|
continue;
|
||||||
sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, st.st_size, false)));
|
sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, st.st_size, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_entries.reserve(sort.size());
|
||||||
if (reverse)
|
if (reverse)
|
||||||
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
|
||||||
m_entries.push_back(std::move(it->second));
|
m_entries.push_back(std::move(it->second));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "amuse/EffectChorus.hpp"
|
#include "amuse/EffectChorus.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/IBackendVoice.hpp"
|
#include "amuse/IBackendVoice.hpp"
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
@@ -10,134 +10,134 @@ namespace amuse
|
|||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
static const float rsmpTab12khz[] =
|
static const float rsmpTab12khz[] =
|
||||||
{
|
{
|
||||||
0.097504, 0.802216, 0.101593, -0.000977,
|
0.097504f, 0.802216f, 0.101593f, -0.000977f,
|
||||||
0.093506, 0.802032, 0.105804, -0.001038,
|
0.093506f, 0.802032f, 0.105804f, -0.001038f,
|
||||||
0.089600, 0.801697, 0.110107, -0.001160,
|
0.089600f, 0.801697f, 0.110107f, -0.001160f,
|
||||||
0.085785, 0.801178, 0.114471, -0.001282,
|
0.085785f, 0.801178f, 0.114471f, -0.001282f,
|
||||||
0.082031, 0.800476, 0.118927, -0.001404,
|
0.082031f, 0.800476f, 0.118927f, -0.001404f,
|
||||||
0.078369, 0.799622, 0.123474, -0.001526,
|
0.078369f, 0.799622f, 0.123474f, -0.001526f,
|
||||||
0.074799, 0.798615, 0.128143, -0.001648,
|
0.074799f, 0.798615f, 0.128143f, -0.001648f,
|
||||||
0.071350, 0.797424, 0.132874, -0.001770,
|
0.071350f, 0.797424f, 0.132874f, -0.001770f,
|
||||||
0.067963, 0.796051, 0.137695, -0.001923,
|
0.067963f, 0.796051f, 0.137695f, -0.001923f,
|
||||||
0.064697, 0.794525, 0.142609, -0.002045,
|
0.064697f, 0.794525f, 0.142609f, -0.002045f,
|
||||||
0.061493, 0.792847, 0.147614, -0.002197,
|
0.061493f, 0.792847f, 0.147614f, -0.002197f,
|
||||||
0.058350, 0.790985, 0.152710, -0.002319,
|
0.058350f, 0.790985f, 0.152710f, -0.002319f,
|
||||||
0.055328, 0.788940, 0.157898, -0.002472,
|
0.055328f, 0.788940f, 0.157898f, -0.002472f,
|
||||||
0.052368, 0.786743, 0.163177, -0.002655,
|
0.052368f, 0.786743f, 0.163177f, -0.002655f,
|
||||||
0.049500, 0.784424, 0.168518, -0.002808,
|
0.049500f, 0.784424f, 0.168518f, -0.002808f,
|
||||||
0.046722, 0.781891, 0.173981, -0.002991,
|
0.046722f, 0.781891f, 0.173981f, -0.002991f,
|
||||||
0.044006, 0.779205, 0.179504, -0.003143,
|
0.044006f, 0.779205f, 0.179504f, -0.003143f,
|
||||||
0.041412, 0.776367, 0.185120, -0.003326,
|
0.041412f, 0.776367f, 0.185120f, -0.003326f,
|
||||||
0.038879, 0.773376, 0.190826, -0.003510,
|
0.038879f, 0.773376f, 0.190826f, -0.003510f,
|
||||||
0.036407, 0.770233, 0.196594, -0.003693,
|
0.036407f, 0.770233f, 0.196594f, -0.003693f,
|
||||||
0.034027, 0.766937, 0.202484, -0.003876,
|
0.034027f, 0.766937f, 0.202484f, -0.003876f,
|
||||||
0.031738, 0.763489, 0.208435, -0.004059,
|
0.031738f, 0.763489f, 0.208435f, -0.004059f,
|
||||||
0.029510, 0.759857, 0.214447, -0.004272,
|
0.029510f, 0.759857f, 0.214447f, -0.004272f,
|
||||||
0.027374, 0.756104, 0.220551, -0.004456,
|
0.027374f, 0.756104f, 0.220551f, -0.004456f,
|
||||||
0.025299, 0.752197, 0.226746, -0.004669,
|
0.025299f, 0.752197f, 0.226746f, -0.004669f,
|
||||||
0.023315, 0.748169, 0.233002, -0.004852,
|
0.023315f, 0.748169f, 0.233002f, -0.004852f,
|
||||||
0.021393, 0.743988, 0.239319, -0.005066,
|
0.021393f, 0.743988f, 0.239319f, -0.005066f,
|
||||||
0.019562, 0.739655, 0.245728, -0.005310,
|
0.019562f, 0.739655f, 0.245728f, -0.005310f,
|
||||||
0.017792, 0.735199, 0.252197, -0.005524,
|
0.017792f, 0.735199f, 0.252197f, -0.005524f,
|
||||||
0.016052, 0.730591, 0.258728, -0.005707,
|
0.016052f, 0.730591f, 0.258728f, -0.005707f,
|
||||||
0.014404, 0.725861, 0.265350, -0.005920,
|
0.014404f, 0.725861f, 0.265350f, -0.005920f,
|
||||||
0.012817, 0.721008, 0.272034, -0.006165,
|
0.012817f, 0.721008f, 0.272034f, -0.006165f,
|
||||||
0.011322, 0.716003, 0.278778, -0.006378,
|
0.011322f, 0.716003f, 0.278778f, -0.006378f,
|
||||||
0.009888, 0.710907, 0.285583, -0.006561,
|
0.009888f, 0.710907f, 0.285583f, -0.006561f,
|
||||||
0.008514, 0.705658, 0.292450, -0.006775,
|
0.008514f, 0.705658f, 0.292450f, -0.006775f,
|
||||||
0.007202, 0.700317, 0.299347, -0.007019,
|
0.007202f, 0.700317f, 0.299347f, -0.007019f,
|
||||||
0.005920, 0.694855, 0.306335, -0.007233,
|
0.005920f, 0.694855f, 0.306335f, -0.007233f,
|
||||||
0.004700, 0.689270, 0.313385, -0.007416,
|
0.004700f, 0.689270f, 0.313385f, -0.007416f,
|
||||||
0.003571, 0.683563, 0.320465, -0.007629,
|
0.003571f, 0.683563f, 0.320465f, -0.007629f,
|
||||||
0.002472, 0.677734, 0.327606, -0.007874,
|
0.002472f, 0.677734f, 0.327606f, -0.007874f,
|
||||||
0.001434, 0.671844, 0.334778, -0.008087,
|
0.001434f, 0.671844f, 0.334778f, -0.008087f,
|
||||||
0.000458, 0.665833, 0.341980, -0.008270,
|
0.000458f, 0.665833f, 0.341980f, -0.008270f,
|
||||||
-0.000488, 0.659729, 0.349243, -0.008453,
|
-0.000488f, 0.659729f, 0.349243f, -0.008453f,
|
||||||
-0.001343, 0.653534, 0.356567, -0.008636,
|
-0.001343f, 0.653534f, 0.356567f, -0.008636f,
|
||||||
-0.002167, 0.647217, 0.363892, -0.008850,
|
-0.002167f, 0.647217f, 0.363892f, -0.008850f,
|
||||||
-0.002960, 0.640839, 0.371277, -0.009033,
|
-0.002960f, 0.640839f, 0.371277f, -0.009033f,
|
||||||
-0.003693, 0.634338, 0.378693, -0.009216,
|
-0.003693f, 0.634338f, 0.378693f, -0.009216f,
|
||||||
-0.004364, 0.627777, 0.386139, -0.009338,
|
-0.004364f, 0.627777f, 0.386139f, -0.009338f,
|
||||||
-0.004974, 0.621155, 0.393616, -0.009491,
|
-0.004974f, 0.621155f, 0.393616f, -0.009491f,
|
||||||
-0.005585, 0.614441, 0.401093, -0.009644,
|
-0.005585f, 0.614441f, 0.401093f, -0.009644f,
|
||||||
-0.006134, 0.607635, 0.408600, -0.009796,
|
-0.006134f, 0.607635f, 0.408600f, -0.009796f,
|
||||||
-0.006653, 0.600769, 0.416107, -0.009918,
|
-0.006653f, 0.600769f, 0.416107f, -0.009918f,
|
||||||
-0.007141, 0.593842, 0.423645, -0.010010,
|
-0.007141f, 0.593842f, 0.423645f, -0.010010f,
|
||||||
-0.007568, 0.586853, 0.431213, -0.010132,
|
-0.007568f, 0.586853f, 0.431213f, -0.010132f,
|
||||||
-0.007965, 0.579773, 0.438751, -0.010223,
|
-0.007965f, 0.579773f, 0.438751f, -0.010223f,
|
||||||
-0.008331, 0.572662, 0.446320, -0.010284,
|
-0.008331f, 0.572662f, 0.446320f, -0.010284f,
|
||||||
-0.008667, 0.565521, 0.453888, -0.010345,
|
-0.008667f, 0.565521f, 0.453888f, -0.010345f,
|
||||||
-0.008972, 0.558319, 0.461456, -0.010406,
|
-0.008972f, 0.558319f, 0.461456f, -0.010406f,
|
||||||
-0.009216, 0.551056, 0.469025, -0.010406,
|
-0.009216f, 0.551056f, 0.469025f, -0.010406f,
|
||||||
-0.009460, 0.543732, 0.476593, -0.010406,
|
-0.009460f, 0.543732f, 0.476593f, -0.010406f,
|
||||||
-0.009674, 0.536407, 0.484131, -0.010376,
|
-0.009674f, 0.536407f, 0.484131f, -0.010376f,
|
||||||
-0.009857, 0.529022, 0.491669, -0.010376,
|
-0.009857f, 0.529022f, 0.491669f, -0.010376f,
|
||||||
-0.010010, 0.521606, 0.499176, -0.010315,
|
-0.010010f, 0.521606f, 0.499176f, -0.010315f,
|
||||||
-0.010132, 0.514160, 0.506683, -0.010254,
|
-0.010132f, 0.514160f, 0.506683f, -0.010254f,
|
||||||
-0.010254, 0.506683, 0.514160, -0.010132,
|
-0.010254f, 0.506683f, 0.514160f, -0.010132f,
|
||||||
-0.010315, 0.499176, 0.521606, -0.010010,
|
-0.010315f, 0.499176f, 0.521606f, -0.010010f,
|
||||||
-0.010376, 0.491669, 0.529022, -0.009857,
|
-0.010376f, 0.491669f, 0.529022f, -0.009857f,
|
||||||
-0.010376, 0.484131, 0.536407, -0.009674,
|
-0.010376f, 0.484131f, 0.536407f, -0.009674f,
|
||||||
-0.010406, 0.476593, 0.543732, -0.009460,
|
-0.010406f, 0.476593f, 0.543732f, -0.009460f,
|
||||||
-0.010406, 0.469025, 0.551056, -0.009216,
|
-0.010406f, 0.469025f, 0.551056f, -0.009216f,
|
||||||
-0.010406, 0.461456, 0.558319, -0.008972,
|
-0.010406f, 0.461456f, 0.558319f, -0.008972f,
|
||||||
-0.010345, 0.453888, 0.565521, -0.008667,
|
-0.010345f, 0.453888f, 0.565521f, -0.008667f,
|
||||||
-0.010284, 0.446320, 0.572662, -0.008331,
|
-0.010284f, 0.446320f, 0.572662f, -0.008331f,
|
||||||
-0.010223, 0.438751, 0.579773, -0.007965,
|
-0.010223f, 0.438751f, 0.579773f, -0.007965f,
|
||||||
-0.010132, 0.431213, 0.586853, -0.007568,
|
-0.010132f, 0.431213f, 0.586853f, -0.007568f,
|
||||||
-0.010010, 0.423645, 0.593842, -0.007141,
|
-0.010010f, 0.423645f, 0.593842f, -0.007141f,
|
||||||
-0.009918, 0.416107, 0.600769, -0.006653,
|
-0.009918f, 0.416107f, 0.600769f, -0.006653f,
|
||||||
-0.009796, 0.408600, 0.607635, -0.006134,
|
-0.009796f, 0.408600f, 0.607635f, -0.006134f,
|
||||||
-0.009644, 0.401093, 0.614441, -0.005585,
|
-0.009644f, 0.401093f, 0.614441f, -0.005585f,
|
||||||
-0.009491, 0.393616, 0.621155, -0.004974,
|
-0.009491f, 0.393616f, 0.621155f, -0.004974f,
|
||||||
-0.009338, 0.386139, 0.627777, -0.004364,
|
-0.009338f, 0.386139f, 0.627777f, -0.004364f,
|
||||||
-0.009216, 0.378693, 0.634338, -0.003693,
|
-0.009216f, 0.378693f, 0.634338f, -0.003693f,
|
||||||
-0.009033, 0.371277, 0.640839, -0.002960,
|
-0.009033f, 0.371277f, 0.640839f, -0.002960f,
|
||||||
-0.008850, 0.363892, 0.647217, -0.002167,
|
-0.008850f, 0.363892f, 0.647217f, -0.002167f,
|
||||||
-0.008636, 0.356567, 0.653534, -0.001343,
|
-0.008636f, 0.356567f, 0.653534f, -0.001343f,
|
||||||
-0.008453, 0.349243, 0.659729, -0.000488,
|
-0.008453f, 0.349243f, 0.659729f, -0.000488f,
|
||||||
-0.008270, 0.341980, 0.665833, 0.000458,
|
-0.008270f, 0.341980f, 0.665833f, 0.000458f,
|
||||||
-0.008087, 0.334778, 0.671844, 0.001434,
|
-0.008087f, 0.334778f, 0.671844f, 0.001434f,
|
||||||
-0.007874, 0.327606, 0.677734, 0.002472,
|
-0.007874f, 0.327606f, 0.677734f, 0.002472f,
|
||||||
-0.007629, 0.320465, 0.683563, 0.003571,
|
-0.007629f, 0.320465f, 0.683563f, 0.003571f,
|
||||||
-0.007416, 0.313385, 0.689270, 0.004700,
|
-0.007416f, 0.313385f, 0.689270f, 0.004700f,
|
||||||
-0.007233, 0.306335, 0.694855, 0.005920,
|
-0.007233f, 0.306335f, 0.694855f, 0.005920f,
|
||||||
-0.007019, 0.299347, 0.700317, 0.007202,
|
-0.007019f, 0.299347f, 0.700317f, 0.007202f,
|
||||||
-0.006775, 0.292450, 0.705658, 0.008514,
|
-0.006775f, 0.292450f, 0.705658f, 0.008514f,
|
||||||
-0.006561, 0.285583, 0.710907, 0.009888,
|
-0.006561f, 0.285583f, 0.710907f, 0.009888f,
|
||||||
-0.006378, 0.278778, 0.716003, 0.011322,
|
-0.006378f, 0.278778f, 0.716003f, 0.011322f,
|
||||||
-0.006165, 0.272034, 0.721008, 0.012817,
|
-0.006165f, 0.272034f, 0.721008f, 0.012817f,
|
||||||
-0.005920, 0.265350, 0.725861, 0.014404,
|
-0.005920f, 0.265350f, 0.725861f, 0.014404f,
|
||||||
-0.005707, 0.258728, 0.730591, 0.016052,
|
-0.005707f, 0.258728f, 0.730591f, 0.016052f,
|
||||||
-0.005524, 0.252197, 0.735199, 0.017792,
|
-0.005524f, 0.252197f, 0.735199f, 0.017792f,
|
||||||
-0.005310, 0.245728, 0.739655, 0.019562,
|
-0.005310f, 0.245728f, 0.739655f, 0.019562f,
|
||||||
-0.005066, 0.239319, 0.743988, 0.021393,
|
-0.005066f, 0.239319f, 0.743988f, 0.021393f,
|
||||||
-0.004852, 0.233002, 0.748169, 0.023315,
|
-0.004852f, 0.233002f, 0.748169f, 0.023315f,
|
||||||
-0.004669, 0.226746, 0.752197, 0.025299,
|
-0.004669f, 0.226746f, 0.752197f, 0.025299f,
|
||||||
-0.004456, 0.220551, 0.756104, 0.027374,
|
-0.004456f, 0.220551f, 0.756104f, 0.027374f,
|
||||||
-0.004272, 0.214447, 0.759857, 0.029510,
|
-0.004272f, 0.214447f, 0.759857f, 0.029510f,
|
||||||
-0.004059, 0.208435, 0.763489, 0.031738,
|
-0.004059f, 0.208435f, 0.763489f, 0.031738f,
|
||||||
-0.003876, 0.202484, 0.766937, 0.034027,
|
-0.003876f, 0.202484f, 0.766937f, 0.034027f,
|
||||||
-0.003693, 0.196594, 0.770233, 0.036407,
|
-0.003693f, 0.196594f, 0.770233f, 0.036407f,
|
||||||
-0.003510, 0.190826, 0.773376, 0.038879,
|
-0.003510f, 0.190826f, 0.773376f, 0.038879f,
|
||||||
-0.003326, 0.185120, 0.776367, 0.041412,
|
-0.003326f, 0.185120f, 0.776367f, 0.041412f,
|
||||||
-0.003143, 0.179504, 0.779205, 0.044006,
|
-0.003143f, 0.179504f, 0.779205f, 0.044006f,
|
||||||
-0.002991, 0.173981, 0.781891, 0.046722,
|
-0.002991f, 0.173981f, 0.781891f, 0.046722f,
|
||||||
-0.002808, 0.168518, 0.784424, 0.049500,
|
-0.002808f, 0.168518f, 0.784424f, 0.049500f,
|
||||||
-0.002655, 0.163177, 0.786743, 0.052368,
|
-0.002655f, 0.163177f, 0.786743f, 0.052368f,
|
||||||
-0.002472, 0.157898, 0.788940, 0.055328,
|
-0.002472f, 0.157898f, 0.788940f, 0.055328f,
|
||||||
-0.002319, 0.152710, 0.790985, 0.058350,
|
-0.002319f, 0.152710f, 0.790985f, 0.058350f,
|
||||||
-0.002197, 0.147614, 0.792847, 0.061493,
|
-0.002197f, 0.147614f, 0.792847f, 0.061493f,
|
||||||
-0.002045, 0.142609, 0.794525, 0.064697,
|
-0.002045f, 0.142609f, 0.794525f, 0.064697f,
|
||||||
-0.001923, 0.137695, 0.796051, 0.067963,
|
-0.001923f, 0.137695f, 0.796051f, 0.067963f,
|
||||||
-0.001770, 0.132874, 0.797424, 0.071350,
|
-0.001770f, 0.132874f, 0.797424f, 0.071350f,
|
||||||
-0.001648, 0.128143, 0.798615, 0.074799,
|
-0.001648f, 0.128143f, 0.798615f, 0.074799f,
|
||||||
-0.001526, 0.123474, 0.799622, 0.078369,
|
-0.001526f, 0.123474f, 0.799622f, 0.078369f,
|
||||||
-0.001404, 0.118927, 0.800476, 0.082031,
|
-0.001404f, 0.118927f, 0.800476f, 0.082031f,
|
||||||
-0.001282, 0.114471, 0.801178, 0.085785,
|
-0.001282f, 0.114471f, 0.801178f, 0.085785f,
|
||||||
-0.001160, 0.110107, 0.801697, 0.089600,
|
-0.001160f, 0.110107f, 0.801697f, 0.089600f,
|
||||||
-0.001038, 0.105804, 0.802032, 0.093506,
|
-0.001038f, 0.105804f, 0.802032f, 0.093506f,
|
||||||
-0.000977, 0.101593, 0.802216, 0.097504,
|
-0.000977f, 0.101593f, 0.802216f, 0.097504f,
|
||||||
};
|
};
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "amuse/EffectDelay.hpp"
|
#include "amuse/EffectDelay.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/IBackendVoice.hpp"
|
#include "amuse/IBackendVoice.hpp"
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
@@ -24,6 +24,19 @@ EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uin
|
|||||||
_setup(sampleRate);
|
_setup(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
EffectDelayImp<T>::EffectDelayImp(const EffectDelayInfo& info, double sampleRate)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
x3c_delay[i] = clamp(10u, info.delay[i], 5000u);
|
||||||
|
x48_feedback[i] = clamp(0u, info.feedback[i], 100u);
|
||||||
|
x54_output[i] = clamp(0u, info.output[i], 100u);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setup(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void EffectDelayImp<T>::_setup(double sampleRate)
|
void EffectDelayImp<T>::_setup(double sampleRate)
|
||||||
{
|
{
|
||||||
@@ -58,10 +71,10 @@ void EffectDelayImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMa
|
|||||||
|
|
||||||
for (size_t f = 0; f < frameCount;)
|
for (size_t f = 0; f < frameCount;)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < chanMap.m_channelCount; ++c)
|
for (unsigned c = 0; c < chanMap.m_channelCount; ++c)
|
||||||
{
|
{
|
||||||
T* chanAud = audio + c;
|
T* chanAud = audio + c;
|
||||||
for (int i = 0; i < m_blockSamples && f < frameCount; ++i, ++f)
|
for (unsigned i = 0; i < m_blockSamples && f < frameCount; ++i, ++f)
|
||||||
{
|
{
|
||||||
T& liveSamp = chanAud[chanMap.m_channelCount * i];
|
T& liveSamp = chanAud[chanMap.m_channelCount * i];
|
||||||
T& samp = x30_chanLines[c][xc_currentPos[c] * m_blockSamples + i];
|
T& samp = x30_chanLines[c][xc_currentPos[c] * m_blockSamples + i];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "amuse/EffectReverb.hpp"
|
#include "amuse/EffectReverb.hpp"
|
||||||
#include "amuse/IBackendVoice.hpp"
|
#include "amuse/IBackendVoice.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,7 @@ template <typename T>
|
|||||||
void EffectReverbStdImp<T>::_update()
|
void EffectReverbStdImp<T>::_update()
|
||||||
{
|
{
|
||||||
float timeSamples = x148_x1d0_time * m_sampleRate;
|
float timeSamples = x148_x1d0_time * m_sampleRate;
|
||||||
double rateRatio = m_sampleRate / 32000.0;
|
double rateRatio = m_sampleRate / NativeSampleRate;
|
||||||
for (int c = 0; c < 8; ++c)
|
for (int c = 0; c < 8; ++c)
|
||||||
{
|
{
|
||||||
for (int t = 0; t < 2; ++t)
|
for (int t = 0; t < 2; ++t)
|
||||||
@@ -265,7 +265,7 @@ template <typename T>
|
|||||||
void EffectReverbHiImp<T>::_update()
|
void EffectReverbHiImp<T>::_update()
|
||||||
{
|
{
|
||||||
float timeSamples = x148_x1d0_time * m_sampleRate;
|
float timeSamples = x148_x1d0_time * m_sampleRate;
|
||||||
double rateRatio = m_sampleRate / 32000.0;
|
double rateRatio = m_sampleRate / NativeSampleRate;
|
||||||
for (int c = 0; c < 8; ++c)
|
for (int c = 0; c < 8; ++c)
|
||||||
{
|
{
|
||||||
for (int t = 0; t < 3; ++t)
|
for (int t = 0; t < 3; ++t)
|
||||||
|
|||||||
136
lib/Emitter.cpp
@@ -1,14 +1,24 @@
|
|||||||
#include "amuse/Emitter.hpp"
|
#include "amuse/Emitter.hpp"
|
||||||
|
#include "amuse/Listener.hpp"
|
||||||
#include "amuse/Voice.hpp"
|
#include "amuse/Voice.hpp"
|
||||||
#include "amuse/Engine.hpp"
|
#include "amuse/Engine.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static void Delta(Vector3f& out, const Vector3f& a, const Vector3f& b)
|
||||||
|
{
|
||||||
|
out[0] = a[0] - b[0];
|
||||||
|
out[1] = a[1] - b[1];
|
||||||
|
out[2] = a[2] - b[2];
|
||||||
|
}
|
||||||
|
|
||||||
Emitter::~Emitter() {}
|
Emitter::~Emitter() {}
|
||||||
|
|
||||||
Emitter::Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox)
|
Emitter::Emitter(Engine& engine, const AudioGroup& group, const std::shared_ptr<Voice>& vox,
|
||||||
: Entity(engine, group, vox->getObjectId()), m_vox(std::move(vox))
|
float maxDist, float minVol, float falloff, bool doppler)
|
||||||
|
: Entity(engine, group, vox->getGroupId(), vox->getObjectId()), m_vox(vox), m_maxDist(maxDist),
|
||||||
|
m_minVol(clamp(0.f, minVol, 1.f)), m_falloff(clamp(-1.f, falloff, 1.f)), m_doppler(doppler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,15 +28,115 @@ void Emitter::_destroy()
|
|||||||
m_vox->kill();
|
m_vox->kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emitter::setPos(const Vector3f& pos) {}
|
float Emitter::_attenuationCurve(float dist) const
|
||||||
|
{
|
||||||
void Emitter::setDir(const Vector3f& dir) {}
|
if (dist > m_maxDist)
|
||||||
|
return 0.f;
|
||||||
void Emitter::setMaxDist(float maxDist) {}
|
float t = dist / m_maxDist;
|
||||||
|
if (m_falloff < 0.f)
|
||||||
void Emitter::setMaxVol(float maxVol) {}
|
{
|
||||||
|
float tmp = t * 10.f + 1.f;
|
||||||
void Emitter::setMinVol(float minVol) {}
|
tmp = 1.f / (tmp * tmp);
|
||||||
|
return (1.f + m_falloff) * (-t + 1.f) + -m_falloff * tmp;
|
||||||
void Emitter::setFalloff(float falloff) {}
|
}
|
||||||
|
else if (m_falloff > 0.f)
|
||||||
|
{
|
||||||
|
float tmp = (t - 1.f) * 10.f - 1.f;
|
||||||
|
tmp = -1.f / (tmp * tmp) + 1.f;
|
||||||
|
return (1.f - m_falloff) * (-t + 1.f) + m_falloff * tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -t + 1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emitter::_update()
|
||||||
|
{
|
||||||
|
if (!m_dirty)
|
||||||
|
{
|
||||||
|
/* Ensure that all listeners are also not dirty */
|
||||||
|
bool dirty = false;
|
||||||
|
for (auto& listener : m_engine.m_activeListeners)
|
||||||
|
{
|
||||||
|
if (listener->m_dirty)
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dirty)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float coefs[8] = {};
|
||||||
|
double avgDopplerRatio = 0.0;
|
||||||
|
|
||||||
|
for (auto& listener : m_engine.m_activeListeners)
|
||||||
|
{
|
||||||
|
Vector3f listenerToEmitter;
|
||||||
|
Delta(listenerToEmitter, m_pos, listener->m_pos);
|
||||||
|
float dist = Length(listenerToEmitter);
|
||||||
|
float panDist = Dot(listenerToEmitter, listener->m_right);
|
||||||
|
float frontPan = clamp(-1.f, panDist / listener->m_frontDiff, 1.f);
|
||||||
|
float backPan = clamp(-1.f, panDist / listener->m_backDiff, 1.f);
|
||||||
|
float spanDist = -Dot(listenerToEmitter, listener->m_heading);
|
||||||
|
float span = clamp(-1.f, spanDist > 0.f ? spanDist / listener->m_backDiff :
|
||||||
|
spanDist / listener->m_frontDiff, 1.f);
|
||||||
|
|
||||||
|
/* Calculate attenuation */
|
||||||
|
float att = _attenuationCurve(dist);
|
||||||
|
if (att > FLT_EPSILON)
|
||||||
|
{
|
||||||
|
att = (1.f - att) * m_minVol + att * m_maxVol;
|
||||||
|
|
||||||
|
/* Apply pan law */
|
||||||
|
float thisCoefs[8] = {};
|
||||||
|
m_vox->_panLaw(thisCoefs, frontPan, backPan, span);
|
||||||
|
|
||||||
|
/* Take maximum coefficient across listeners */
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
coefs[i] = std::max(coefs[i], thisCoefs[i] * att * listener->m_volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate doppler */
|
||||||
|
if (m_doppler)
|
||||||
|
{
|
||||||
|
/* Positive values indicate emitter and listener closing in */
|
||||||
|
Vector3f dirDelta;
|
||||||
|
Delta(dirDelta, m_dir, listener->m_dir);
|
||||||
|
Vector3f posDelta;
|
||||||
|
Delta(posDelta, listener->m_pos, m_pos);
|
||||||
|
Normalize(posDelta);
|
||||||
|
float deltaSpeed = Dot(dirDelta, posDelta);
|
||||||
|
if (listener->m_soundSpeed != 0.f)
|
||||||
|
avgDopplerRatio += 1.0 + deltaSpeed / listener->m_soundSpeed;
|
||||||
|
else
|
||||||
|
avgDopplerRatio += 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_engine.m_activeListeners.size() != 0)
|
||||||
|
{
|
||||||
|
m_vox->setChannelCoefs(coefs);
|
||||||
|
if (m_doppler)
|
||||||
|
{
|
||||||
|
m_vox->m_dopplerRatio = avgDopplerRatio / float(m_engine.m_activeListeners.size());
|
||||||
|
m_vox->m_pitchDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emitter::setVectors(const float* pos, const float* dir)
|
||||||
|
{
|
||||||
|
for (int i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
m_pos[i] = pos[i];
|
||||||
|
m_dir[i] = dir[i];
|
||||||
|
}
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ static const float FullLevels[8] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
|
|||||||
|
|
||||||
Engine::~Engine()
|
Engine::~Engine()
|
||||||
{
|
{
|
||||||
|
m_backend.setCallbackInterface(nullptr);
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
||||||
if (!seq->m_destroyed)
|
if (!seq->m_destroyed)
|
||||||
seq->_destroy();
|
seq->_destroy();
|
||||||
@@ -30,7 +31,7 @@ Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode)
|
|||||||
m_defaultStudio->getAuxA().makeReverbStd(0.5f, 0.8f, 3.0f, 0.5f, 0.1f);
|
m_defaultStudio->getAuxA().makeReverbStd(0.5f, 0.8f, 3.0f, 0.5f, 0.1f);
|
||||||
m_defaultStudio->getAuxB().makeChorus(15, 0, 500);
|
m_defaultStudio->getAuxB().makeChorus(15, 0, 500);
|
||||||
m_defaultStudioReady = true;
|
m_defaultStudioReady = true;
|
||||||
backend.register5MsCallback(std::bind(&Engine::_5MsCallback, this, std::placeholders::_1));
|
m_backend.setCallbackInterface(this);
|
||||||
m_midiReader = backend.allocateMIDIReader(*this);
|
m_midiReader = backend.allocateMIDIReader(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +103,7 @@ std::shared_ptr<Studio> Engine::_allocateStudio(bool mainOut)
|
|||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
|
std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
assert(this == &(*it)->getEngine());
|
assert(this == &(*it)->getEngine());
|
||||||
#endif
|
|
||||||
if ((*it)->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
return m_activeVoices.begin();
|
return m_activeVoices.begin();
|
||||||
(*it)->_destroy();
|
(*it)->_destroy();
|
||||||
@@ -114,9 +113,7 @@ std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std:
|
|||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
std::list<std::shared_ptr<Sequencer>>::iterator
|
||||||
Engine::_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it)
|
Engine::_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
assert(this == &(*it)->getEngine());
|
assert(this == &(*it)->getEngine());
|
||||||
#endif
|
|
||||||
if ((*it)->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
return m_activeSequencers.begin();
|
return m_activeSequencers.begin();
|
||||||
(*it)->_destroy();
|
(*it)->_destroy();
|
||||||
@@ -171,18 +168,21 @@ void Engine::_bringOutYourDead()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::_5MsCallback(double dt)
|
void Engine::_on5MsInterval(IBackendVoiceAllocator& engine, double dt)
|
||||||
{
|
{
|
||||||
|
m_channelSet = engine.getAvailableSet();
|
||||||
if (m_midiReader)
|
if (m_midiReader)
|
||||||
m_midiReader->pumpReader(dt);
|
m_midiReader->pumpReader(dt);
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
||||||
seq->advance(dt);
|
seq->advance(dt);
|
||||||
|
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
|
||||||
|
emitter->_update();
|
||||||
|
for (std::shared_ptr<Listener>& listener : m_activeListeners)
|
||||||
|
listener->m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update all active audio entities and fill OS audio buffers as needed */
|
void Engine::_onPumpCycleComplete(IBackendVoiceAllocator& engine)
|
||||||
void Engine::pumpEngine()
|
|
||||||
{
|
{
|
||||||
m_backend.pumpAndMixVoices();
|
|
||||||
_bringOutYourDead();
|
_bringOutYourDead();
|
||||||
|
|
||||||
/* Determine lowest available free vid */
|
/* Determine lowest available free vid */
|
||||||
@@ -305,7 +305,7 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret =
|
std::list<std::shared_ptr<Voice>>::iterator ret =
|
||||||
_allocateVoice(*grp, std::get<1>(search->second), 32000.0, true, false, smx);
|
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, false, smx);
|
||||||
|
|
||||||
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
||||||
if (!(*ret)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
if (!(*ret)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
@@ -320,8 +320,9 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist, float falloff,
|
std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
int sfxId, float minVol, float maxVol, std::weak_ptr<Studio> smx)
|
int sfxId, float minVol, float maxVol, bool doppler,
|
||||||
|
std::weak_ptr<Studio> smx)
|
||||||
{
|
{
|
||||||
auto search = m_sfxLookup.find(sfxId);
|
auto search = m_sfxLookup.find(sfxId);
|
||||||
if (search == m_sfxLookup.end())
|
if (search == m_sfxLookup.end())
|
||||||
@@ -333,29 +334,50 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator vox =
|
std::list<std::shared_ptr<Voice>>::iterator vox =
|
||||||
_allocateVoice(*grp, std::get<1>(search->second), 32000.0, true, true, smx);
|
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, true, smx);
|
||||||
auto emitIt = m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(*vox)));
|
|
||||||
Emitter& ret = *(*emitIt);
|
|
||||||
|
|
||||||
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
||||||
if (!ret.getVoice()->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
if (!(*vox)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
{
|
{
|
||||||
ret._destroy();
|
_destroyVoice(vox);
|
||||||
m_activeEmitters.erase(emitIt);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
(*vox)->setPan(entry->panning);
|
auto emitIt = m_activeEmitters.emplace(m_activeEmitters.end(),
|
||||||
ret.setPos(pos);
|
new Emitter(*this, *grp, *vox, maxDist, minVol, falloff, doppler));
|
||||||
ret.setDir(dir);
|
Emitter& ret = *(*emitIt);
|
||||||
ret.setMaxDist(maxDist);
|
|
||||||
ret.setFalloff(falloff);
|
ret.getVoice()->setPan(entry->panning);
|
||||||
ret.setMinVol(minVol);
|
ret.setVectors(pos, dir);
|
||||||
ret.setMaxVol(maxVol);
|
ret.setMaxVol(maxVol);
|
||||||
|
|
||||||
return *emitIt;
|
return *emitIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Build listener and add to engine's listener list */
|
||||||
|
std::shared_ptr<Listener> Engine::addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
||||||
|
float frontDiff, float backDiff, float soundSpeed, float volume)
|
||||||
|
{
|
||||||
|
auto listenerIt = m_activeListeners.emplace(m_activeListeners.end(),
|
||||||
|
new Listener(volume, frontDiff, backDiff, soundSpeed));
|
||||||
|
Listener& ret = *(*listenerIt);
|
||||||
|
ret.setVectors(pos, dir, heading, up);
|
||||||
|
return *listenerIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove listener from engine's listener list */
|
||||||
|
void Engine::removeListener(Listener* listener)
|
||||||
|
{
|
||||||
|
for (auto it = m_activeListeners.begin() ; it != m_activeListeners.end() ; ++it)
|
||||||
|
{
|
||||||
|
if (it->get() == listener)
|
||||||
|
{
|
||||||
|
m_activeListeners.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData,
|
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData,
|
||||||
std::weak_ptr<Studio> smx)
|
std::weak_ptr<Studio> smx)
|
||||||
@@ -384,12 +406,10 @@ std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsign
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" const float VolumeLUT[];
|
|
||||||
|
|
||||||
/** Set total volume of engine */
|
/** Set total volume of engine */
|
||||||
void Engine::setVolume(float vol)
|
void Engine::setVolume(float vol)
|
||||||
{
|
{
|
||||||
m_backend.setVolume(VolumeLUT[int(clamp(0.f, vol, 1.f) * 65536)] * 1.46245869f);
|
m_masterVolume = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find voice from VoiceId */
|
/** Find voice from VoiceId */
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include "amuse/Listener.hpp"
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
static void Cross(Vector3f& out, const Vector3f& a, const Vector3f& b)
|
||||||
|
{
|
||||||
|
out[0] = a[1] * b[2] - a[2] * b[1];
|
||||||
|
out[1] = a[2] * b[0] - a[0] * b[2];
|
||||||
|
out[2] = a[0] * b[1] - a[1] * b[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Listener::setVectors(const float* pos, const float* dir, const float* heading, const float* up)
|
||||||
|
{
|
||||||
|
for (int i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
m_pos[i] = pos[i];
|
||||||
|
m_dir[i] = dir[i];
|
||||||
|
m_heading[i] = heading[i];
|
||||||
|
m_up[i] = up[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Normalize(m_heading);
|
||||||
|
Normalize(m_up);
|
||||||
|
Cross(m_right, m_heading, m_up);
|
||||||
|
Normalize(m_right);
|
||||||
|
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ void Sequencer::_bringOutYourDead()
|
|||||||
{
|
{
|
||||||
for (auto& chan : m_chanStates)
|
for (auto& chan : m_chanStates)
|
||||||
if (chan)
|
if (chan)
|
||||||
chan->_bringOutYourDead();
|
chan._bringOutYourDead();
|
||||||
|
|
||||||
if (!m_arrData && m_dieOnEnd && getVoiceCount() == 0)
|
if (!m_arrData && m_dieOnEnd && getVoiceCount() == 0)
|
||||||
m_state = SequencerState::Dead;
|
m_state = SequencerState::Dead;
|
||||||
@@ -81,18 +81,19 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const
|
|||||||
|
|
||||||
Sequencer::ChannelState::~ChannelState() {}
|
Sequencer::ChannelState::~ChannelState() {}
|
||||||
|
|
||||||
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_parent(parent), m_chanId(chanId)
|
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
|
: m_parent(&parent), m_chanId(chanId)
|
||||||
{
|
{
|
||||||
if (m_parent.m_songGroup)
|
if (m_parent->m_songGroup)
|
||||||
{
|
{
|
||||||
if (m_parent.m_midiSetup)
|
if (m_parent->m_midiSetup)
|
||||||
{
|
{
|
||||||
m_setup = &m_parent.m_midiSetup[chanId];
|
m_setup = &m_parent->m_midiSetup[chanId];
|
||||||
|
|
||||||
if (chanId == 9)
|
if (chanId == 9)
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_drumPages.find(m_setup->programNo);
|
auto it = m_parent->m_songGroup->m_drumPages.find(m_setup->programNo);
|
||||||
if (it != m_parent.m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
m_curProgram = m_setup->programNo;
|
m_curProgram = m_setup->programNo;
|
||||||
@@ -100,8 +101,8 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_par
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_normPages.find(m_setup->programNo);
|
auto it = m_parent->m_songGroup->m_normPages.find(m_setup->programNo);
|
||||||
if (it != m_parent.m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
m_curProgram = m_setup->programNo;
|
m_curProgram = m_setup->programNo;
|
||||||
@@ -117,14 +118,14 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_par
|
|||||||
{
|
{
|
||||||
if (chanId == 9)
|
if (chanId == 9)
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_drumPages.find(0);
|
auto it = m_parent->m_songGroup->m_drumPages.find(0);
|
||||||
if (it != m_parent.m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_normPages.find(0);
|
auto it = m_parent->m_songGroup->m_normPages.find(0);
|
||||||
if (it != m_parent.m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_par
|
|||||||
m_ctrlVals[0x5d] = 0;
|
m_ctrlVals[0x5d] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_parent.m_sfxGroup)
|
else if (m_parent->m_sfxGroup)
|
||||||
{
|
{
|
||||||
m_curVol = 1.f;
|
m_curVol = 1.f;
|
||||||
m_curPan = 0.f;
|
m_curPan = 0.f;
|
||||||
@@ -149,12 +150,45 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) : m_par
|
|||||||
void Sequencer::advance(double dt)
|
void Sequencer::advance(double dt)
|
||||||
{
|
{
|
||||||
if (m_state == SequencerState::Playing)
|
if (m_state == SequencerState::Playing)
|
||||||
|
{
|
||||||
|
if (m_stopFadeTime)
|
||||||
|
{
|
||||||
|
float step = dt / m_stopFadeTime * m_stopFadeBeginVol;
|
||||||
|
float vol = std::max(0.f, m_curVol - step);
|
||||||
|
if (vol == 0.f)
|
||||||
|
{
|
||||||
|
m_arrData = nullptr;
|
||||||
|
m_state = SequencerState::Interactive;
|
||||||
|
allOff(true);
|
||||||
|
m_stopFadeTime = 0.f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setVolume(vol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_volFadeTime)
|
||||||
|
{
|
||||||
|
float step = dt / m_volFadeTime * std::fabs(m_volFadeTarget - m_volFadeStart);
|
||||||
|
float vol;
|
||||||
|
if (m_curVol < m_volFadeTarget)
|
||||||
|
vol = std::min(m_volFadeTarget, m_curVol + step);
|
||||||
|
else
|
||||||
|
vol = std::max(m_volFadeTarget, m_curVol - step);
|
||||||
|
if (vol == m_volFadeTarget)
|
||||||
|
m_volFadeTime = 0.f;
|
||||||
|
else
|
||||||
|
setVolume(vol);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_songState.advance(*this, dt))
|
if (m_songState.advance(*this, dt))
|
||||||
{
|
{
|
||||||
m_arrData = nullptr;
|
m_arrData = nullptr;
|
||||||
m_state = SequencerState::Interactive;
|
m_state = SequencerState::Interactive;
|
||||||
allOff();
|
allOff();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Sequencer::ChannelState::getVoiceCount() const
|
size_t Sequencer::ChannelState::getVoiceCount() const
|
||||||
@@ -172,13 +206,13 @@ size_t Sequencer::getVoiceCount() const
|
|||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (const auto& chan : m_chanStates)
|
for (const auto& chan : m_chanStates)
|
||||||
if (chan)
|
if (chan)
|
||||||
ret += chan->getVoiceCount();
|
ret += chan.getVoiceCount();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity)
|
std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity)
|
||||||
{
|
{
|
||||||
if (m_parent.m_songGroup && !m_page)
|
if (m_parent->m_songGroup && !m_page)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
||||||
@@ -205,32 +239,32 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
|||||||
m_chanVoxs.erase(keySearch);
|
m_chanVoxs.erase(keySearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret = m_parent.m_engine._allocateVoice(
|
std::list<std::shared_ptr<Voice>>::iterator ret = m_parent->m_engine._allocateVoice(
|
||||||
m_parent.m_audioGroup, m_parent.m_groupId, 32000.0, true, false, m_parent.m_studio);
|
m_parent->m_audioGroup, m_parent->m_groupId, NativeSampleRate, true, false, m_parent->m_studio);
|
||||||
if (*ret)
|
if (*ret)
|
||||||
{
|
{
|
||||||
m_chanVoxs[note] = *ret;
|
m_chanVoxs[note] = *ret;
|
||||||
(*ret)->installCtrlValues(m_ctrlVals);
|
(*ret)->installCtrlValues(m_ctrlVals);
|
||||||
|
|
||||||
ObjectId oid;
|
ObjectId oid;
|
||||||
if (m_parent.m_songGroup)
|
if (m_parent->m_songGroup)
|
||||||
oid = (m_parent.m_audioGroup.getDataFormat() == DataFormat::PC) ? m_page->objId : SBig(m_page->objId);
|
oid = (m_parent->m_audioGroup.getDataFormat() == DataFormat::PC) ? m_page->objId : SBig(m_page->objId);
|
||||||
else if (m_parent.m_sfxMappings.size())
|
else if (m_parent->m_sfxMappings.size())
|
||||||
{
|
{
|
||||||
size_t lookupIdx = note % m_parent.m_sfxMappings.size();
|
size_t lookupIdx = note % m_parent->m_sfxMappings.size();
|
||||||
const SFXGroupIndex::SFXEntry* sfxEntry = m_parent.m_sfxMappings[lookupIdx];
|
const SFXGroupIndex::SFXEntry* sfxEntry = m_parent->m_sfxMappings[lookupIdx];
|
||||||
oid = (m_parent.m_audioGroup.getDataFormat() == DataFormat::PC) ? sfxEntry->objId : SBig(sfxEntry->objId);
|
oid = (m_parent->m_audioGroup.getDataFormat() == DataFormat::PC) ? sfxEntry->objId : SBig(sfxEntry->objId);
|
||||||
note = sfxEntry->defKey;
|
note = sfxEntry->defKey;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!(*ret)->loadSoundObject(oid, 0, m_parent.m_ticksPerSec, note, velocity, m_ctrlVals[1]))
|
if (!(*ret)->loadSoundObject(oid, 0, m_parent->m_ticksPerSec, note, velocity, m_ctrlVals[1]))
|
||||||
{
|
{
|
||||||
m_parent.m_engine._destroyVoice(ret);
|
m_parent->m_engine._destroyVoice(ret);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
(*ret)->setVolume(m_parent.m_curVol * m_curVol);
|
(*ret)->setVolume(m_parent->m_curVol * m_curVol);
|
||||||
(*ret)->setReverbVol(m_ctrlVals[0x5b] / 127.f);
|
(*ret)->setReverbVol(m_ctrlVals[0x5b] / 127.f);
|
||||||
(*ret)->setAuxBVol(m_ctrlVals[0x5d] / 127.f);
|
(*ret)->setAuxBVol(m_ctrlVals[0x5d] / 127.f);
|
||||||
(*ret)->setPan(m_curPan);
|
(*ret)->setPan(m_curPan);
|
||||||
@@ -251,9 +285,9 @@ std::shared_ptr<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velo
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!m_chanStates[chan])
|
if (!m_chanStates[chan])
|
||||||
m_chanStates[chan].emplace(*this, chan);
|
m_chanStates[chan] = ChannelState(*this, chan);
|
||||||
|
|
||||||
return m_chanStates[chan]->keyOn(note, velocity);
|
return m_chanStates[chan].keyOn(note, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
||||||
@@ -274,7 +308,7 @@ void Sequencer::keyOff(uint8_t chan, uint8_t note, uint8_t velocity)
|
|||||||
if (chan > 15 || !m_chanStates[chan])
|
if (chan > 15 || !m_chanStates[chan])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_chanStates[chan]->keyOff(note, velocity);
|
m_chanStates[chan].keyOff(note, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::ChannelState::setCtrlValue(uint8_t ctrl, int8_t val)
|
void Sequencer::ChannelState::setCtrlValue(uint8_t ctrl, int8_t val)
|
||||||
@@ -300,12 +334,12 @@ void Sequencer::ChannelState::setCtrlValue(uint8_t ctrl, int8_t val)
|
|||||||
|
|
||||||
bool Sequencer::ChannelState::programChange(int8_t prog)
|
bool Sequencer::ChannelState::programChange(int8_t prog)
|
||||||
{
|
{
|
||||||
if (m_parent.m_songGroup)
|
if (m_parent->m_songGroup)
|
||||||
{
|
{
|
||||||
if (m_chanId == 9)
|
if (m_chanId == 9)
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_drumPages.find(prog);
|
auto it = m_parent->m_songGroup->m_drumPages.find(prog);
|
||||||
if (it != m_parent.m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
m_curProgram = prog;
|
m_curProgram = prog;
|
||||||
@@ -314,8 +348,8 @@ bool Sequencer::ChannelState::programChange(int8_t prog)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup->m_normPages.find(prog);
|
auto it = m_parent->m_songGroup->m_normPages.find(prog);
|
||||||
if (it != m_parent.m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
m_curProgram = prog;
|
m_curProgram = prog;
|
||||||
@@ -357,9 +391,9 @@ void Sequencer::setCtrlValue(uint8_t chan, uint8_t ctrl, int8_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_chanStates[chan])
|
if (!m_chanStates[chan])
|
||||||
m_chanStates[chan].emplace(*this, chan);
|
m_chanStates[chan] = ChannelState(*this, chan);
|
||||||
|
|
||||||
m_chanStates[chan]->setCtrlValue(ctrl, val);
|
m_chanStates[chan].setCtrlValue(ctrl, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::ChannelState::setPitchWheel(float pitchWheel)
|
void Sequencer::ChannelState::setPitchWheel(float pitchWheel)
|
||||||
@@ -377,9 +411,9 @@ void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_chanStates[chan])
|
if (!m_chanStates[chan])
|
||||||
m_chanStates[chan].emplace(*this, chan);
|
m_chanStates[chan] = ChannelState(*this, chan);
|
||||||
|
|
||||||
m_chanStates[chan]->setPitchWheel(pitchWheel);
|
m_chanStates[chan].setPitchWheel(pitchWheel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::setTempo(double ticksPerSec) { m_ticksPerSec = ticksPerSec; }
|
void Sequencer::setTempo(double ticksPerSec) { m_ticksPerSec = ticksPerSec; }
|
||||||
@@ -403,18 +437,18 @@ void Sequencer::allOff(bool now)
|
|||||||
{
|
{
|
||||||
if (chan)
|
if (chan)
|
||||||
{
|
{
|
||||||
for (const auto& vox : chan->m_chanVoxs)
|
for (const auto& vox : chan.m_chanVoxs)
|
||||||
vox.second->kill();
|
vox.second->kill();
|
||||||
for (const auto& vox : chan->m_keyoffVoxs)
|
for (const auto& vox : chan.m_keyoffVoxs)
|
||||||
vox->kill();
|
vox->kill();
|
||||||
chan->m_chanVoxs.clear();
|
chan.m_chanVoxs.clear();
|
||||||
chan->m_keyoffVoxs.clear();
|
chan.m_keyoffVoxs.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (auto& chan : m_chanStates)
|
for (auto& chan : m_chanStates)
|
||||||
if (chan)
|
if (chan)
|
||||||
chan->allOff();
|
chan.allOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::allOff(uint8_t chan, bool now)
|
void Sequencer::allOff(uint8_t chan, bool now)
|
||||||
@@ -424,15 +458,15 @@ void Sequencer::allOff(uint8_t chan, bool now)
|
|||||||
|
|
||||||
if (now)
|
if (now)
|
||||||
{
|
{
|
||||||
for (const auto& vox : m_chanStates[chan]->m_chanVoxs)
|
for (const auto& vox : m_chanStates[chan].m_chanVoxs)
|
||||||
vox.second->kill();
|
vox.second->kill();
|
||||||
for (const auto& vox : m_chanStates[chan]->m_keyoffVoxs)
|
for (const auto& vox : m_chanStates[chan].m_keyoffVoxs)
|
||||||
vox->kill();
|
vox->kill();
|
||||||
m_chanStates[chan]->m_chanVoxs.clear();
|
m_chanStates[chan].m_chanVoxs.clear();
|
||||||
m_chanStates[chan]->m_keyoffVoxs.clear();
|
m_chanStates[chan].m_keyoffVoxs.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_chanStates[chan]->allOff();
|
m_chanStates[chan].allOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
@@ -476,7 +510,7 @@ void Sequencer::killKeygroup(uint8_t kg, bool now)
|
|||||||
{
|
{
|
||||||
for (auto& chan : m_chanStates)
|
for (auto& chan : m_chanStates)
|
||||||
if (chan)
|
if (chan)
|
||||||
chan->killKeygroup(kg, now);
|
chan.killKeygroup(kg, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
|
std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
|
||||||
@@ -496,7 +530,7 @@ std::shared_ptr<Voice> Sequencer::findVoice(int vid)
|
|||||||
{
|
{
|
||||||
if (chan)
|
if (chan)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> ret = chan->findVoice(vid);
|
std::shared_ptr<Voice> ret = chan.findVoice(vid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -524,7 +558,7 @@ void Sequencer::sendMacroMessage(ObjectId macroId, int32_t val)
|
|||||||
{
|
{
|
||||||
for (auto& chan : m_chanStates)
|
for (auto& chan : m_chanStates)
|
||||||
if (chan)
|
if (chan)
|
||||||
chan->sendMacroMessage(macroId, val);
|
chan.sendMacroMessage(macroId, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::playSong(const unsigned char* arrData, bool dieOnEnd)
|
void Sequencer::playSong(const unsigned char* arrData, bool dieOnEnd)
|
||||||
@@ -536,17 +570,25 @@ void Sequencer::playSong(const unsigned char* arrData, bool dieOnEnd)
|
|||||||
m_state = SequencerState::Playing;
|
m_state = SequencerState::Playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::stopSong(bool now)
|
void Sequencer::stopSong(float fadeTime, bool now)
|
||||||
{
|
{
|
||||||
allOff(now);
|
if (fadeTime == 0.f)
|
||||||
m_arrData = nullptr;
|
{
|
||||||
m_state = SequencerState::Interactive;
|
allOff(now);
|
||||||
|
m_arrData = nullptr;
|
||||||
|
m_state = SequencerState::Interactive;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_stopFadeTime = fadeTime;
|
||||||
|
m_stopFadeBeginVol = m_curVol;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::ChannelState::setVolume(float vol)
|
void Sequencer::ChannelState::setVolume(float vol)
|
||||||
{
|
{
|
||||||
m_curVol = vol;
|
m_curVol = vol;
|
||||||
float voxVol = m_parent.m_curVol * m_curVol;
|
float voxVol = m_parent->m_curVol * m_curVol;
|
||||||
for (const auto& v : m_chanVoxs)
|
for (const auto& v : m_chanVoxs)
|
||||||
{
|
{
|
||||||
Voice* vox = v.second.get();
|
Voice* vox = v.second.get();
|
||||||
@@ -574,12 +616,21 @@ void Sequencer::ChannelState::setPan(float pan)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::setVolume(float vol)
|
void Sequencer::setVolume(float vol, float fadeTime)
|
||||||
{
|
{
|
||||||
m_curVol = vol;
|
if (fadeTime == 0.f)
|
||||||
for (auto& chan : m_chanStates)
|
{
|
||||||
if (chan)
|
m_curVol = vol;
|
||||||
chan->setVolume(chan->m_curVol);
|
for (auto& chan : m_chanStates)
|
||||||
|
if (chan)
|
||||||
|
chan.setVolume(chan.m_curVol);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_volFadeTime = fadeTime;
|
||||||
|
m_volFadeTarget = vol;
|
||||||
|
m_volFadeStart = m_curVol;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t Sequencer::getChanProgram(int8_t chanId) const
|
int8_t Sequencer::getChanProgram(int8_t chanId) const
|
||||||
@@ -594,7 +645,7 @@ int8_t Sequencer::getChanProgram(int8_t chanId) const
|
|||||||
return m_midiSetup[chanId].programNo;
|
return m_midiSetup[chanId].programNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_chanStates[chanId]->m_curProgram;
|
return m_chanStates[chanId].m_curProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequencer::setChanProgram(int8_t chanId, int8_t prog)
|
bool Sequencer::setChanProgram(int8_t chanId, int8_t prog)
|
||||||
@@ -603,9 +654,9 @@ bool Sequencer::setChanProgram(int8_t chanId, int8_t prog)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_chanStates[chanId])
|
if (!m_chanStates[chanId])
|
||||||
m_chanStates[chanId].emplace(*this, chanId);
|
m_chanStates[chanId] = ChannelState(*this, chanId);
|
||||||
|
|
||||||
return m_chanStates[chanId]->programChange(prog);
|
return m_chanStates[chanId].programChange(prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::nextChanProgram(int8_t chanId)
|
void Sequencer::nextChanProgram(int8_t chanId)
|
||||||
@@ -614,9 +665,9 @@ void Sequencer::nextChanProgram(int8_t chanId)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_chanStates[chanId])
|
if (!m_chanStates[chanId])
|
||||||
m_chanStates[chanId].emplace(*this, chanId);
|
m_chanStates[chanId] = ChannelState(*this, chanId);
|
||||||
|
|
||||||
return m_chanStates[chanId]->nextProgram();
|
return m_chanStates[chanId].nextProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::prevChanProgram(int8_t chanId)
|
void Sequencer::prevChanProgram(int8_t chanId)
|
||||||
@@ -625,8 +676,8 @@ void Sequencer::prevChanProgram(int8_t chanId)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_chanStates[chanId])
|
if (!m_chanStates[chanId])
|
||||||
m_chanStates[chanId].emplace(*this, chanId);
|
m_chanStates[chanId] = ChannelState(*this, chanId);
|
||||||
|
|
||||||
return m_chanStates[chanId]->prevProgram();
|
return m_chanStates[chanId].prevProgram();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "amuse/SongConverter.hpp"
|
#include "amuse/SongConverter.hpp"
|
||||||
#include "amuse/SongState.hpp"
|
#include "amuse/SongState.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
@@ -341,8 +341,8 @@ class MIDIEncoder
|
|||||||
|
|
||||||
void _sendContinuedValue(uint32_t val)
|
void _sendContinuedValue(uint32_t val)
|
||||||
{
|
{
|
||||||
uint32_t send[3] = {};
|
uint8_t send[3] = {};
|
||||||
uint32_t* ptr = nullptr;
|
uint8_t* ptr = nullptr;
|
||||||
if (val >= 0x4000)
|
if (val >= 0x4000)
|
||||||
{
|
{
|
||||||
ptr = &send[0];
|
ptr = &send[0];
|
||||||
@@ -632,7 +632,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
isBig = song.m_bigEndian;
|
isBig = song.m_bigEndian;
|
||||||
|
|
||||||
size_t trkCount = 1;
|
size_t trkCount = 1;
|
||||||
for (std::experimental::optional<SongState::Track>& trk : song.m_tracks)
|
for (SongState::Track& trk : song.m_tracks)
|
||||||
if (trk)
|
if (trk)
|
||||||
++trkCount;
|
++trkCount;
|
||||||
|
|
||||||
@@ -695,7 +695,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate each SNG track into type-1 MIDI track */
|
/* Iterate each SNG track into type-1 MIDI track */
|
||||||
for (std::experimental::optional<SongState::Track>& trk : song.m_tracks)
|
for (SongState::Track& trk : song.m_tracks)
|
||||||
{
|
{
|
||||||
if (trk)
|
if (trk)
|
||||||
{
|
{
|
||||||
@@ -703,35 +703,35 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
std::multimap<int, Event> allEvents;
|
std::multimap<int, Event> allEvents;
|
||||||
|
|
||||||
/* Iterate all regions */
|
/* Iterate all regions */
|
||||||
while (trk->m_nextRegion->indexValid(song.m_bigEndian))
|
while (trk.m_nextRegion->indexValid(song.m_bigEndian))
|
||||||
{
|
{
|
||||||
std::multimap<int, Event> events;
|
std::multimap<int, Event> events;
|
||||||
trk->advanceRegion(nullptr);
|
trk.advanceRegion(nullptr);
|
||||||
uint32_t regStart =
|
uint32_t regStart =
|
||||||
song.m_bigEndian ? SBig(trk->m_curRegion->m_startTick) : trk->m_curRegion->m_startTick;
|
song.m_bigEndian ? SBig(trk.m_curRegion->m_startTick) : trk.m_curRegion->m_startTick;
|
||||||
|
|
||||||
/* Initial program change */
|
/* Initial program change */
|
||||||
if (trk->m_curRegion->m_progNum != 0xff)
|
if (trk.m_curRegion->m_progNum != 0xff)
|
||||||
events.emplace(regStart, Event{ProgEvent{}, trk->m_midiChan, trk->m_curRegion->m_progNum});
|
events.emplace(regStart, Event{ProgEvent{}, trk.m_midiChan, trk.m_curRegion->m_progNum});
|
||||||
|
|
||||||
/* Update continuous pitch data */
|
/* Update continuous pitch data */
|
||||||
if (trk->m_pitchWheelData)
|
if (trk.m_pitchWheelData)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* See if there's an upcoming pitch change in this interval */
|
/* See if there's an upcoming pitch change in this interval */
|
||||||
const unsigned char* ptr = trk->m_pitchWheelData;
|
const unsigned char* ptr = trk.m_pitchWheelData;
|
||||||
uint32_t deltaTicks = DecodeRLE(ptr);
|
uint32_t deltaTicks = DecodeRLE(ptr);
|
||||||
if (deltaTicks != 0xffffffff)
|
if (deltaTicks != 0xffffffff)
|
||||||
{
|
{
|
||||||
int32_t nextTick = trk->m_lastPitchTick + deltaTicks;
|
int32_t nextTick = trk.m_lastPitchTick + deltaTicks;
|
||||||
int32_t pitchDelta = DecodeContinuousRLE(ptr);
|
int32_t pitchDelta = DecodeContinuousRLE(ptr);
|
||||||
trk->m_lastPitchVal += pitchDelta;
|
trk.m_lastPitchVal += pitchDelta;
|
||||||
trk->m_pitchWheelData = ptr;
|
trk.m_pitchWheelData = ptr;
|
||||||
trk->m_lastPitchTick = nextTick;
|
trk.m_lastPitchTick = nextTick;
|
||||||
events.emplace(regStart + nextTick,
|
events.emplace(regStart + nextTick,
|
||||||
Event{PitchEvent{}, trk->m_midiChan,
|
Event{PitchEvent{}, trk.m_midiChan,
|
||||||
clamp(0, trk->m_lastPitchVal / 2 + 0x2000, 0x4000)});
|
clamp(0, trk.m_lastPitchVal / 2 + 0x2000, 0x4000)});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -739,23 +739,23 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update continuous modulation data */
|
/* Update continuous modulation data */
|
||||||
if (trk->m_modWheelData)
|
if (trk.m_modWheelData)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* See if there's an upcoming modulation change in this interval */
|
/* See if there's an upcoming modulation change in this interval */
|
||||||
const unsigned char* ptr = trk->m_modWheelData;
|
const unsigned char* ptr = trk.m_modWheelData;
|
||||||
uint32_t deltaTicks = DecodeRLE(ptr);
|
uint32_t deltaTicks = DecodeRLE(ptr);
|
||||||
if (deltaTicks != 0xffffffff)
|
if (deltaTicks != 0xffffffff)
|
||||||
{
|
{
|
||||||
int32_t nextTick = trk->m_lastModTick + deltaTicks;
|
int32_t nextTick = trk.m_lastModTick + deltaTicks;
|
||||||
int32_t modDelta = DecodeContinuousRLE(ptr);
|
int32_t modDelta = DecodeContinuousRLE(ptr);
|
||||||
trk->m_lastModVal += modDelta;
|
trk.m_lastModVal += modDelta;
|
||||||
trk->m_modWheelData = ptr;
|
trk.m_modWheelData = ptr;
|
||||||
trk->m_lastModTick = nextTick;
|
trk.m_lastModTick = nextTick;
|
||||||
events.emplace(regStart + nextTick,
|
events.emplace(regStart + nextTick,
|
||||||
Event{CtrlEvent{}, trk->m_midiChan, 1,
|
Event{CtrlEvent{}, trk.m_midiChan, 1,
|
||||||
uint8_t(clamp(0, trk->m_lastModVal * 128 / 16384, 127)), 0});
|
uint8_t(clamp(0, trk.m_lastModVal * 128 / 16384, 127)), 0});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -769,44 +769,44 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* Load next command */
|
/* Load next command */
|
||||||
if (*reinterpret_cast<const uint16_t*>(trk->m_data) == 0xffff)
|
if (*reinterpret_cast<const uint16_t*>(trk.m_data) == 0xffff)
|
||||||
{
|
{
|
||||||
/* End of channel */
|
/* End of channel */
|
||||||
trk->m_data = nullptr;
|
trk.m_data = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (trk->m_data[0] & 0x80 && trk->m_data[1] & 0x80)
|
else if (trk.m_data[0] & 0x80 && trk.m_data[1] & 0x80)
|
||||||
{
|
{
|
||||||
/* Control change */
|
/* Control change */
|
||||||
uint8_t val = trk->m_data[0] & 0x7f;
|
uint8_t val = trk.m_data[0] & 0x7f;
|
||||||
uint8_t ctrl = trk->m_data[1] & 0x7f;
|
uint8_t ctrl = trk.m_data[1] & 0x7f;
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{CtrlEvent{}, trk->m_midiChan, ctrl, val, 0});
|
Event{CtrlEvent{}, trk.m_midiChan, ctrl, val, 0});
|
||||||
trk->m_data += 2;
|
trk.m_data += 2;
|
||||||
}
|
}
|
||||||
else if (trk->m_data[0] & 0x80)
|
else if (trk.m_data[0] & 0x80)
|
||||||
{
|
{
|
||||||
/* Program change */
|
/* Program change */
|
||||||
uint8_t prog = trk->m_data[0] & 0x7f;
|
uint8_t prog = trk.m_data[0] & 0x7f;
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{ProgEvent{}, trk->m_midiChan, prog});
|
Event{ProgEvent{}, trk.m_midiChan, prog});
|
||||||
trk->m_data += 2;
|
trk.m_data += 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Note */
|
/* Note */
|
||||||
uint8_t note = trk->m_data[0] & 0x7f;
|
uint8_t note = trk.m_data[0] & 0x7f;
|
||||||
uint8_t vel = trk->m_data[1] & 0x7f;
|
uint8_t vel = trk.m_data[1] & 0x7f;
|
||||||
uint16_t length =
|
uint16_t length =
|
||||||
(song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk->m_data + 2))
|
(song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk.m_data + 2))
|
||||||
: *reinterpret_cast<const uint16_t*>(trk->m_data + 2));
|
: *reinterpret_cast<const uint16_t*>(trk.m_data + 2));
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{NoteEvent{}, trk->m_midiChan, note, vel, length});
|
Event{NoteEvent{}, trk.m_midiChan, note, vel, length});
|
||||||
trk->m_data += 4;
|
trk.m_data += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set next delta-time */
|
/* Set next delta-time */
|
||||||
trk->m_eventWaitCountdown += int32_t(DecodeTimeRLE(trk->m_data));
|
trk.m_eventWaitCountdown += int32_t(DecodeTimeRLE(trk.m_data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -815,49 +815,49 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* Load next command */
|
/* Load next command */
|
||||||
if (*reinterpret_cast<const uint16_t*>(&trk->m_data[2]) == 0xffff)
|
if (*reinterpret_cast<const uint16_t*>(&trk.m_data[2]) == 0xffff)
|
||||||
{
|
{
|
||||||
/* End of channel */
|
/* End of channel */
|
||||||
trk->m_data = nullptr;
|
trk.m_data = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((trk->m_data[2] & 0x80) != 0x80)
|
if ((trk.m_data[2] & 0x80) != 0x80)
|
||||||
{
|
{
|
||||||
/* Note */
|
/* Note */
|
||||||
uint16_t length =
|
uint16_t length =
|
||||||
(song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk->m_data))
|
(song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk.m_data))
|
||||||
: *reinterpret_cast<const uint16_t*>(trk->m_data));
|
: *reinterpret_cast<const uint16_t*>(trk.m_data));
|
||||||
uint8_t note = trk->m_data[2] & 0x7f;
|
uint8_t note = trk.m_data[2] & 0x7f;
|
||||||
uint8_t vel = trk->m_data[3] & 0x7f;
|
uint8_t vel = trk.m_data[3] & 0x7f;
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{NoteEvent{}, trk->m_midiChan, note, vel, length});
|
Event{NoteEvent{}, trk.m_midiChan, note, vel, length});
|
||||||
}
|
}
|
||||||
else if (trk->m_data[2] & 0x80 && trk->m_data[3] & 0x80)
|
else if (trk.m_data[2] & 0x80 && trk.m_data[3] & 0x80)
|
||||||
{
|
{
|
||||||
/* Control change */
|
/* Control change */
|
||||||
uint8_t val = trk->m_data[2] & 0x7f;
|
uint8_t val = trk.m_data[2] & 0x7f;
|
||||||
uint8_t ctrl = trk->m_data[3] & 0x7f;
|
uint8_t ctrl = trk.m_data[3] & 0x7f;
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{CtrlEvent{}, trk->m_midiChan, ctrl, val, 0});
|
Event{CtrlEvent{}, trk.m_midiChan, ctrl, val, 0});
|
||||||
}
|
}
|
||||||
else if (trk->m_data[2] & 0x80)
|
else if (trk.m_data[2] & 0x80)
|
||||||
{
|
{
|
||||||
/* Program change */
|
/* Program change */
|
||||||
uint8_t prog = trk->m_data[2] & 0x7f;
|
uint8_t prog = trk.m_data[2] & 0x7f;
|
||||||
events.emplace(regStart + trk->m_eventWaitCountdown,
|
events.emplace(regStart + trk.m_eventWaitCountdown,
|
||||||
Event{ProgEvent{}, trk->m_midiChan, prog});
|
Event{ProgEvent{}, trk.m_midiChan, prog});
|
||||||
}
|
}
|
||||||
trk->m_data += 4;
|
trk.m_data += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set next delta-time */
|
/* Set next delta-time */
|
||||||
int32_t absTick = (song.m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(trk->m_data))
|
int32_t absTick = (song.m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(trk.m_data))
|
||||||
: *reinterpret_cast<const int32_t*>(trk->m_data));
|
: *reinterpret_cast<const int32_t*>(trk.m_data));
|
||||||
trk->m_eventWaitCountdown += absTick - trk->m_lastN64EventTick;
|
trk.m_eventWaitCountdown += absTick - trk.m_lastN64EventTick;
|
||||||
trk->m_lastN64EventTick = absTick;
|
trk.m_lastN64EventTick = absTick;
|
||||||
trk->m_data += 4;
|
trk.m_data += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,10 +888,10 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
|
|||||||
encoder.controlChange(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal);
|
encoder.controlChange(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal);
|
||||||
break;
|
break;
|
||||||
case Event::Type::Program:
|
case Event::Type::Program:
|
||||||
encoder.programChange(trk->m_midiChan, pair.second.program);
|
encoder.programChange(trk.m_midiChan, pair.second.program);
|
||||||
break;
|
break;
|
||||||
case Event::Type::Pitch:
|
case Event::Type::Pitch:
|
||||||
encoder.pitchBend(trk->m_midiChan, pair.second.pitchBend);
|
encoder.pitchBend(trk.m_midiChan, pair.second.pitchBend);
|
||||||
break;
|
break;
|
||||||
case Event::Type::Note:
|
case Event::Type::Note:
|
||||||
if (pair.second.endEvent)
|
if (pair.second.endEvent)
|
||||||
@@ -1286,6 +1286,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
|
|||||||
curRegionOff += 12 + region.eventBuf.size() + region.pitchBuf.size() + region.modBuf.size();
|
curRegionOff += 12 + region.eventBuf.size() + region.pitchBuf.size() + region.modBuf.size();
|
||||||
int paddedRegOff = ((curRegionOff + 3) & ~3);
|
int paddedRegOff = ((curRegionOff + 3) & ~3);
|
||||||
region.padding = paddedRegOff - curRegionOff;
|
region.padding = paddedRegOff - curRegionOff;
|
||||||
|
curRegionOff = paddedRegOff;
|
||||||
regions.push_back(std::move(region));
|
regions.push_back(std::move(region));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1324,7 +1325,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
|
|||||||
reg.m_progNum = 0xff;
|
reg.m_progNum = 0xff;
|
||||||
reg.m_unk1 = 0xff;
|
reg.m_unk1 = 0xff;
|
||||||
reg.m_unk2 = 0;
|
reg.m_unk2 = 0;
|
||||||
reg.m_regionIndex = 0xffff;
|
reg.m_regionIndex = -1;
|
||||||
reg.m_unk3 = 0;
|
reg.m_unk3 = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1333,7 +1334,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
|
|||||||
reg.m_progNum = 0xff;
|
reg.m_progNum = 0xff;
|
||||||
reg.m_unk1 = 0xff;
|
reg.m_unk1 = 0xff;
|
||||||
reg.m_unk2 = 0;
|
reg.m_unk2 = 0;
|
||||||
reg.m_regionIndex = 0xffff;
|
reg.m_regionIndex = -1;
|
||||||
reg.m_unk3 = 0;
|
reg.m_unk3 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,46 +98,46 @@ void SongState::Track::Header::swapBig()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SongState::Track::Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions)
|
SongState::Track::Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions)
|
||||||
: m_parent(parent), m_midiChan(midiChan), m_curRegion(nullptr), m_nextRegion(regions)
|
: m_parent(&parent), m_midiChan(midiChan), m_curRegion(nullptr), m_nextRegion(regions)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 128; ++i)
|
for (int i = 0; i < 128; ++i)
|
||||||
m_remNoteLengths[i] = INT_MIN;
|
m_remNoteLengths[i] = std::numeric_limits<decltype(m_remNoteLengths)::value_type>::min();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SongState::Track::setRegion(Sequencer* seq, const TrackRegion* region)
|
void SongState::Track::setRegion(Sequencer* seq, const TrackRegion* region)
|
||||||
{
|
{
|
||||||
m_curRegion = region;
|
m_curRegion = region;
|
||||||
uint32_t regionIdx = (m_parent.m_bigEndian ? SBig(m_curRegion->m_regionIndex) : m_curRegion->m_regionIndex);
|
uint32_t regionIdx = (m_parent->m_bigEndian ? SBig(m_curRegion->m_regionIndex) : m_curRegion->m_regionIndex);
|
||||||
m_nextRegion = &m_curRegion[1];
|
m_nextRegion = &m_curRegion[1];
|
||||||
|
|
||||||
m_data = m_parent.m_songData +
|
m_data = m_parent->m_songData +
|
||||||
(m_parent.m_bigEndian ? SBig(m_parent.m_regionIdx[regionIdx]) : m_parent.m_regionIdx[regionIdx]);
|
(m_parent->m_bigEndian ? SBig(m_parent->m_regionIdx[regionIdx]) : m_parent->m_regionIdx[regionIdx]);
|
||||||
|
|
||||||
Header header = *reinterpret_cast<const Header*>(m_data);
|
Header header = *reinterpret_cast<const Header*>(m_data);
|
||||||
if (m_parent.m_bigEndian)
|
if (m_parent->m_bigEndian)
|
||||||
header.swapBig();
|
header.swapBig();
|
||||||
m_data += 12;
|
m_data += 12;
|
||||||
|
|
||||||
if (header.m_pitchOff)
|
if (header.m_pitchOff)
|
||||||
m_pitchWheelData = m_parent.m_songData + header.m_pitchOff;
|
m_pitchWheelData = m_parent->m_songData + header.m_pitchOff;
|
||||||
if (header.m_modOff)
|
if (header.m_modOff)
|
||||||
m_modWheelData = m_parent.m_songData + header.m_modOff;
|
m_modWheelData = m_parent->m_songData + header.m_modOff;
|
||||||
|
|
||||||
m_eventWaitCountdown = 0;
|
m_eventWaitCountdown = 0;
|
||||||
m_lastPitchTick = m_parent.m_curTick;
|
m_lastPitchTick = m_parent->m_curTick;
|
||||||
m_lastPitchVal = 0;
|
m_lastPitchVal = 0;
|
||||||
m_lastModTick = m_parent.m_curTick;
|
m_lastModTick = m_parent->m_curTick;
|
||||||
m_lastModVal = 0;
|
m_lastModVal = 0;
|
||||||
if (seq)
|
if (seq)
|
||||||
{
|
{
|
||||||
seq->setPitchWheel(m_midiChan, clamp(-1.f, m_lastPitchVal / 32768.f, 1.f));
|
seq->setPitchWheel(m_midiChan, clamp(-1.f, m_lastPitchVal / 32768.f, 1.f));
|
||||||
seq->setCtrlValue(m_midiChan, 1, clamp(0, m_lastModVal * 128 / 16384, 127));
|
seq->setCtrlValue(m_midiChan, 1, clamp(0, m_lastModVal * 128 / 16384, 127));
|
||||||
}
|
}
|
||||||
if (m_parent.m_sngVersion == 1)
|
if (m_parent->m_sngVersion == 1)
|
||||||
m_eventWaitCountdown = int32_t(DecodeTimeRLE(m_data));
|
m_eventWaitCountdown = int32_t(DecodeTimeRLE(m_data));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int32_t absTick = (m_parent.m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(m_data))
|
int32_t absTick = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(m_data))
|
||||||
: *reinterpret_cast<const int32_t*>(m_data));
|
: *reinterpret_cast<const int32_t*>(m_data));
|
||||||
m_eventWaitCountdown = absTick;
|
m_eventWaitCountdown = absTick;
|
||||||
m_lastN64EventTick = absTick;
|
m_lastN64EventTick = absTick;
|
||||||
@@ -345,10 +345,10 @@ bool SongState::initialize(const unsigned char* ptr)
|
|||||||
{
|
{
|
||||||
const TrackRegion* region =
|
const TrackRegion* region =
|
||||||
reinterpret_cast<const TrackRegion*>(ptr + (m_bigEndian ? SBig(trackIdx[i]) : trackIdx[i]));
|
reinterpret_cast<const TrackRegion*>(ptr + (m_bigEndian ? SBig(trackIdx[i]) : trackIdx[i]));
|
||||||
m_tracks[i].emplace(*this, chanMap[i], region);
|
m_tracks[i] = Track(*this, chanMap[i], region);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_tracks[i] = std::experimental::nullopt;
|
m_tracks[i] = Track();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize tempo */
|
/* Initialize tempo */
|
||||||
@@ -366,13 +366,13 @@ bool SongState::initialize(const unsigned char* ptr)
|
|||||||
|
|
||||||
bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
||||||
{
|
{
|
||||||
int32_t endTick = m_parent.m_curTick + ticks;
|
int32_t endTick = m_parent->m_curTick + ticks;
|
||||||
|
|
||||||
/* Advance region if needed */
|
/* Advance region if needed */
|
||||||
while (m_nextRegion->indexValid(m_parent.m_bigEndian))
|
while (m_nextRegion->indexValid(m_parent->m_bigEndian))
|
||||||
{
|
{
|
||||||
uint32_t nextRegTick = (m_parent.m_bigEndian ? SBig(m_nextRegion->m_startTick) : m_nextRegion->m_startTick);
|
uint32_t nextRegTick = (m_parent->m_bigEndian ? SBig(m_nextRegion->m_startTick) : m_nextRegion->m_startTick);
|
||||||
if (endTick > nextRegTick)
|
if (uint32_t(endTick) > nextRegTick)
|
||||||
advanceRegion(&seq);
|
advanceRegion(&seq);
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -381,24 +381,25 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
/* Stop finished notes */
|
/* Stop finished notes */
|
||||||
for (int i = 0; i < 128; ++i)
|
for (int i = 0; i < 128; ++i)
|
||||||
{
|
{
|
||||||
if (m_remNoteLengths[i] != INT_MIN)
|
constexpr decltype(m_remNoteLengths)::value_type MIN = std::numeric_limits<decltype(MIN)>::min();
|
||||||
|
if (m_remNoteLengths[i] != MIN)
|
||||||
{
|
{
|
||||||
m_remNoteLengths[i] -= ticks;
|
m_remNoteLengths[i] -= ticks;
|
||||||
if (m_remNoteLengths[i] <= 0)
|
if (m_remNoteLengths[i] <= 0)
|
||||||
{
|
{
|
||||||
seq.keyOff(m_midiChan, i, 0);
|
seq.keyOff(m_midiChan, i, 0);
|
||||||
m_remNoteLengths[i] = INT_MIN;
|
m_remNoteLengths[i] = MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_data)
|
if (!m_data)
|
||||||
return !m_nextRegion->indexValid(m_parent.m_bigEndian);
|
return !m_nextRegion->indexValid(m_parent->m_bigEndian);
|
||||||
|
|
||||||
/* Update continuous pitch data */
|
/* Update continuous pitch data */
|
||||||
if (m_pitchWheelData)
|
if (m_pitchWheelData)
|
||||||
{
|
{
|
||||||
int32_t pitchTick = m_parent.m_curTick;
|
int32_t pitchTick = m_parent->m_curTick;
|
||||||
int32_t remPitchTicks = ticks;
|
int32_t remPitchTicks = ticks;
|
||||||
while (pitchTick < endTick)
|
while (pitchTick < endTick)
|
||||||
{
|
{
|
||||||
@@ -431,7 +432,7 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
/* Update continuous modulation data */
|
/* Update continuous modulation data */
|
||||||
if (m_modWheelData)
|
if (m_modWheelData)
|
||||||
{
|
{
|
||||||
int32_t modTick = m_parent.m_curTick;
|
int32_t modTick = m_parent->m_curTick;
|
||||||
int32_t remModTicks = ticks;
|
int32_t remModTicks = ticks;
|
||||||
while (modTick < endTick)
|
while (modTick < endTick)
|
||||||
{
|
{
|
||||||
@@ -462,7 +463,7 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through as many commands as we can for this time period */
|
/* Loop through as many commands as we can for this time period */
|
||||||
if (m_parent.m_sngVersion == 1)
|
if (m_parent->m_sngVersion == 1)
|
||||||
{
|
{
|
||||||
/* Revision */
|
/* Revision */
|
||||||
while (true)
|
while (true)
|
||||||
@@ -481,7 +482,7 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
{
|
{
|
||||||
/* End of channel */
|
/* End of channel */
|
||||||
m_data = nullptr;
|
m_data = nullptr;
|
||||||
return !m_nextRegion->indexValid(m_parent.m_bigEndian);
|
return !m_nextRegion->indexValid(m_parent->m_bigEndian);
|
||||||
}
|
}
|
||||||
else if (m_data[0] & 0x80 && m_data[1] & 0x80)
|
else if (m_data[0] & 0x80 && m_data[1] & 0x80)
|
||||||
{
|
{
|
||||||
@@ -503,7 +504,7 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
/* Note */
|
/* Note */
|
||||||
uint8_t note = m_data[0] & 0x7f;
|
uint8_t note = m_data[0] & 0x7f;
|
||||||
uint8_t vel = m_data[1] & 0x7f;
|
uint8_t vel = m_data[1] & 0x7f;
|
||||||
uint16_t length = (m_parent.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data + 2))
|
uint16_t length = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data + 2))
|
||||||
: *reinterpret_cast<const uint16_t*>(m_data + 2));
|
: *reinterpret_cast<const uint16_t*>(m_data + 2));
|
||||||
seq.keyOn(m_midiChan, note, vel);
|
seq.keyOn(m_midiChan, note, vel);
|
||||||
m_remNoteLengths[note] = length;
|
m_remNoteLengths[note] = length;
|
||||||
@@ -533,14 +534,14 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
{
|
{
|
||||||
/* End of channel */
|
/* End of channel */
|
||||||
m_data = nullptr;
|
m_data = nullptr;
|
||||||
return !m_nextRegion->indexValid(m_parent.m_bigEndian);
|
return !m_nextRegion->indexValid(m_parent->m_bigEndian);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((m_data[2] & 0x80) != 0x80)
|
if ((m_data[2] & 0x80) != 0x80)
|
||||||
{
|
{
|
||||||
/* Note */
|
/* Note */
|
||||||
uint16_t length = (m_parent.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data))
|
uint16_t length = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data))
|
||||||
: *reinterpret_cast<const uint16_t*>(m_data));
|
: *reinterpret_cast<const uint16_t*>(m_data));
|
||||||
uint8_t note = m_data[2] & 0x7f;
|
uint8_t note = m_data[2] & 0x7f;
|
||||||
uint8_t vel = m_data[3] & 0x7f;
|
uint8_t vel = m_data[3] & 0x7f;
|
||||||
@@ -564,7 +565,7 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set next delta-time */
|
/* Set next delta-time */
|
||||||
int32_t absTick = (m_parent.m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(m_data))
|
int32_t absTick = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const int32_t*>(m_data))
|
||||||
: *reinterpret_cast<const int32_t*>(m_data));
|
: *reinterpret_cast<const int32_t*>(m_data));
|
||||||
m_eventWaitCountdown += absTick - m_lastN64EventTick;
|
m_eventWaitCountdown += absTick - m_lastN64EventTick;
|
||||||
m_lastN64EventTick = absTick;
|
m_lastN64EventTick = absTick;
|
||||||
@@ -614,9 +615,9 @@ bool SongState::advance(Sequencer& seq, double dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Advance all tracks */
|
/* Advance all tracks */
|
||||||
for (std::experimental::optional<Track>& trk : m_tracks)
|
for (Track& trk : m_tracks)
|
||||||
if (trk)
|
if (trk)
|
||||||
done &= trk->advance(seq, remTicks);
|
done &= trk.advance(seq, remTicks);
|
||||||
|
|
||||||
m_curTick += remTicks;
|
m_curTick += remTicks;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/AudioGroup.hpp"
|
#include "amuse/AudioGroup.hpp"
|
||||||
#include "amuse/AudioGroupPool.hpp"
|
#include "amuse/AudioGroupPool.hpp"
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
/* Squelch Win32 macro pollution >.< */
|
/* Squelch Win32 macro pollution >.< */
|
||||||
#undef SendMessage
|
#undef SendMessage
|
||||||
@@ -13,6 +13,19 @@
|
|||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
int SoundMacroState::_assertPC(int pc, uint32_t size)
|
||||||
|
{
|
||||||
|
if (pc == -1)
|
||||||
|
return -1;
|
||||||
|
int cmdCount = (size - sizeof(Header)) / sizeof(Command);
|
||||||
|
if (pc >= cmdCount)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SoundMacro PC bounds exceeded [%d/%d]\n", pc, cmdCount);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
void SoundMacroState::Header::swapBig()
|
void SoundMacroState::Header::swapBig()
|
||||||
{
|
{
|
||||||
m_size = SBig(m_size);
|
m_size = SBig(m_size);
|
||||||
@@ -133,7 +146,8 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
|||||||
m_curMod = midiMod;
|
m_curMod = midiMod;
|
||||||
m_curPitch = midiKey * 100;
|
m_curPitch = midiKey * 100;
|
||||||
m_pc.clear();
|
m_pc.clear();
|
||||||
m_pc.push_back({ptr, step});
|
const Header& header = reinterpret_cast<const Header&>(ptr);
|
||||||
|
m_pc.push_back({ptr, _assertPC(step, header.m_size, swapData)});
|
||||||
m_inWait = false;
|
m_inWait = false;
|
||||||
m_execTime = 0.f;
|
m_execTime = 0.f;
|
||||||
m_keyoff = false;
|
m_keyoff = false;
|
||||||
@@ -143,7 +157,7 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
|||||||
m_useAdsrControllers = false;
|
m_useAdsrControllers = false;
|
||||||
m_portamentoMode = 2;
|
m_portamentoMode = 2;
|
||||||
m_portamentoTime = 0.5f;
|
m_portamentoTime = 0.5f;
|
||||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
m_header = header;
|
||||||
if (swapData)
|
if (swapData)
|
||||||
m_header.swapBig();
|
m_header.swapBig();
|
||||||
}
|
}
|
||||||
@@ -180,6 +194,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
|
|
||||||
/* Load next command based on counter */
|
/* Load next command based on counter */
|
||||||
const Command* commands = reinterpret_cast<const Command*>(m_pc.back().first + sizeof(Header));
|
const Command* commands = reinterpret_cast<const Command*>(m_pc.back().first + sizeof(Header));
|
||||||
|
_assertPC(m_pc.back().second, m_header.m_size);
|
||||||
Command cmd = commands[m_pc.back().second++];
|
Command cmd = commands[m_pc.back().second++];
|
||||||
if (vox.getAudioGroup().getDataFormat() != DataFormat::PC)
|
if (vox.getAudioGroup().getDataFormat() != DataFormat::PC)
|
||||||
cmd.swapBig();
|
cmd.swapBig();
|
||||||
@@ -189,7 +204,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
case Op::End:
|
case Op::End:
|
||||||
case Op::Stop:
|
case Op::Stop:
|
||||||
m_pc.back().second = -1;
|
_setPC(-1);
|
||||||
return true;
|
return true;
|
||||||
case Op::SplitKey:
|
case Op::SplitKey:
|
||||||
{
|
{
|
||||||
@@ -201,7 +216,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
/* Do Branch */
|
/* Do Branch */
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
||||||
}
|
}
|
||||||
@@ -218,7 +233,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
/* Do Branch */
|
/* Do Branch */
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
||||||
}
|
}
|
||||||
@@ -287,7 +302,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
/* Loop back to step */
|
/* Loop back to step */
|
||||||
--m_loopCountdown;
|
--m_loopCountdown;
|
||||||
m_pc.back().second = step;
|
_setPC(step);
|
||||||
}
|
}
|
||||||
else /* Break out of loop */
|
else /* Break out of loop */
|
||||||
m_loopCountdown = -1;
|
m_loopCountdown = -1;
|
||||||
@@ -301,7 +316,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
|
|
||||||
/* Do Branch */
|
/* Do Branch */
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
||||||
|
|
||||||
@@ -389,7 +404,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
/* Do Branch */
|
/* Do Branch */
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
||||||
}
|
}
|
||||||
@@ -511,7 +526,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
{
|
{
|
||||||
/* Do branch */
|
/* Do branch */
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
||||||
}
|
}
|
||||||
@@ -674,12 +689,12 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
case Op::Vibrato:
|
case Op::Vibrato:
|
||||||
{
|
{
|
||||||
int32_t level = cmd.m_data[0] * 100 + cmd.m_data[1];
|
int32_t level = cmd.m_data[0] * 100 + cmd.m_data[1];
|
||||||
int32_t modLevel = cmd.m_data[2];
|
bool modScale = cmd.m_data[2] != 0;
|
||||||
int8_t ms = cmd.m_data[4];
|
int8_t ms = cmd.m_data[4];
|
||||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||||
|
|
||||||
float q = ms ? 1000.f : m_ticksPerSec;
|
float q = ms ? 1000.f : m_ticksPerSec;
|
||||||
vox.setVibrato(level, modLevel, timeMs / q);
|
vox.setVibrato(level, modScale, timeMs / q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::PitchSweep1:
|
case Op::PitchSweep1:
|
||||||
@@ -776,7 +791,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||||
|
|
||||||
if (macroId == m_header.m_macroId)
|
if (macroId == m_header.m_macroId)
|
||||||
m_pc.push_back({m_pc.back().first, macroStep});
|
m_pc.push_back({m_pc.back().first, _assertPC(macroStep, m_header.m_size)});
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod, true);
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod, true);
|
||||||
|
|
||||||
@@ -876,8 +891,8 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
}
|
}
|
||||||
case Op::SendFlag:
|
case Op::SendFlag:
|
||||||
{
|
{
|
||||||
int8_t id = cmd.m_data[0];
|
//int8_t id = cmd.m_data[0];
|
||||||
int8_t val = cmd.m_data[1];
|
//int8_t val = cmd.m_data[1];
|
||||||
break; /* TODO: figure out a good API */
|
break; /* TODO: figure out a good API */
|
||||||
}
|
}
|
||||||
case Op::PitchWheelR:
|
case Op::PitchWheelR:
|
||||||
@@ -1205,7 +1220,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
b = m_variables[b];
|
b = m_variables[b];
|
||||||
|
|
||||||
if ((a == b) ^ lnot)
|
if ((a == b) ^ lnot)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1229,7 +1244,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
|||||||
b = m_variables[b];
|
b = m_variables[b];
|
||||||
|
|
||||||
if ((a < b) ^ lnot)
|
if ((a < b) ^ lnot)
|
||||||
m_pc.back().second = macroStep;
|
_setPC(macroStep);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,8 @@ void Studio::addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA,
|
|||||||
{
|
{
|
||||||
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
|
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/* Cyclic check */
|
/* Cyclic check */
|
||||||
assert(!_cyclicCheck(this));
|
assert(!_cyclicCheck(this));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Studio::resetOutputSampleRate(double sampleRate)
|
void Studio::resetOutputSampleRate(double sampleRate)
|
||||||
|
|||||||
@@ -10,22 +10,42 @@ EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_
|
|||||||
return makeEffect<EffectChorus>(baseDelay, variation, period);
|
return makeEffect<EffectChorus>(baseDelay, variation, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectChorus& Submix::makeChorus(const EffectChorusInfo& info)
|
||||||
|
{
|
||||||
|
return makeEffect<EffectChorus>(info);
|
||||||
|
}
|
||||||
|
|
||||||
EffectDelay& Submix::makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput)
|
EffectDelay& Submix::makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput)
|
||||||
{
|
{
|
||||||
return makeEffect<EffectDelay>(initDelay, initFeedback, initOutput);
|
return makeEffect<EffectDelay>(initDelay, initFeedback, initOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectDelay& Submix::makeDelay(const EffectDelayInfo& info)
|
||||||
|
{
|
||||||
|
return makeEffect<EffectDelay>(info);
|
||||||
|
}
|
||||||
|
|
||||||
EffectReverbStd& Submix::makeReverbStd(float coloration, float mix, float time, float damping, float preDelay)
|
EffectReverbStd& Submix::makeReverbStd(float coloration, float mix, float time, float damping, float preDelay)
|
||||||
{
|
{
|
||||||
return makeEffect<EffectReverbStd>(coloration, mix, time, damping, preDelay);
|
return makeEffect<EffectReverbStd>(coloration, mix, time, damping, preDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectReverbStd& Submix::makeReverbStd(const EffectReverbStdInfo& info)
|
||||||
|
{
|
||||||
|
return makeEffect<EffectReverbStd>(info);
|
||||||
|
}
|
||||||
|
|
||||||
EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
|
EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
|
||||||
float crosstalk)
|
float crosstalk)
|
||||||
{
|
{
|
||||||
return makeEffect<EffectReverbHi>(coloration, mix, time, damping, preDelay, crosstalk);
|
return makeEffect<EffectReverbHi>(coloration, mix, time, damping, preDelay, crosstalk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectReverbHi& Submix::makeReverbHi(const EffectReverbHiInfo& info)
|
||||||
|
{
|
||||||
|
return makeEffect<EffectReverbHi>(info);
|
||||||
|
}
|
||||||
|
|
||||||
void Submix::applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const
|
void Submix::applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const
|
||||||
{
|
{
|
||||||
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
|
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
#include "amuse/SurroundProfiles.hpp"
|
|
||||||
#include <cmath>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cfloat>
|
|
||||||
|
|
||||||
namespace amuse
|
|
||||||
{
|
|
||||||
|
|
||||||
static float Dot(const Vector3f& a, const Vector3f& b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; }
|
|
||||||
|
|
||||||
static float Length(const Vector3f& a)
|
|
||||||
{
|
|
||||||
if (std::fabs(a[0]) <= FLT_EPSILON && std::fabs(a[1]) <= FLT_EPSILON && std::fabs(a[2]) <= FLT_EPSILON)
|
|
||||||
return 0.f;
|
|
||||||
return std::sqrt(Dot(a, a));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float Normalize(Vector3f& out, const Vector3f& in)
|
|
||||||
{
|
|
||||||
out[0] = in[0];
|
|
||||||
out[1] = in[1];
|
|
||||||
out[2] = in[2];
|
|
||||||
float dist = Length(out);
|
|
||||||
out[0] /= dist;
|
|
||||||
out[1] /= dist;
|
|
||||||
out[2] /= dist;
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Cross(Vector3f& out, const Vector3f& a, const Vector3f& b)
|
|
||||||
{
|
|
||||||
out[0] = a[1] * b[2] - a[2] * b[1];
|
|
||||||
out[1] = a[2] * b[0] - a[0] * b[2];
|
|
||||||
out[2] = a[0] * b[1] - a[1] * b[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimpleMatrix
|
|
||||||
{
|
|
||||||
Vector3f m_mat[3];
|
|
||||||
|
|
||||||
public:
|
|
||||||
SimpleMatrix(const Vector3f& dir, const Vector3f& up)
|
|
||||||
{
|
|
||||||
Vector3f temp;
|
|
||||||
Normalize(temp, dir);
|
|
||||||
m_mat[0][1] = temp[0];
|
|
||||||
m_mat[1][1] = temp[1];
|
|
||||||
m_mat[2][1] = temp[2];
|
|
||||||
|
|
||||||
Normalize(temp, up);
|
|
||||||
m_mat[0][2] = temp[0];
|
|
||||||
m_mat[1][2] = temp[1];
|
|
||||||
m_mat[2][2] = temp[2];
|
|
||||||
|
|
||||||
Cross(temp, dir, up);
|
|
||||||
m_mat[0][0] = temp[0];
|
|
||||||
m_mat[1][0] = temp[1];
|
|
||||||
m_mat[2][0] = temp[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
void vecMult(Vector3f& out, const Vector3f& in)
|
|
||||||
{
|
|
||||||
out[0] = Dot(m_mat[0], in);
|
|
||||||
out[1] = Dot(m_mat[1], in);
|
|
||||||
out[2] = Dot(m_mat[2], in);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReferenceVector
|
|
||||||
{
|
|
||||||
Vector3f vec;
|
|
||||||
float bias;
|
|
||||||
bool valid = false;
|
|
||||||
ReferenceVector() = default;
|
|
||||||
ReferenceVector(float x, float y, float z, float thres)
|
|
||||||
{
|
|
||||||
vec[0] = x;
|
|
||||||
vec[1] = y;
|
|
||||||
vec[2] = z;
|
|
||||||
bias = thres;
|
|
||||||
valid = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const ReferenceVector StereoVectors[8] = {
|
|
||||||
{-0.80901f, 0.58778f, 0.f, 0.3f}, {0.80901f, 0.58778f, 0.f, 0.3f},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const ReferenceVector QuadVectors[8] = {
|
|
||||||
{-0.70710f, 0.70710f, 0.f, 0.1f},
|
|
||||||
{0.70710f, 0.70710f, 0.f, 0.1f},
|
|
||||||
{-0.70710f, -0.70710f, 0.f, 0.1f},
|
|
||||||
{0.70710f, -0.70710f, 0.f, 0.1f},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const ReferenceVector Sur51Vectors[8] = {
|
|
||||||
{-0.70710f, 0.70710f, 0.f, 0.1f}, {0.70710f, 0.70710f, 0.f, 0.1f}, {-0.70710f, -0.70710f, 0.f, 0.1f},
|
|
||||||
{0.70710f, -0.70710f, 0.f, 0.1f}, {0.0f, 1.0f, 0.f, 0.1f}, {0.0f, 1.0f, 0.f, 1.0f},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const ReferenceVector Sur71Vectors[8] = {
|
|
||||||
{-0.70710f, 0.70710f, 0.f, 0.1f}, {0.70710f, 0.70710f, 0.f, 0.1f}, {-0.70710f, -0.70710f, 0.f, 0.1f},
|
|
||||||
{0.70710f, -0.70710f, 0.f, 0.1f}, {0.0f, 1.0f, 0.f, 0.1f}, {0.0f, 1.0f, 0.f, 1.0f},
|
|
||||||
{-1.f, 0.0f, 0.f, 0.1f}, {1.f, 0.0f, 0.f, 0.1f},
|
|
||||||
};
|
|
||||||
|
|
||||||
void SurroundProfiles::SetupRefs(float matOut[8], const ChannelMap& map, const Vector3f& listenEmit,
|
|
||||||
const ReferenceVector refs[])
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < map.m_channelCount && i < 8; ++i)
|
|
||||||
{
|
|
||||||
matOut[i] = 0.f;
|
|
||||||
if (map.m_channels[i] == AudioChannel::Unknown)
|
|
||||||
continue;
|
|
||||||
const ReferenceVector& refVec = refs[int(map.m_channels[i])];
|
|
||||||
if (!refVec.valid)
|
|
||||||
continue;
|
|
||||||
matOut[i] = std::max(1.f, Dot(listenEmit, refVec.vec) + refVec.bias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SurroundProfiles::SetupMatrix(float matOut[8], const ChannelMap& map, AudioChannelSet set, const Vector3f& emitPos,
|
|
||||||
const Vector3f& listenPos, const Vector3f& listenHeading, const Vector3f& listenUp)
|
|
||||||
{
|
|
||||||
Vector3f listenDelta;
|
|
||||||
listenDelta[0] = emitPos[0] - listenPos[0];
|
|
||||||
listenDelta[1] = emitPos[1] - listenPos[1];
|
|
||||||
listenDelta[2] = emitPos[2] - listenPos[2];
|
|
||||||
|
|
||||||
Vector3f listenNorm;
|
|
||||||
float dist = Normalize(listenNorm, listenDelta);
|
|
||||||
|
|
||||||
SimpleMatrix listenerMat(listenHeading, listenUp);
|
|
||||||
Vector3f listenEmit;
|
|
||||||
listenerMat.vecMult(listenEmit, listenNorm);
|
|
||||||
|
|
||||||
/* Factor for each channel in set */
|
|
||||||
switch (set)
|
|
||||||
{
|
|
||||||
case AudioChannelSet::Stereo:
|
|
||||||
default:
|
|
||||||
SetupRefs(matOut, map, listenEmit, StereoVectors);
|
|
||||||
break;
|
|
||||||
case AudioChannelSet::Quad:
|
|
||||||
SetupRefs(matOut, map, listenEmit, QuadVectors);
|
|
||||||
break;
|
|
||||||
case AudioChannelSet::Surround51:
|
|
||||||
SetupRefs(matOut, map, listenEmit, Sur51Vectors);
|
|
||||||
break;
|
|
||||||
case AudioChannelSet::Surround71:
|
|
||||||
SetupRefs(matOut, map, listenEmit, Sur71Vectors);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
283
lib/Voice.cpp
@@ -8,11 +8,10 @@
|
|||||||
#include "amuse/DSPCodec.h"
|
#include "amuse/DSPCodec.h"
|
||||||
#include "amuse/N64MusyXCodec.h"
|
#include "amuse/N64MusyXCodec.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
extern "C" const float VolumeLUT[];
|
|
||||||
|
|
||||||
void Voice::_destroy()
|
void Voice::_destroy()
|
||||||
{
|
{
|
||||||
@@ -46,7 +45,8 @@ void Voice::_macroSampleEnd()
|
|||||||
{
|
{
|
||||||
if (m_sampleEndTrap.macroId == m_state.m_header.m_macroId)
|
if (m_sampleEndTrap.macroId == m_state.m_header.m_macroId)
|
||||||
{
|
{
|
||||||
m_state.m_pc.back().second = m_sampleEndTrap.macroStep;
|
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_sampleEndTrap.macroStep,
|
||||||
|
m_state.m_header.m_size);
|
||||||
m_state.m_inWait = false;
|
m_state.m_inWait = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -117,7 +117,7 @@ void Voice::_setTotalPitch(int32_t cents, bool slew)
|
|||||||
{
|
{
|
||||||
// fprintf(stderr, "PITCH %d %d \n", cents, slew);
|
// fprintf(stderr, "PITCH %d %d \n", cents, slew);
|
||||||
int32_t interval = cents - m_curSample->first.m_pitch * 100;
|
int32_t interval = cents - m_curSample->first.m_pitch * 100;
|
||||||
double ratio = std::exp2(interval / 1200.0);
|
double ratio = std::exp2(interval / 1200.0) * m_dopplerRatio;
|
||||||
m_sampleRate = m_curSample->first.m_sampleRate * ratio;
|
m_sampleRate = m_curSample->first.m_sampleRate * ratio;
|
||||||
m_backendVoice->setPitchRatio(ratio, slew);
|
m_backendVoice->setPitchRatio(ratio, slew);
|
||||||
}
|
}
|
||||||
@@ -192,8 +192,7 @@ std::list<std::shared_ptr<Voice>>::iterator Voice::_destroyVoice(std::list<std::
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static T ApplyVolume(float vol, T samp)
|
static T ApplyVolume(float vol, T samp)
|
||||||
{
|
{
|
||||||
/* -10dB to 0dB mapped to full volume range */
|
return samp * vol;
|
||||||
return samp * VolumeLUT[int(vol * 65536)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::_procSamplePre(int16_t& samp)
|
void Voice::_procSamplePre(int16_t& samp)
|
||||||
@@ -220,7 +219,7 @@ void Voice::_procSamplePre(int16_t& samp)
|
|||||||
float l = clamp(0.f, m_lastLevel * (1.f - t) + m_nextLevel * t, 1.f);
|
float l = clamp(0.f, m_lastLevel * (1.f - t) + m_nextLevel * t, 1.f);
|
||||||
|
|
||||||
/* Apply total volume to sample using decibel scale */
|
/* Apply total volume to sample using decibel scale */
|
||||||
samp = ApplyVolume(l, samp);
|
samp = ApplyVolume(l * m_engine.m_masterVolume, samp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +313,7 @@ void Voice::_procSamplePre(int16_t& samp)
|
|||||||
m_nextLevel = clamp(0.f, m_nextLevel, 1.f);
|
m_nextLevel = clamp(0.f, m_nextLevel, 1.f);
|
||||||
|
|
||||||
/* Apply total volume to sample using decibel scale */
|
/* Apply total volume to sample using decibel scale */
|
||||||
samp = ApplyVolume(m_nextLevel, samp);
|
samp = ApplyVolume(m_nextLevel * m_engine.m_masterVolume, samp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -449,6 +448,18 @@ void Voice::preSupplyAudio(double dt)
|
|||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Process vibrato */
|
||||||
|
if (m_vibratoTime >= 0.f)
|
||||||
|
{
|
||||||
|
m_vibratoTime += dt;
|
||||||
|
float vibrato = std::sin(m_vibratoTime / m_vibratoPeriod * (2.f * M_PIF));
|
||||||
|
if (m_vibratoModWheel)
|
||||||
|
newPitch += m_vibratoModLevel * vibrato;
|
||||||
|
else
|
||||||
|
newPitch += m_vibratoLevel * vibrato;
|
||||||
|
refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Process pitch sweep 1 */
|
/* Process pitch sweep 1 */
|
||||||
if (m_pitchSweep1It < m_pitchSweep1Times)
|
if (m_pitchSweep1It < m_pitchSweep1Times)
|
||||||
{
|
{
|
||||||
@@ -723,7 +734,7 @@ int Voice::maxVid() const
|
|||||||
std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Voice>>::iterator vox = _allocateVoice(32000.0, true);
|
std::list<std::shared_ptr<Voice>>::iterator vox = _allocateVoice(NativeSampleRate, true);
|
||||||
if (!(*vox)->loadSoundObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
|
if (!(*vox)->loadSoundObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
|
||||||
{
|
{
|
||||||
_destroyVoice(vox);
|
_destroyVoice(vox);
|
||||||
@@ -751,9 +762,11 @@ bool Voice::_loadSoundMacro(const unsigned char* macroData, int macroStep, doubl
|
|||||||
{
|
{
|
||||||
if (!pushPc)
|
if (!pushPc)
|
||||||
m_state.m_pc.clear();
|
m_state.m_pc.clear();
|
||||||
m_state.m_pc.push_back({macroData, macroStep});
|
const SoundMacroState::Header& header = reinterpret_cast<const SoundMacroState::Header&>(macroData);
|
||||||
m_state.m_header = *reinterpret_cast<const SoundMacroState::Header*>(macroData);
|
const bool swapData = m_audioGroup.getDataFormat() != DataFormat::PC;
|
||||||
if (m_audioGroup.getDataFormat() != DataFormat::PC)
|
m_state.m_pc.push_back({macroData, SoundMacroState::_assertPC(macroStep, header.m_size, swapData)});
|
||||||
|
m_state.m_header = header;
|
||||||
|
if (swapData)
|
||||||
m_state.m_header.swapBig();
|
m_state.m_header.swapBig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,17 +826,29 @@ bool Voice::_loadLayer(const std::vector<const LayerMapping*>& layer, int macroS
|
|||||||
bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
||||||
uint8_t midiMod, bool pushPc)
|
uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return false;
|
||||||
|
|
||||||
const unsigned char* macroData = m_audioGroup.getPool().soundMacro(objectId);
|
const unsigned char* macroData = m_audioGroup.getPool().soundMacro(objectId);
|
||||||
if (macroData)
|
if (macroData)
|
||||||
|
{
|
||||||
|
m_objectId = objectId;
|
||||||
return _loadSoundMacro(macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadSoundMacro(macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
|
}
|
||||||
|
|
||||||
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
|
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
|
||||||
if (keymap)
|
if (keymap)
|
||||||
|
{
|
||||||
|
m_objectId = objectId;
|
||||||
return _loadKeymap(keymap, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadKeymap(keymap, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<const LayerMapping*>* layer = m_audioGroup.getPool().layer(objectId);
|
const std::vector<const LayerMapping*>* layer = m_audioGroup.getPool().layer(objectId);
|
||||||
if (layer)
|
if (layer)
|
||||||
|
{
|
||||||
|
m_objectId = objectId;
|
||||||
return _loadLayer(*layer, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadLayer(*layer, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -842,18 +867,22 @@ void Voice::_macroKeyOff()
|
|||||||
|
|
||||||
void Voice::keyOff()
|
void Voice::keyOff()
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_keyoffTrap.macroId != 0xffff)
|
if (m_keyoffTrap.macroId != 0xffff)
|
||||||
{
|
{
|
||||||
if (m_keyoffTrap.macroId == m_state.m_header.m_macroId)
|
if (m_keyoffTrap.macroId == m_state.m_header.m_macroId)
|
||||||
{
|
{
|
||||||
m_state.m_pc.back().second = m_keyoffTrap.macroStep;
|
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_keyoffTrap.macroStep,
|
||||||
|
m_state.m_header.m_size);
|
||||||
m_state.m_inWait = false;
|
m_state.m_inWait = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
m_state.m_initVel, m_state.m_initMod);
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
}
|
}
|
||||||
else
|
else if (!m_curSample || m_curSample->first.m_loopLengthSamples)
|
||||||
_macroKeyOff();
|
_macroKeyOff();
|
||||||
|
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
@@ -862,12 +891,16 @@ void Voice::keyOff()
|
|||||||
|
|
||||||
void Voice::message(int32_t val)
|
void Voice::message(int32_t val)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_messageQueue.push_back(val);
|
m_messageQueue.push_back(val);
|
||||||
|
|
||||||
if (m_messageTrap.macroId != 0xffff)
|
if (m_messageTrap.macroId != 0xffff)
|
||||||
{
|
{
|
||||||
if (m_messageTrap.macroId == m_state.m_header.m_macroId)
|
if (m_messageTrap.macroId == m_state.m_header.m_macroId)
|
||||||
m_state.m_pc.back().second = m_messageTrap.macroStep;
|
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_messageTrap.macroStep,
|
||||||
|
m_state.m_header.m_size);
|
||||||
else
|
else
|
||||||
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
m_state.m_initVel, m_state.m_initMod);
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
@@ -876,6 +909,9 @@ void Voice::message(int32_t val)
|
|||||||
|
|
||||||
void Voice::startSample(int16_t sampId, int32_t offset)
|
void Voice::startSample(int16_t sampId, int32_t offset)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curSample = m_audioGroup.getSample(sampId);
|
m_curSample = m_audioGroup.getSample(sampId);
|
||||||
if (m_curSample)
|
if (m_curSample)
|
||||||
{
|
{
|
||||||
@@ -939,55 +975,144 @@ void Voice::stopSample() { m_curSample = nullptr; }
|
|||||||
|
|
||||||
void Voice::setVolume(float vol)
|
void Voice::setVolume(float vol)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_targetUserVol = clamp(0.f, vol, 1.f);
|
m_targetUserVol = clamp(0.f, vol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
vox->setVolume(vol);
|
vox->setVolume(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::_panLaw(float coefs[8], float frontPan, float backPan, float totalSpan) const
|
||||||
|
{
|
||||||
|
/* -3dB panning law for various channel configs */
|
||||||
|
switch (m_engine.m_channelSet)
|
||||||
|
{
|
||||||
|
case AudioChannelSet::Stereo:
|
||||||
|
default:
|
||||||
|
/* Left */
|
||||||
|
coefs[0] = std::sqrt(-frontPan * 0.5f + 0.5f);
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
coefs[1] = std::sqrt(frontPan * 0.5f + 0.5f);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AudioChannelSet::Quad:
|
||||||
|
/* Left */
|
||||||
|
coefs[0] = -frontPan * 0.5f + 0.5f;
|
||||||
|
coefs[0] *= -totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[0] = std::sqrt(coefs[0]);
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
coefs[1] = frontPan * 0.5f + 0.5f;
|
||||||
|
coefs[1] *= -totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[1] = std::sqrt(coefs[1]);
|
||||||
|
|
||||||
|
/* Back Left */
|
||||||
|
coefs[2] = -backPan * 0.5f + 0.5f;
|
||||||
|
coefs[2] *= totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[2] = std::sqrt(coefs[2]);
|
||||||
|
|
||||||
|
/* Back Right */
|
||||||
|
coefs[3] = backPan * 0.5f + 0.5f;
|
||||||
|
coefs[3] *= totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[3] = std::sqrt(coefs[3]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AudioChannelSet::Surround51:
|
||||||
|
/* Left */
|
||||||
|
coefs[0] = (frontPan <= 0.f) ? -frontPan : 0.f;
|
||||||
|
coefs[0] *= -totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[0] = std::sqrt(coefs[0]);
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
coefs[1] = (frontPan >= 0.f) ? frontPan : 0.f;
|
||||||
|
coefs[1] *= -totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[1] = std::sqrt(coefs[1]);
|
||||||
|
|
||||||
|
/* Back Left */
|
||||||
|
coefs[2] = -backPan * 0.5f + 0.5f;
|
||||||
|
coefs[2] *= totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[2] = std::sqrt(coefs[2]);
|
||||||
|
|
||||||
|
/* Back Right */
|
||||||
|
coefs[3] = backPan * 0.5f + 0.5f;
|
||||||
|
coefs[3] *= totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[3] = std::sqrt(coefs[3]);
|
||||||
|
|
||||||
|
/* Center */
|
||||||
|
coefs[4] = 1.f - std::fabs(frontPan);
|
||||||
|
coefs[4] *= -totalSpan * 0.5f + 0.5f;
|
||||||
|
coefs[4] = std::sqrt(coefs[4]);
|
||||||
|
|
||||||
|
/* LFE */
|
||||||
|
coefs[5] = 0.25f;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AudioChannelSet::Surround71:
|
||||||
|
/* Left */
|
||||||
|
coefs[0] = (frontPan <= 0.f) ? -frontPan : 0.f;
|
||||||
|
coefs[0] *= (totalSpan <= 0.f) ? -totalSpan : 0.f;
|
||||||
|
coefs[0] = std::sqrt(coefs[0]);
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
coefs[1] = (frontPan >= 0.f) ? frontPan : 0.f;
|
||||||
|
coefs[1] *= (totalSpan <= 0.f) ? -totalSpan : 0.f;
|
||||||
|
coefs[1] = std::sqrt(coefs[1]);
|
||||||
|
|
||||||
|
/* Back Left */
|
||||||
|
coefs[2] = -backPan * 0.5f + 0.5f;
|
||||||
|
coefs[2] *= (totalSpan >= 0.f) ? totalSpan : 0.f;
|
||||||
|
coefs[2] = std::sqrt(coefs[2]);
|
||||||
|
|
||||||
|
/* Back Right */
|
||||||
|
coefs[3] = backPan * 0.5f + 0.5f;
|
||||||
|
coefs[3] *= (totalSpan >= 0.f) ? totalSpan : 0.f;
|
||||||
|
coefs[3] = std::sqrt(coefs[3]);
|
||||||
|
|
||||||
|
/* Center */
|
||||||
|
coefs[4] = 1.f - std::fabs(frontPan);
|
||||||
|
coefs[4] *= (totalSpan <= 0.f) ? -totalSpan : 0.f;
|
||||||
|
coefs[4] = std::sqrt(coefs[4]);
|
||||||
|
|
||||||
|
/* LFE */
|
||||||
|
coefs[5] = 0.25f;
|
||||||
|
|
||||||
|
/* Side Left */
|
||||||
|
coefs[6] = -backPan * 0.5f + 0.5f;
|
||||||
|
coefs[6] *= 1.f - std::fabs(totalSpan);
|
||||||
|
coefs[6] = std::sqrt(coefs[6]);
|
||||||
|
|
||||||
|
/* Side Right */
|
||||||
|
coefs[7] = backPan * 0.5f + 0.5f;
|
||||||
|
coefs[7] *= 1.f - std::fabs(totalSpan);
|
||||||
|
coefs[7] = std::sqrt(coefs[7]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Voice::_setPan(float pan)
|
void Voice::_setPan(float pan)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed || m_emitter)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curPan = clamp(-1.f, pan, 1.f);
|
m_curPan = clamp(-1.f, pan, 1.f);
|
||||||
float totalPan = clamp(-1.f, m_curPan + m_userPan, 1.f);
|
float totalPan = clamp(-1.f, m_curPan + m_userPan, 1.f);
|
||||||
float totalSpan = clamp(-1.f, m_curSpan + m_userSpan, 1.f);
|
float totalSpan = clamp(-1.f, m_curSpan + m_userSpan, 1.f);
|
||||||
float coefs[8];
|
float coefs[8] = {};
|
||||||
|
_panLaw(coefs, totalPan, totalPan, totalSpan);
|
||||||
/* Left */
|
_setChannelCoefs(coefs);
|
||||||
coefs[0] = (totalPan <= 0.f) ? 1.f : (1.f - totalPan);
|
|
||||||
coefs[0] *= (totalSpan <= 0.f) ? 1.f : (1.f - totalSpan);
|
|
||||||
|
|
||||||
/* Right */
|
|
||||||
coefs[1] = (totalPan >= 0.f) ? 1.f : (1.f + totalPan);
|
|
||||||
coefs[1] *= (totalSpan <= 0.f) ? 1.f : (1.f - totalSpan);
|
|
||||||
|
|
||||||
/* Back Left */
|
|
||||||
coefs[2] = (totalPan <= 0.f) ? 1.f : (1.f - totalPan);
|
|
||||||
coefs[2] *= (totalSpan >= 0.f) ? 1.f : (1.f + totalSpan);
|
|
||||||
|
|
||||||
/* Back Right */
|
|
||||||
coefs[3] = (totalPan >= 0.f) ? 1.f : (1.f + totalPan);
|
|
||||||
coefs[3] *= (totalSpan >= 0.f) ? 1.f : (1.f + totalSpan);
|
|
||||||
|
|
||||||
/* Center */
|
|
||||||
coefs[4] = 1.f - std::fabs(totalPan);
|
|
||||||
|
|
||||||
/* LFE */
|
|
||||||
coefs[5] = 1.f;
|
|
||||||
|
|
||||||
/* Side Left */
|
|
||||||
coefs[6] = (totalPan <= 0.f) ? 1.f : (1.f - totalPan);
|
|
||||||
coefs[6] *= 1.f - std::fabs(totalSpan);
|
|
||||||
|
|
||||||
/* Side Right */
|
|
||||||
coefs[7] = (totalPan >= 0.f) ? 1.f : (1.f + totalPan);
|
|
||||||
coefs[7] *= 1.f - std::fabs(totalSpan);
|
|
||||||
|
|
||||||
m_backendVoice->setChannelLevels(m_studio->getMaster().m_backendSubmix.get(), coefs, true);
|
|
||||||
m_backendVoice->setChannelLevels(m_studio->getAuxA().m_backendSubmix.get(), coefs, true);
|
|
||||||
m_backendVoice->setChannelLevels(m_studio->getAuxB().m_backendSubmix.get(), coefs, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::setPan(float pan)
|
void Voice::setPan(float pan)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_userPan = pan;
|
m_userPan = pan;
|
||||||
_setPan(m_curPan);
|
_setPan(m_curPan);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
@@ -1002,12 +1127,32 @@ void Voice::_setSurroundPan(float span)
|
|||||||
|
|
||||||
void Voice::setSurroundPan(float span)
|
void Voice::setSurroundPan(float span)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_userSpan = span;
|
m_userSpan = span;
|
||||||
_setSurroundPan(m_curSpan);
|
_setSurroundPan(m_curSpan);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
vox->setSurroundPan(span);
|
vox->setSurroundPan(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::_setChannelCoefs(const float coefs[8])
|
||||||
|
{
|
||||||
|
m_backendVoice->setChannelLevels(m_studio->getMaster().m_backendSubmix.get(), coefs, true);
|
||||||
|
m_backendVoice->setChannelLevels(m_studio->getAuxA().m_backendSubmix.get(), coefs, true);
|
||||||
|
m_backendVoice->setChannelLevels(m_studio->getAuxB().m_backendSubmix.get(), coefs, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Voice::setChannelCoefs(const float coefs[8])
|
||||||
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_setChannelCoefs(coefs);
|
||||||
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
|
vox->setChannelCoefs(coefs);
|
||||||
|
}
|
||||||
|
|
||||||
void Voice::startEnvelope(double dur, float vol, const Curve* envCurve)
|
void Voice::startEnvelope(double dur, float vol, const Curve* envCurve)
|
||||||
{
|
{
|
||||||
m_envelopeTime = 0.f;
|
m_envelopeTime = 0.f;
|
||||||
@@ -1050,6 +1195,9 @@ void Voice::setPitchKey(int32_t cents)
|
|||||||
|
|
||||||
void Voice::setPedal(bool pedal)
|
void Voice::setPedal(bool pedal)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_sustained && !pedal && m_sustainKeyOff)
|
if (m_sustained && !pedal && m_sustainKeyOff)
|
||||||
{
|
{
|
||||||
m_sustainKeyOff = false;
|
m_sustainKeyOff = false;
|
||||||
@@ -1063,10 +1211,11 @@ void Voice::setPedal(bool pedal)
|
|||||||
|
|
||||||
void Voice::setDoppler(float) {}
|
void Voice::setDoppler(float) {}
|
||||||
|
|
||||||
void Voice::setVibrato(int32_t level, int32_t modLevel, float period)
|
void Voice::setVibrato(int32_t level, bool modScale, float period)
|
||||||
{
|
{
|
||||||
|
m_vibratoTime = std::fabs(period) < FLT_EPSILON ? -1.f : 0.f;
|
||||||
m_vibratoLevel = level;
|
m_vibratoLevel = level;
|
||||||
m_vibratoModLevel = modLevel;
|
m_vibratoModWheel = modScale;
|
||||||
m_vibratoPeriod = period;
|
m_vibratoPeriod = period;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1096,6 +1245,9 @@ void Voice::setPitchSweep2(uint8_t times, int16_t add)
|
|||||||
|
|
||||||
void Voice::setReverbVol(float rvol)
|
void Voice::setReverbVol(float rvol)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curReverbVol = clamp(0.f, rvol, 1.f);
|
m_curReverbVol = clamp(0.f, rvol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
vox->setReverbVol(rvol);
|
vox->setReverbVol(rvol);
|
||||||
@@ -1103,6 +1255,9 @@ void Voice::setReverbVol(float rvol)
|
|||||||
|
|
||||||
void Voice::setAuxBVol(float bvol)
|
void Voice::setAuxBVol(float bvol)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curAuxBVol = clamp(0.f, bvol, 1.f);
|
m_curAuxBVol = clamp(0.f, bvol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
vox->setAuxBVol(bvol);
|
vox->setAuxBVol(bvol);
|
||||||
@@ -1110,6 +1265,9 @@ void Voice::setAuxBVol(float bvol)
|
|||||||
|
|
||||||
void Voice::setAdsr(ObjectId adsrId, bool dls)
|
void Voice::setAdsr(ObjectId adsrId, bool dls)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (dls)
|
if (dls)
|
||||||
{
|
{
|
||||||
const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId);
|
const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId);
|
||||||
@@ -1134,6 +1292,9 @@ void Voice::setAdsr(ObjectId adsrId, bool dls)
|
|||||||
|
|
||||||
void Voice::setPitchFrequency(uint32_t hz, uint16_t fine)
|
void Voice::setPitchFrequency(uint32_t hz, uint16_t fine)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_sampleRate = hz + fine / 65536.0;
|
m_sampleRate = hz + fine / 65536.0;
|
||||||
m_backendVoice->setPitchRatio(1.0, false);
|
m_backendVoice->setPitchRatio(1.0, false);
|
||||||
m_backendVoice->resetSampleRate(m_sampleRate);
|
m_backendVoice->resetSampleRate(m_sampleRate);
|
||||||
@@ -1141,6 +1302,9 @@ void Voice::setPitchFrequency(uint32_t hz, uint16_t fine)
|
|||||||
|
|
||||||
void Voice::setPitchAdsr(ObjectId adsrId, int32_t cents)
|
void Voice::setPitchAdsr(ObjectId adsrId, int32_t cents)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId);
|
const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId);
|
||||||
if (adsr)
|
if (adsr)
|
||||||
{
|
{
|
||||||
@@ -1152,6 +1316,9 @@ void Voice::setPitchAdsr(ObjectId adsrId, int32_t cents)
|
|||||||
|
|
||||||
void Voice::_setPitchWheel(float pitchWheel)
|
void Voice::_setPitchWheel(float pitchWheel)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (pitchWheel > 0.f)
|
if (pitchWheel > 0.f)
|
||||||
m_pitchWheelVal = m_pitchWheelUp * m_curPitchWheel;
|
m_pitchWheelVal = m_pitchWheelUp * m_curPitchWheel;
|
||||||
else if (pitchWheel < 0.f)
|
else if (pitchWheel < 0.f)
|
||||||
@@ -1163,6 +1330,9 @@ void Voice::_setPitchWheel(float pitchWheel)
|
|||||||
|
|
||||||
void Voice::setPitchWheel(float pitchWheel)
|
void Voice::setPitchWheel(float pitchWheel)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curPitchWheel = amuse::clamp(-1.f, pitchWheel, 1.f);
|
m_curPitchWheel = amuse::clamp(-1.f, pitchWheel, 1.f);
|
||||||
_setPitchWheel(m_curPitchWheel);
|
_setPitchWheel(m_curPitchWheel);
|
||||||
|
|
||||||
@@ -1172,6 +1342,9 @@ void Voice::setPitchWheel(float pitchWheel)
|
|||||||
|
|
||||||
void Voice::setPitchWheelRange(int8_t up, int8_t down)
|
void Voice::setPitchWheelRange(int8_t up, int8_t down)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_pitchWheelUp = up * 100;
|
m_pitchWheelUp = up * 100;
|
||||||
m_pitchWheelDown = down * 100;
|
m_pitchWheelDown = down * 100;
|
||||||
_setPitchWheel(m_curPitchWheel);
|
_setPitchWheel(m_curPitchWheel);
|
||||||
@@ -1179,6 +1352,9 @@ void Voice::setPitchWheelRange(int8_t up, int8_t down)
|
|||||||
|
|
||||||
void Voice::setAftertouch(uint8_t aftertouch)
|
void Voice::setAftertouch(uint8_t aftertouch)
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_curAftertouch = aftertouch;
|
m_curAftertouch = aftertouch;
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
vox->setAftertouch(aftertouch);
|
vox->setAftertouch(aftertouch);
|
||||||
@@ -1243,6 +1419,9 @@ size_t Voice::getTotalVoices() const
|
|||||||
|
|
||||||
void Voice::kill()
|
void Voice::kill()
|
||||||
{
|
{
|
||||||
|
if (m_destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
m_voxState = VoiceState::Dead;
|
m_voxState = VoiceState::Dead;
|
||||||
m_backendVoice->stop();
|
m_backendVoice->stop();
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
|
|||||||