83 Commits

Author SHA1 Message Date
Jack Andersen
77c7daa67c Windows build fixes and warning avoidance 2018-05-24 20:37:27 -10:00
e3c936648b Fix compiling of amuserender/play 2018-05-20 08:29:27 -07:00
Jack Andersen
1fefba66e7 Implement VIBRATO 2018-05-18 19:15:12 -10:00
Jack Andersen
594fb346e1 Add sanitizers to executable targets 2018-05-06 13:06:49 -10:00
Jack Andersen
3833c137f6 Linux amuseplay crash fixes 2018-05-06 12:47:03 -10:00
Jack Andersen
912eb7950c Add amuse-gui .rc in CMake 2018-03-23 11:54:52 -10:00
4146cdd049 Rename mainwindow.ui to MainWindow.ui 2018-03-15 16:17:00 -07:00
Jack Andersen
f5a0a46453 Stub editor application 2018-03-14 14:25:29 -10:00
Jack Andersen
8f94bdd488 Minor syntax adjustment 2018-01-11 16:32:13 -10:00
Jack Andersen
f37296d560 Updated boo API 2018-01-09 20:18:15 -10:00
fd292491c7 Build fix 2018-01-07 01:27:58 -08:00
Jack Andersen
380381c7d1 Update for boo API change 2018-01-06 19:18:31 -10:00
Jack Andersen
3f9a91b0ab Disable cotire unity build 2017-12-31 16:52:40 -10:00
Jack Andersen
985994a291 Huge compile performance refactor 2017-12-28 21:57:22 -10:00
Jack Andersen
e37128d657 Use com.axiodl.* rather than io.github.axiodl.* for Apple identifiers 2017-12-27 17:45:59 -10:00
Jack Andersen
4c2a262478 Removed redundant NDEBUGs 2017-12-22 19:35:55 -10:00
Jack Andersen
3eba4cc1ac Minor Amuse-AU changes 2017-12-15 14:18:57 -10:00
Jack Andersen
91b88c0568 Add ASan build capability 2017-12-11 16:05:54 -10:00
Jack Andersen
6f7d09ce45 Fix amuseplay build 2017-12-06 18:34:45 -10:00
Jack Andersen
5caf6bf017 Remove optional.hpp dependency 2017-12-06 18:06:35 -10:00
Jack Andersen
d399f1d302 UWP support 2017-12-05 17:23:07 -10:00
Jack Andersen
77215fc996 boo::ObjToken for referencing voices and submixes 2017-12-03 16:51:23 -10:00
Jack Andersen
2f4d0e7541 Minor code formatting adjustments 2017-12-02 20:09:34 -10:00
Jack Andersen
89233e98b5 Use sqrt() in pan law 2017-11-28 00:05:59 -10:00
Jack Andersen
b890a76e20 Adjust 7.1 pan law 2017-11-27 17:38:58 -10:00
Jack Andersen
3c7cf5515f Voice lifetime and emitter bug fixes 2017-11-27 16:44:35 -10:00
Jack Andersen
ebe6f18898 MIDIToSong bug fix 2017-11-26 19:04:13 -10:00
Jack Andersen
cab7402104 Don't keyoff on non-trapped, non-looping macros 2017-11-21 00:35:38 -10:00
Jack Andersen
862c618b7e Require CMake 3.10 2017-11-13 18:52:03 -10:00
Jack Andersen
448b212ad9 Windows fixes 2017-11-13 17:35:02 -10:00
Jack Andersen
03d597b0ac Linux build fixes 2017-11-12 21:21:07 -10:00
Jack Andersen
75830dc6dd string_view refactor 2017-11-12 20:15:33 -10:00
Jack Andersen
e18c0a62de Update amuseplay for boo changes 2017-11-04 20:16:06 -10:00
Jack Andersen
047a91452e Win32 macro undef 2017-09-30 19:30:34 -10:00
Jack Andersen
fdf07d6c33 Update amuseplay for new texture API 2017-09-30 18:30:12 -10:00
Jack Andersen
4b2b86f420 Emitter bug fixes and test macro for amuseplay 2017-09-19 23:22:46 -10:00
Jack Andersen
c6781df90a Implement listener, emitter, and -3dB pan law 2017-09-18 17:59:20 -10:00
Jack Andersen
aef2b2a707 Update amuseplay for boo changes 2017-07-16 16:55:14 -10:00
0bace131e8 Compile fixes 2017-07-02 03:14:33 -07:00
Tom M
4e7c31849d Minor fixes (#6)
* cmake: require c++14

* correctly clip samples

by using numeric_limits rather than C macros

* oops, implicit type conversion of template causes overflow

* store default sample rate in global constexpr var
2017-06-17 16:48:52 -10:00
Jack Andersen
3d56d5f0cc MIDI encoder fix 2017-03-23 19:28:05 -10:00
54bbc7399a Use std::fabs instead of std::fabsf 2017-02-28 21:36:58 -08:00
Jack Andersen
a23af16349 Add sequencer fade times 2017-02-26 19:24:58 -10:00
Jack Andersen
5c8fa2e8ab New engine event interface 2017-02-14 20:01:39 -10:00
Jack Andersen
aff8880595 Better volume handling 2017-02-05 17:21:38 -10:00
Jack Andersen
2e7345f11d Add info structures for holding effect parameters 2017-01-22 21:21:50 -10:00
Jack Andersen
ecd990e94e Remove VolumeLUT; SoundMacro mixing appears to be linear 2017-01-10 20:54:40 -10:00
Jack Andersen
2836e73812 Add some reserve() calls 2016-12-29 20:36:17 -10:00
Jack Andersen
df167556fb Emitter API tweak 2016-12-28 19:52:28 -10:00
Phillip Stephens
72d0df7d46 Silence double->float conversion warning 2016-12-21 10:42:32 -08:00
Jack Andersen
1dfdf4c392 Update amuse-boo interface 2016-12-13 15:09:48 -10:00
Jack Andersen
9cf96ad6f9 Windows fixes 2016-12-10 15:52:42 -10:00
Jack Andersen
eb948dfd63 Add bounds checking to SoundMacro execution loop 2016-12-07 18:54:45 -10:00
c886bfd7d2 FreeBSD fixes 2016-10-27 15:48:12 -08:00
Jack Andersen
3fd3f3edc5 Construct sequencer for playing back SFX groups 2016-10-08 15:39:04 -10:00
Jack Andersen
7cb7ed73ea Remove unnecessary and RVO-detrimental moves 2016-10-02 18:38:08 -10:00
Jack Andersen
2521f37408 Ensure LZO linked on OS X 2016-09-10 19:49:51 -10:00
Jack Andersen
bfe6668d0c Windows fixes 2016-09-10 15:25:32 -10:00
Jack Andersen
38f24ce3e4 Minor literal value adjustment 2016-09-05 19:50:42 -10:00
Jack Andersen
218fad7541 less redundant way of handling little-endian shorts 2016-09-04 20:56:01 -10:00
af68ee61e1 Remove debug print 2016-09-02 13:05:58 -07:00
b40b2c031a Better temp file handling 2016-09-02 13:00:56 -07:00
aa32ff7e84 Add LZO support for MP2 audio groups 2016-09-02 12:52:17 -07:00
Jack Andersen
28cac7ff83 Update .clang-format 2016-08-21 14:09:24 -10:00
Jack Andersen
055e73183a Add standalone bootstrap script 2016-07-18 13:18:15 -10:00
Jack Andersen
a048605011 Support for loading revised Factor5 N64 ROMs 2016-07-18 12:38:28 -10:00
Jack Andersen
260ec5bb93 Add standalone bootstrap script 2016-07-18 07:52:17 -10:00
Jack Andersen
2a2a16fd17 Typing refinements for song events 2016-07-17 11:23:29 -10:00
Jack Andersen
b421412cac Add lookup table for Rogue Squadron SNG Setup mappings 2016-07-16 11:55:13 -10:00
Jack Andersen
5bae40d3c3 Handle additional corner cases for getChanProgram 2016-07-14 09:42:54 -10:00
Jack Andersen
d06a5ebcfa Fix amuserender crash 2016-07-13 20:51:59 -10:00
Jack Andersen
e2581cea8b Better master volume lookup 2016-07-13 20:36:12 -10:00
Jack Andersen
d602fbacd3 Added master volume API for entire engine 2016-07-13 20:16:00 -10:00
Jack Andersen
2dcb9dd1c7 Working Studio implementation 2016-07-13 18:54:46 -10:00
Jack Andersen
d3d5595422 Initial multiple-referencing submix refactor 2016-07-12 17:04:55 -10:00
Jack Andersen
596bc66ce6 Windows build fix 2016-07-07 09:37:50 -10:00
Jack Andersen
3a7b43a63a Mask out high bit on Tempo changes 2016-07-07 09:17:30 -10:00
Jack Andersen
83a2bf0b4e Merge branch 'master' of https://github.com/AxioDL/amuse 2016-07-06 18:21:49 -10:00
Jack Andersen
695fc10b8f Setup ID prompt for amuserender 2016-07-06 18:19:40 -10:00
feea7c2ecc Add PaperMario TTYD Song Group descs 2016-07-06 21:10:02 -07:00
Jack Andersen
1be5d6e821 Windows fixes 2016-07-06 11:45:41 -10:00
Jack Andersen
2d31313594 Add amuserender executable 2016-07-06 11:30:46 -10:00
Jack Andersen
52cba61f76 Refactored audio supply dispatch across two passes 2016-07-04 15:08:00 -10:00
103 changed files with 4780 additions and 68783 deletions

30
.clang-format Normal file
View File

@@ -0,0 +1,30 @@
---
IndentWidth: 4
ColumnLimit: 120
UseTab: Never
---
Language: Cpp
DerivePointerAlignment: false
PointerAlignment: Left
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
BreakBeforeBraces: Allman
IndentCaseLabels: false
AllowShortBlocksOnASingleLine: true
AlignOperands: true
AlignTrailingComments: true
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BreakConstructorInitializersBeforeComma: true
BreakStringLiterals: true
AlwaysBreakAfterReturnType: None
AlwaysBreakAfterDefinitionReturnType: None
AllowShortFunctionsOnASingleLine: All
Cpp11BracedListStyle: true
NamespaceIndentation: None
BinPackArguments: true
BinPackParameters: true
SortIncludes: false
AccessModifierOffset: -4
ConstructorInitializerIndentWidth: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true

View File

@@ -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>

View File

@@ -36,15 +36,15 @@
IBOutlet NSTableView* sfxTable; IBOutlet NSTableView* sfxTable;
IBOutlet NSTableView* samplesTable; IBOutlet NSTableView* samplesTable;
IBOutlet NSTextView* creditsView; IBOutlet NSTextView* creditsView;
IBOutlet NSButton* removeDataButton; IBOutlet NSButton* removeDataButton;
IBOutlet NSMenuItem* removeDataMenu; IBOutlet NSMenuItem* removeDataMenu;
AudioGroupFilePresenter* groupFilePresenter; AudioGroupFilePresenter* groupFilePresenter;
SamplesTableController* samplesController; SamplesTableController* samplesController;
SFXTableController* sfxController; SFXTableController* sfxController;
@public @public
std::unique_ptr<boo::IAudioVoiceEngine> booEngine; std::unique_ptr<boo::IAudioVoiceEngine> booEngine;
std::experimental::optional<amuse::BooBackendVoiceAllocator> amuseAllocator; std::experimental::optional<amuse::BooBackendVoiceAllocator> amuseAllocator;

View File

@@ -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];
} }

View File

@@ -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>

View File

@@ -30,24 +30,28 @@ struct AudioGroupDataCollection
NSURL* m_meta; NSURL* m_meta;
AudioGroupDataToken* m_token; AudioGroupDataToken* m_token;
std::vector<uint8_t> m_projData; std::vector<uint8_t> m_projData;
std::vector<uint8_t> m_poolData; std::vector<uint8_t> m_poolData;
std::vector<uint8_t> m_sdirData; std::vector<uint8_t> m_sdirData;
std::vector<uint8_t> m_sampData; std::vector<uint8_t> m_sampData;
struct MetaData struct MetaData
{ {
amuse::DataFormat fmt; amuse::DataFormat fmt;
uint32_t absOffs; uint32_t absOffs;
uint32_t active; uint32_t active;
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn) MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {} : fmt(fmtIn), absOffs(absOffsIn), active(activeIn)
{
}
MetaData(athena::io::FileReader& r) MetaData(athena::io::FileReader& r)
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {} : fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little())
{
}
}; };
std::experimental::optional<MetaData> m_metaData; std::experimental::optional<MetaData> m_metaData;
std::experimental::optional<amuse::AudioGroupData> m_loadedData; std::experimental::optional<amuse::AudioGroupData> m_loadedData;
const amuse::AudioGroup* m_loadedGroup; const amuse::AudioGroup* m_loadedGroup;
std::vector<AudioGroupToken*> m_groupTokens; std::vector<AudioGroupToken*> m_groupTokens;
@@ -60,8 +64,11 @@ 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 {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;} bool isDataComplete() const
{
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
}
bool _attemptLoad(AudioGroupFilePresenter* presenter); bool _attemptLoad(AudioGroupFilePresenter* presenter);
bool _indexData(AudioGroupFilePresenter* presenter); bool _indexData(AudioGroupFilePresenter* presenter);
@@ -72,16 +79,16 @@ struct AudioGroupDataCollection
struct AudioGroupCollection struct AudioGroupCollection
{ {
NSURL* m_url; NSURL* m_url;
AudioGroupCollectionToken* m_token; AudioGroupCollectionToken* m_token;
std::map<std::string, std::unique_ptr<AudioGroupDataCollection>> m_groups; std::map<std::string, std::unique_ptr<AudioGroupDataCollection>> m_groups;
std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups; std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups;
AudioGroupCollection(NSURL* url); AudioGroupCollection(NSURL* url);
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);
@@ -119,8 +126,10 @@ struct AudioGroupCollection
NSAttributedString* m_name; NSAttributedString* m_name;
const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>* m_sample; const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>* m_sample;
} }
- (id)initWithName:(NSAttributedString*)name samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry, - (id)
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample; initWithName:(NSAttributedString*)name
samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>*)
sample;
@end @end
@interface AudioGroupToken : NSObject @interface AudioGroupToken : NSObject
@@ -144,12 +153,13 @@ struct AudioGroupCollection
std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections; std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections;
NSOutlineView* m_lastOutlineView; NSOutlineView* m_lastOutlineView;
NSString* m_searchStr; NSString* m_searchStr;
std::vector<AudioGroupSFXToken*> m_sfxTableData; std::vector<AudioGroupSFXToken*> m_sfxTableData;
std::vector<AudioGroupSampleToken*> m_sampleTableData; std::vector<AudioGroupSampleToken*> m_sampleTableData;
} }
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client; - (id)initWithAudioGroupClient:(id<AudioGroupClient>)client;
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection; - (BOOL)addCollectionName:(std::string&&)name
items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
- (void)update; - (void)update;
- (void)resetIterators; - (void)resetIterators;
- (void)setSearchFilter:(NSString*)str; - (void)setSearchFilter:(NSString*)str;

View File

@@ -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];

View File

@@ -27,12 +27,10 @@ namespace amuse
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
{ {
public: public:
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : BooBackendVoiceAllocator(booEngine) {}
: BooBackendVoiceAllocator(booEngine) {}
}; };
void RegisterAudioUnit(); void RegisterAudioUnit();
} }
@interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient> @interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient>
@@ -47,7 +45,7 @@ void RegisterAudioUnit();
AUAudioUnitBusArray* m_outs; AUAudioUnitBusArray* m_outs;
} }
- (nullable id)initWithComponentDescription:(AudioComponentDescription)componentDescription - (nullable id)initWithComponentDescription:(AudioComponentDescription)componentDescription
error:(NSError * __nullable * __nonnull)outError error:(NSError* __nullable* __nonnull)outError
viewController:(AudioUnitViewController* __nonnull)vc; viewController:(AudioUnitViewController* __nonnull)vc;
- (void)requestAudioGroup:(AudioGroupToken* _Nonnull)group; - (void)requestAudioGroup:(AudioGroupToken* _Nonnull)group;
@end @end

View File

@@ -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;
}; };
} }

View File

@@ -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()

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,7 +1,19 @@
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
project(amuse) project(amuse)
if(EXISTS boo) 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)
message(STATUS "Preparing standalone build")
add_subdirectory(boo) add_subdirectory(boo)
add_subdirectory(athena)
include_directories(athena/include)
endif() endif()
set(SOURCES set(SOURCES
@@ -20,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.cpp
lib/Submix.cpp lib/Submix.cpp
lib/EffectBase.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)
@@ -49,6 +59,7 @@ set(HEADERS
include/amuse/SongState.hpp include/amuse/SongState.hpp
include/amuse/Voice.hpp include/amuse/Voice.hpp
include/amuse/Submix.hpp include/amuse/Submix.hpp
include/amuse/Studio.hpp
include/amuse/IBackendSubmix.hpp include/amuse/IBackendSubmix.hpp
include/amuse/IBackendVoice.hpp include/amuse/IBackendVoice.hpp
include/amuse/IBackendVoiceAllocator.hpp include/amuse/IBackendVoiceAllocator.hpp
@@ -56,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
@@ -66,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()
@@ -77,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)
@@ -89,9 +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
add_executable(amuserender driver/amuserender.cpp)
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
View 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
View File

@@ -0,0 +1,5 @@
//
// Created by Jack Andersen on 3/5/18.
//
#include "MainWindow.hpp"

15
Editor/MainWindow.hpp Normal file
View 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
View 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
View File

@@ -0,0 +1,8 @@
//
// Created by Jack Andersen on 3/5/18.
//
int main(int argc, char* argv[])
{
// TODO: Do
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View 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()

View 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

View 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;
}

View 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>

Binary file not shown.

View 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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -6,42 +6,153 @@
namespace amuse namespace amuse
{ {
static const wchar_t *const GMNames[128] = static const wchar_t* const GMNames[128] = {L"Acoustic Grand Piano",
{ L"Bright Acoustic Piano",
L"Acoustic Grand Piano", L"Bright Acoustic Piano", L"Electric Grand Piano", L"Honky-tonk Piano", L"Rhodes Piano", L"Chorused Piano", L"Electric Grand Piano",
L"Harpsichord", L"Clavinet", L"Celesta", L"Glockenspiel", L"Music Box", L"Vibraphone", L"Marimba", L"Xylophone", L"Tubular Bells", L"Dulcimer", L"Honky-tonk Piano",
L"Drawbar Organ", L"Percussive Organ", L"Rock Organ", L"Church Organ", L"Reed Organ", L"Accordion", L"Harmonica", L"Tango Accordion", L"Rhodes Piano",
L"Acoustic Guitar (nylon)", L"Acoustic Guitar (steel)", L"Electric Guitar (jazz)", L"Electric Guitar (clean)", L"Electric Guitar (muted)", L"Chorused Piano",
L"Overdriven Guitar", L"Distortion Guitar", L"Guitar Harmonics", L"Acoustic Bass", L"Electric Bass (finger)", L"Electric Bass (pick)", L"Harpsichord",
L"Fretless Bass", L"Slap Bass 1", L"Slap Bass 2", L"Synth Bass 1", L"Synth Bass 2", L"Violin", L"Viola", L"Cello", L"Contrabass", L"Clavinet",
L"Tremelo Strings", L"Pizzicato Strings", L"Orchestral Harp", L"Timpani", L"String Ensemble 1", L"String Ensemble 2", L"SynthStrings 1", L"Celesta",
L"SynthStrings 2", L"Choir Aahs", L"Voice Oohs", L"Synth Voice", L"Orchestra Hit", L"Trumpet", L"Trombone", L"Tuba", L"Muted Trumpet", L"Glockenspiel",
L"French Horn", L"Brass Section", L"Synth Brass 1", L"Synth Brass 2", L"Soprano Sax", L"Alto Sax", L"Tenor Sax", L"Baritone Sax", L"Music Box",
L"Oboe", L"English Horn", L"Bassoon", L"Clarinet", L"Piccolo", L"Flute", L"Recorder", L"Pan Flute", L"Bottle Blow", L"Shakuhachi", L"Whistle", L"Vibraphone",
L"Ocarina", L"Lead 1 (square)", L"Lead 2 (sawtooth)", L"Lead 3 (calliope lead)", L"Lead 4 (chiff lead)", L"Lead 5 (charang)", L"Marimba",
L"Lead 6 (voice)", L"Lead 7 (fifths)", L"Lead 8 (bass + lead)", L"Pad 1 (new age)", L"Pad 2 (warm)", L"Pad 3 (polysynth)", L"Pad 4 (choir)", L"Xylophone",
L"Pad 5 (bowed)", L"Pad 6 (metallic)", L"Pad 7 (halo)", L"Pad 8 (sweep)", L"FX 1 (rain)", L"FX 2 (soundtrack)", L"FX 3 (crystal)", L"Tubular Bells",
L"FX 4 (atmosphere)", L"FX 5 (brightness)", L"FX 6 (goblins)", L"FX 7 (echoes)", L"FX 8 (sci-fi)", L"Sitar", L"Banjo", L"Shamisen", L"Koto", L"Dulcimer",
L"Kalimba", L"Bagpipe", L"Fiddle", L"Shanai", L"Tinkle Bell", L"Agogo", L"Steel Drums", L"Woodblock", L"Taiko Drum", L"Melodic Tom", L"Drawbar Organ",
L"Synth Drum", L"Reverse Cymbal", L"Guitar Fret Noise", L"Breath Noise", L"Seashore", L"Bird Tweet", L"Telephone Ring", L"Helicopter", L"Percussive Organ",
L"Applause", L"Gunshot" L"Rock Organ",
}; L"Church Organ",
L"Reed Organ",
L"Accordion",
L"Harmonica",
L"Tango Accordion",
L"Acoustic Guitar (nylon)",
L"Acoustic Guitar (steel)",
L"Electric Guitar (jazz)",
L"Electric Guitar (clean)",
L"Electric Guitar (muted)",
L"Overdriven Guitar",
L"Distortion Guitar",
L"Guitar Harmonics",
L"Acoustic Bass",
L"Electric Bass (finger)",
L"Electric Bass (pick)",
L"Fretless Bass",
L"Slap Bass 1",
L"Slap Bass 2",
L"Synth Bass 1",
L"Synth Bass 2",
L"Violin",
L"Viola",
L"Cello",
L"Contrabass",
L"Tremelo Strings",
L"Pizzicato Strings",
L"Orchestral Harp",
L"Timpani",
L"String Ensemble 1",
L"String Ensemble 2",
L"SynthStrings 1",
L"SynthStrings 2",
L"Choir Aahs",
L"Voice Oohs",
L"Synth Voice",
L"Orchestra Hit",
L"Trumpet",
L"Trombone",
L"Tuba",
L"Muted Trumpet",
L"French Horn",
L"Brass Section",
L"Synth Brass 1",
L"Synth Brass 2",
L"Soprano Sax",
L"Alto Sax",
L"Tenor Sax",
L"Baritone Sax",
L"Oboe",
L"English Horn",
L"Bassoon",
L"Clarinet",
L"Piccolo",
L"Flute",
L"Recorder",
L"Pan Flute",
L"Bottle Blow",
L"Shakuhachi",
L"Whistle",
L"Ocarina",
L"Lead 1 (square)",
L"Lead 2 (sawtooth)",
L"Lead 3 (calliope lead)",
L"Lead 4 (chiff lead)",
L"Lead 5 (charang)",
L"Lead 6 (voice)",
L"Lead 7 (fifths)",
L"Lead 8 (bass + lead)",
L"Pad 1 (new age)",
L"Pad 2 (warm)",
L"Pad 3 (polysynth)",
L"Pad 4 (choir)",
L"Pad 5 (bowed)",
L"Pad 6 (metallic)",
L"Pad 7 (halo)",
L"Pad 8 (sweep)",
L"FX 1 (rain)",
L"FX 2 (soundtrack)",
L"FX 3 (crystal)",
L"FX 4 (atmosphere)",
L"FX 5 (brightness)",
L"FX 6 (goblins)",
L"FX 7 (echoes)",
L"FX 8 (sci-fi)",
L"Sitar",
L"Banjo",
L"Shamisen",
L"Koto",
L"Kalimba",
L"Bagpipe",
L"Fiddle",
L"Shanai",
L"Tinkle Bell",
L"Agogo",
L"Steel Drums",
L"Woodblock",
L"Taiko Drum",
L"Melodic Tom",
L"Synth Drum",
L"Reverse Cymbal",
L"Guitar Fret Noise",
L"Breath Noise",
L"Seashore",
L"Bird Tweet",
L"Telephone Ring",
L"Helicopter",
L"Applause",
L"Gunshot"};
static const wchar_t *const GMPercNames[128] = static const wchar_t* const GMPercNames[128] = {
{ nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, L"Acoustic Bass Drum", L"Bass Drum 1", L"Side Stick", nullptr, nullptr, nullptr, nullptr, nullptr,
L"Acoustic Snare", L"Hand Clap", L"Electric Snare", L"Low Floor Tom", L"Closed Hi-Hat", nullptr, nullptr, nullptr, nullptr, nullptr,
L"High Floor Tom", L"Pedal Hi-Hat", L"Low Tom", L"Open Hi-Hat", L"Low-Mid Tom", L"Hi-Mid Tom", nullptr, nullptr, nullptr, nullptr, L"Acoustic Bass Drum",
L"Crash Cymbal 1", L"High Tom", L"Ride Cymbal 1", L"Chinese Cymbal", L"Ride Bell", L"Tambourine", L"Bass Drum 1", L"Side Stick", L"Acoustic Snare", L"Hand Clap", L"Electric Snare",
L"Splash Cymbal", L"Cowbell", L"Crash Cymbal 2", L"Vibraslap", L"Ride Cymbal 2", L"Hi Bongo", L"Low Floor Tom", L"Closed Hi-Hat", L"High Floor Tom", L"Pedal Hi-Hat", L"Low Tom",
L"Low Bongo", L"Mute Hi Conga", L"Open Hi Conga", L"Low Conga", L"High Timbale", L"Low Timbale", L"Open Hi-Hat", L"Low-Mid Tom", L"Hi-Mid Tom", L"Crash Cymbal 1", L"High Tom",
L"High Agogo", L"Low Agogo", L"Cabasa", L"Maracas", L"Short Whistle", L"Long Whistle", L"Short Guiro", L"Ride Cymbal 1", L"Chinese Cymbal", L"Ride Bell", L"Tambourine", L"Splash Cymbal",
L"Long Guiro", L"Claves", L"Hi Wood Block", L"Low Wood Block", L"Mute Cuica", L"Open Cuica", L"Cowbell", L"Crash Cymbal 2", L"Vibraslap", L"Ride Cymbal 2", L"Hi Bongo",
L"Mute Triangle", L"Open Triangle" L"Low Bongo", L"Mute Hi Conga", L"Open Hi Conga", L"Low Conga", L"High Timbale",
}; L"Low Timbale", L"High Agogo", L"Low Agogo", L"Cabasa", L"Maracas",
L"Short Whistle", L"Long Whistle", L"Short Guiro", L"Long Guiro", L"Claves",
L"Hi Wood Block", L"Low Wood Block", L"Mute Cuica", L"Open Cuica", L"Mute Triangle",
L"Open Triangle"};
bool AudioGroupDataCollection::loadProj() bool AudioGroupDataCollection::loadProj()
{ {
@@ -106,10 +217,9 @@ 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)
{ {
} }
bool AudioGroupDataCollection::_attemptLoad() bool AudioGroupDataCollection::_attemptLoad()
@@ -134,28 +244,22 @@ bool AudioGroupDataCollection::_indexData()
{ {
switch (m_metaData->fmt) switch (m_metaData->fmt)
{ {
case amuse::DataFormat::GCN: case amuse::DataFormat::GCN:
default: default:
m_loadedData.emplace(m_projData.data(), m_projData.size(), m_loadedData.emplace(m_projData.data(), m_projData.size(), m_poolData.data(), m_poolData.size(),
m_poolData.data(), m_poolData.size(), m_sdirData.data(), m_sdirData.size(), m_sampData.data(), m_sampData.size(),
m_sdirData.data(), m_sdirData.size(), amuse::GCNDataTag{});
m_sampData.data(), m_sampData.size(), break;
amuse::GCNDataTag{}); case amuse::DataFormat::N64:
break; m_loadedData.emplace(m_projData.data(), m_projData.size(), m_poolData.data(), m_poolData.size(),
case amuse::DataFormat::N64: m_sdirData.data(), m_sdirData.size(), m_sampData.data(), m_sampData.size(),
m_loadedData.emplace(m_projData.data(), m_projData.size(), m_metaData->absOffs, amuse::N64DataTag{});
m_poolData.data(), m_poolData.size(), break;
m_sdirData.data(), m_sdirData.size(), case amuse::DataFormat::PC:
m_sampData.data(), m_sampData.size(), m_loadedData.emplace(m_projData.data(), m_projData.size(), m_poolData.data(), m_poolData.size(),
m_metaData->absOffs, amuse::N64DataTag{}); m_sdirData.data(), m_sdirData.size(), m_sampData.data(), m_sampData.size(),
break; m_metaData->absOffs, amuse::PCDataTag{});
case amuse::DataFormat::PC: break;
m_loadedData.emplace(m_projData.data(), m_projData.size(),
m_poolData.data(), m_poolData.size(),
m_sdirData.data(), m_sdirData.size(),
m_sampData.data(), m_sampData.size(),
m_metaData->absOffs, amuse::PCDataTag{});
break;
} }
return m_loadedData.operator bool(); return m_loadedData.operator bool();
@@ -189,18 +293,15 @@ void AudioGroupDataCollection::addToEngine(amuse::Engine& engine)
} }
} }
void AudioGroupDataCollection::removeFromEngine(amuse::Engine& engine) const void AudioGroupDataCollection::removeFromEngine(amuse::Engine& engine) const { engine.removeAudioGroup(*m_loadedData); }
{
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)
{ {
} }
void AudioGroupCollection::addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection) void AudioGroupCollection::addCollection(
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
{ {
for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection) for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection)
{ {
@@ -210,9 +311,9 @@ void AudioGroupCollection::addCollection(std::vector<std::pair<std::wstring, amu
auto search = m_groups.find(pair.first); auto search = m_groups.find(pair.first);
if (search == m_groups.end()) if (search == m_groups.end())
{ {
search = m_groups.emplace(pair.first, search =
std::make_unique<AudioGroupDataCollection>(collectionPath, m_groups.emplace(pair.first, std::make_unique<AudioGroupDataCollection>(collectionPath, pair.first))
pair.first)).first; .first;
} }
AudioGroupDataCollection& dataCollection = *search->second; AudioGroupDataCollection& dataCollection = *search->second;
@@ -253,9 +354,9 @@ void AudioGroupCollection::update(AudioGroupFilePresenter& presenter)
if (search == m_groups.end()) if (search == m_groups.end())
{ {
search = search =
m_groups.emplace(nameStr, m_groups
std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr, .emplace(nameStr, std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr, nameStr))
nameStr)).first; .first;
search->second->_attemptLoad(); search->second->_attemptLoad();
} }
} }
@@ -284,8 +385,10 @@ void AudioGroupFilePresenter::update()
auto search = theMap.find(nameStr); auto search = theMap.find(nameStr);
if (search == theMap.end()) if (search == theMap.end())
{ {
search = theMap.emplace(nameStr, search = theMap
std::make_unique<AudioGroupCollection>(m_backend.getUserDir() + L'\\' + nameStr, nameStr)).first; .emplace(nameStr, std::make_unique<AudioGroupCollection>(
m_backend.getUserDir() + L'\\' + nameStr, nameStr))
.first;
search->second->update(*this); search->second->update(*this);
} }
} }
@@ -294,11 +397,12 @@ void AudioGroupFilePresenter::update()
FindClose(dir); FindClose(dir);
} }
void AudioGroupFilePresenter::addCollection(const std::wstring& name, void AudioGroupFilePresenter::addCollection(
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 = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second; AudioGroupCollection& insert =
*m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second;
CreateDirectory(insert.m_path.c_str(), nullptr); CreateDirectory(insert.m_path.c_str(), nullptr);
insert.addCollection(std::move(collection)); insert.addCollection(std::move(collection));
@@ -368,7 +472,7 @@ void AudioGroupCollection::populateFiles(VSTEditor& editor, HTREEITEM colHandle,
m_iteratorVec.clear(); m_iteratorVec.clear();
m_iteratorVec.reserve(m_groups.size()); m_iteratorVec.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)
{ {
ins.item.pszText = LPWSTR(it->first.c_str()); ins.item.pszText = LPWSTR(it->first.c_str());
ins.item.lParam = LPARAM(0x80000000 | (parentIdx << 16) | m_iteratorVec.size()); ins.item.lParam = LPARAM(0x80000000 | (parentIdx << 16) | m_iteratorVec.size());
@@ -389,7 +493,7 @@ void AudioGroupFilePresenter::populateCollectionColumn(VSTEditor& editor)
m_iteratorVec.clear(); m_iteratorVec.clear();
m_iteratorVec.reserve(m_audioGroupCollections.size()); m_iteratorVec.reserve(m_audioGroupCollections.size());
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it) for (auto it = m_audioGroupCollections.begin(); it != m_audioGroupCollections.end(); ++it)
{ {
ins.item.cChildren = it->second->m_groups.size() ? 1 : 0; ins.item.cChildren = it->second->m_groups.size() ? 1 : 0;
ins.item.pszText = LPWSTR(it->first.c_str()); ins.item.pszText = LPWSTR(it->first.c_str());
@@ -453,7 +557,8 @@ void AudioGroupFilePresenter::populatePageColumn(VSTEditor& editor, int collecti
for (auto& pair : sortPages) for (auto& pair : sortPages)
{ {
wchar_t name[256]; wchar_t name[256];
wnsprintf(name, 256, L"%d (%s)", pair.first, GMNames[pair.first] ? GMNames[pair.first] : L"???"); wnsprintf(name, 256, L"%d (%s)", pair.first,
GMNames[pair.first] ? GMNames[pair.first] : L"???");
item.pszText = name; item.pszText = name;
item.iItem = idx++; item.iItem = idx++;
item.lParam = pair.first; item.lParam = pair.first;
@@ -467,7 +572,8 @@ void AudioGroupFilePresenter::populatePageColumn(VSTEditor& editor, int collecti
for (auto& pair : sortPages) for (auto& pair : sortPages)
{ {
wchar_t name[256]; wchar_t name[256];
wnsprintf(name, 256, L"%d (%s)", pair.first, GMPercNames[pair.first] ? GMPercNames[pair.first] : L"???"); wnsprintf(name, 256, L"%d (%s)", pair.first,
GMPercNames[pair.first] ? GMPercNames[pair.first] : L"???");
item.pszText = name; item.pszText = name;
item.iItem = idx++; item.iItem = idx++;
item.lParam = 0x80000000 | pair.first; item.lParam = 0x80000000 | pair.first;
@@ -478,5 +584,4 @@ void AudioGroupFilePresenter::populatePageColumn(VSTEditor& editor, int collecti
} }
} }
} }
} }

View File

@@ -33,9 +33,13 @@ struct AudioGroupDataCollection
uint32_t absOffs; uint32_t absOffs;
uint32_t active; uint32_t active;
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn) MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {} : fmt(fmtIn), absOffs(absOffsIn), active(activeIn)
{
}
MetaData(athena::io::FileReader& r) MetaData(athena::io::FileReader& r)
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {} : fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little())
{
}
}; };
std::experimental::optional<MetaData> m_metaData; std::experimental::optional<MetaData> m_metaData;
@@ -57,8 +61,11 @@ 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 {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;} bool isDataComplete() const
{
return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;
}
bool _attemptLoad(); bool _attemptLoad();
bool _indexData(); bool _indexData();
@@ -75,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);
@@ -84,24 +91,26 @@ struct AudioGroupCollection
class AudioGroupFilePresenter class AudioGroupFilePresenter
{ {
friend class VSTBackend; friend class VSTBackend;
public: public:
using CollectionIterator = std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>::iterator; using CollectionIterator = std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>::iterator;
private: private:
VSTBackend& m_backend; VSTBackend& m_backend;
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections; std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
std::vector<CollectionIterator> m_iteratorVec; std::vector<CollectionIterator> m_iteratorVec;
public: public:
AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {} AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {}
void update(); void update();
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; }
}; };
} }
#endif // __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__ #endif // __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__

View File

@@ -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()

View File

@@ -1,10 +1,10 @@
#include "FileOpenDialog.hpp" #include "FileOpenDialog.hpp"
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> // For common windows data types and function headers #include <windows.h> // For common windows data types and function headers
#define STRICT_TYPED_ITEMIDS #define STRICT_TYPED_ITEMIDS
#include <objbase.h> // For COM headers #include <objbase.h> // For COM headers
#include <shobjidl.h> // for IFileDialogEvents and IFileDialogControlEvents #include <shobjidl.h> // for IFileDialogEvents and IFileDialogControlEvents
#include <shlwapi.h> #include <shlwapi.h>
#include <knownfolders.h> // for KnownFolder APIs/datatypes/function headers #include <knownfolders.h> // for KnownFolder APIs/datatypes/function headers
#include <propvarutil.h> // for PROPVAR-related functions #include <propvarutil.h> // for PROPVAR-related functions
@@ -15,26 +15,25 @@
#include <new> #include <new>
// Controls // Controls
#define CONTROL_GROUP 2000 #define CONTROL_GROUP 2000
#define CONTROL_RADIOBUTTONLIST 2 #define CONTROL_RADIOBUTTONLIST 2
#define CONTROL_RADIOBUTTON1 1 #define CONTROL_RADIOBUTTON1 1
#define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same IDas CONTROL_RADIOBUTTONLIST, #define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same IDas CONTROL_RADIOBUTTONLIST,
// because it is a child control under CONTROL_RADIOBUTTONLIST // because it is a child control under CONTROL_RADIOBUTTONLIST
// IDs for the Task Dialog Buttons // IDs for the Task Dialog Buttons
#define IDC_BASICFILEOPEN 100 #define IDC_BASICFILEOPEN 100
#define IDC_ADDITEMSTOCUSTOMPLACES 101 #define IDC_ADDITEMSTOCUSTOMPLACES 101
#define IDC_ADDCUSTOMCONTROLS 102 #define IDC_ADDCUSTOMCONTROLS 102
#define IDC_SETDEFAULTVALUESFORPROPERTIES 103 #define IDC_SETDEFAULTVALUESFORPROPERTIES 103
#define IDC_WRITEPROPERTIESUSINGHANDLERS 104 #define IDC_WRITEPROPERTIESUSINGHANDLERS 104
#define IDC_WRITEPROPERTIESWITHOUTUSINGHANDLERS 105 #define IDC_WRITEPROPERTIESWITHOUTUSINGHANDLERS 105
HWND ghMainWnd = 0; HWND ghMainWnd = 0;
HINSTANCE ghAppInst = 0; HINSTANCE ghAppInst = 0;
RECT winRect; RECT winRect;
class CDialogEventHandler : public IFileDialogEvents, class CDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents
public IFileDialogControlEvents
{ {
public: public:
// IUnknown methods // IUnknown methods
@@ -43,15 +42,12 @@ public:
static const QITAB qit[] = { static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents), QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents), QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 }, {0},
}; };
return QISearch(this, qit, riid, ppv); return QISearch(this, qit, riid, ppv);
} }
IFACEMETHODIMP_(ULONG) AddRef() IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&_cRef); }
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release() IFACEMETHODIMP_(ULONG) Release()
{ {
@@ -62,106 +58,107 @@ public:
} }
// IFileDialogEvents methods // IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; }; IFACEMETHODIMP OnFileOk(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; }; IFACEMETHODIMP OnFolderChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; }; IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; }; IFACEMETHODIMP OnHelp(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; }; IFACEMETHODIMP OnSelectionChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; }; IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) { return S_OK; };
IFACEMETHODIMP OnTypeChange(IFileDialog *pfd); IFACEMETHODIMP OnTypeChange(IFileDialog* pfd);
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; }; IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) { return S_OK; };
// IFileDialogControlEvents methods // IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem); IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* pfdc, DWORD dwIDCtl, DWORD dwIDItem);
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; }; IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize*, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; }; IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize*, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; }; IFACEMETHODIMP OnControlActivating(IFileDialogCustomize*, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1){};
CDialogEventHandler() : _cRef(1) { };
private: private:
~CDialogEventHandler() { }; ~CDialogEventHandler(){};
long _cRef; long _cRef;
}; };
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv); HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void** ppv);
std::wstring openDB() std::wstring openDB()
{ {
std::wstring ret; std::wstring ret;
CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
//Cocreate the file open dialog object // Cocreate the file open dialog object
IFileDialog *pfd = NULL; IFileDialog* pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd)); HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Stuff needed for later // Stuff needed for later
const COMDLG_FILTERSPEC rgFExt[] = {{L"Audio Group Archive (*.*)", L"*.*"}}; const COMDLG_FILTERSPEC rgFExt[] = {{L"Audio Group Archive (*.*)", L"*.*"}};
//Create event handling // Create event handling
IFileDialogEvents *pfde = NULL; IFileDialogEvents* pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde)); hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if(SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Hook the event handler // Hook the event handler
DWORD dwCookie; DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie); hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Set options for the dialog // Set options for the dialog
DWORD dwFlags; DWORD dwFlags;
//Get options first so we do not override // Get options first so we do not override
hr = pfd->GetOptions(&dwFlags); hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Get shell items only // Get shell items only
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM); hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Types of files to display (not default) // Types of files to display (not default)
hr = pfd->SetFileTypes(ARRAYSIZE(rgFExt), rgFExt); hr = pfd->SetFileTypes(ARRAYSIZE(rgFExt), rgFExt);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Set default file type to display // Set default file type to display
//hr = pfd->SetDefaultExtension(L"sqlite"); // hr = pfd->SetDefaultExtension(L"sqlite");
//if (SUCCEEDED(hr)) // if (SUCCEEDED(hr))
//{ //{
//Show dialog // Show dialog
hr = pfd->Show(NULL); hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Get the result once the user clicks on open
IShellItem* result;
hr = pfd->GetResult(&result);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Get the result once the user clicks on open // Print out the file name
IShellItem *result; PWSTR fName = NULL;
hr = pfd->GetResult(&result); hr = result->GetDisplayName(SIGDN_FILESYSPATH, &fName);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
//Print out the file name ret.assign(fName);
PWSTR fName = NULL; CoTaskMemFree(fName);
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &fName);
if (SUCCEEDED(hr))
{
ret.assign(fName);
CoTaskMemFree(fName);
}
result->Release();
} }
result->Release();
} }
}
//} //}
} }
} }
@@ -178,11 +175,10 @@ std::wstring openDB()
return ret; return ret;
} }
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void** ppv)
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
{ {
*ppv = NULL; *ppv = NULL;
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler(); CDialogEventHandler* pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY; HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@@ -192,19 +188,17 @@ HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
return hr; return hr;
} }
HRESULT CDialogEventHandler::OnTypeChange(IFileDialog *pfd) HRESULT CDialogEventHandler::OnTypeChange(IFileDialog* pfd)
{ {
IFileSaveDialog *pfsd; IFileSaveDialog* pfsd;
HRESULT hr = pfd->QueryInterface(&pfsd); HRESULT hr = pfd->QueryInterface(&pfsd);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
UINT uIndex; UINT uIndex;
hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
IPropertyDescriptionList *pdl = NULL; IPropertyDescriptionList* pdl = NULL;
} }
pfsd->Release(); pfsd->Release();
} }
@@ -214,9 +208,9 @@ HRESULT CDialogEventHandler::OnTypeChange(IFileDialog *pfd)
// IFileDialogControlEvents // IFileDialogControlEvents
// This method gets called when an dialog control item selection happens (radio-button selection. etc). // This method gets called when an dialog control item selection happens (radio-button selection. etc).
// For sample sake, let's react to this event by changing the dialog title. // For sample sake, let's react to this event by changing the dialog title.
HRESULT CDialogEventHandler::OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem) HRESULT CDialogEventHandler::OnItemSelected(IFileDialogCustomize* pfdc, DWORD dwIDCtl, DWORD dwIDItem)
{ {
IFileDialog *pfd = NULL; IFileDialog* pfd = NULL;
HRESULT hr = pfdc->QueryInterface(&pfd); HRESULT hr = pfdc->QueryInterface(&pfd);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {

View File

@@ -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
@@ -13,27 +13,17 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
size_t m_renderFrames = 0; size_t m_renderFrames = 0;
size_t m_curBufFrame = 0; size_t m_curBufFrame = 0;
boo::AudioChannelSet _getAvailableSet() boo::AudioChannelSet _getAvailableSet() { return boo::AudioChannelSet::Stereo; }
{
return boo::AudioChannelSet::Stereo;
}
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const { return {}; }
{
return {};
}
boo::ReceiveFunctor* m_midiReceiver = nullptr; boo::ReceiveFunctor* m_midiReceiver = nullptr;
struct MIDIIn : public boo::IMIDIIn struct MIDIIn : public boo::IMIDIIn
{ {
MIDIIn(bool virt, boo::ReceiveFunctor&& receiver) MIDIIn(bool virt, boo::ReceiveFunctor&& receiver) : IMIDIIn(virt, std::move(receiver)) {}
: IMIDIIn(virt, std::move(receiver)) {}
std::string description() const std::string description() const { return "VST MIDI"; }
{
return "VST MIDI";
}
}; };
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver) std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
@@ -43,32 +33,17 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut() std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut() { return {}; }
{
return {};
}
std::unique_ptr<boo::IMIDIInOut> newVirtualMIDIInOut(boo::ReceiveFunctor&& receiver) std::unique_ptr<boo::IMIDIInOut> newVirtualMIDIInOut(boo::ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<boo::IMIDIIn> newRealMIDIIn(const char* name, boo::ReceiveFunctor&& receiver) std::unique_ptr<boo::IMIDIIn> newRealMIDIIn(const char* name, boo::ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<boo::IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<boo::IMIDIOut> newRealMIDIOut(const char* name) { return {}; }
{
return {};
}
std::unique_ptr<boo::IMIDIInOut> newRealMIDIInOut(const char* name, boo::ReceiveFunctor&& receiver) std::unique_ptr<boo::IMIDIInOut> newRealMIDIInOut(const char* name, boo::ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
bool useMIDILock() const {return false;} bool useMIDILock() const { return false; }
VSTVoiceEngine() VSTVoiceEngine()
{ {
@@ -112,7 +87,7 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
void pumpAndMixVoices() void pumpAndMixVoices()
{ {
for (size_t f=0 ; f<m_renderFrames ;) for (size_t f = 0; f < m_renderFrames;)
{ {
if (m_curBufFrame == m_5msFrames) if (m_curBufFrame == m_5msFrames)
{ {
@@ -123,11 +98,11 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
size_t remRenderFrames = std::min(m_renderFrames - f, m_5msFrames - m_curBufFrame); size_t remRenderFrames = std::min(m_renderFrames - f, m_5msFrames - m_curBufFrame);
if (remRenderFrames) if (remRenderFrames)
{ {
for (size_t i=0 ; i<2 ; ++i) for (size_t i = 0; i < 2; ++i)
{ {
float* bufOut = m_outputData[i]; float* bufOut = m_outputData[i];
for (size_t lf=0 ; lf<remRenderFrames ; ++lf) for (size_t lf = 0; lf < remRenderFrames; ++lf)
bufOut[f+lf] = m_interleavedBuf[(m_curBufFrame+lf)*2+i]; bufOut[f + lf] = m_interleavedBuf[(m_curBufFrame + lf) * 2 + i];
} }
m_curBufFrame += remRenderFrames; m_curBufFrame += remRenderFrames;
f += remRenderFrames; f += remRenderFrames;
@@ -135,18 +110,17 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
} }
} }
double getCurrentSampleRate() const {return m_mixInfo.m_sampleRate;} double getCurrentSampleRate() const { return m_mixInfo.m_sampleRate; }
}; };
namespace amuse namespace amuse
{ {
#define kBackendID CCONST ('a','m','u','s') #define kBackendID CCONST('a', 'm', 'u', 's')
static logvisor::Module Log("amuse::AudioUnitBackend"); static logvisor::Module Log("amuse::AudioUnitBackend");
VSTBackend::VSTBackend(audioMasterCallback cb) VSTBackend::VSTBackend(audioMasterCallback cb) : AudioEffectX(cb, 0, 0), m_filePresenter(*this), m_editor(*this)
: AudioEffectX(cb, 0, 0), m_filePresenter(*this), m_editor(*this)
{ {
isSynth(); isSynth();
setUniqueID(kBackendID); setUniqueID(kBackendID);
@@ -170,15 +144,9 @@ VSTBackend::VSTBackend(audioMasterCallback cb)
m_filePresenter.update(); m_filePresenter.update();
} }
VSTBackend::~VSTBackend() VSTBackend::~VSTBackend() { editor = nullptr; }
{
editor = nullptr;
}
AEffEditor* VSTBackend::getEditor() AEffEditor* VSTBackend::getEditor() { return &m_editor; }
{
return &m_editor;
}
VstInt32 VSTBackend::processEvents(VstEvents* events) VstInt32 VSTBackend::processEvents(VstEvents* events)
{ {
@@ -197,7 +165,7 @@ VstInt32 VSTBackend::processEvents(VstEvents* events)
if (engine.m_midiReceiver) if (engine.m_midiReceiver)
{ {
for (VstInt32 i=0 ; i<events->numEvents ; ++i) for (VstInt32 i = 0; i < events->numEvents; ++i)
{ {
VstMidiEvent* evt = reinterpret_cast<VstMidiEvent*>(events->events[i]); VstMidiEvent* evt = reinterpret_cast<VstMidiEvent*>(events->events[i]);
if (evt->type == kVstMidiType) if (evt->type == kVstMidiType)
@@ -207,9 +175,9 @@ VstInt32 VSTBackend::processEvents(VstEvents* events)
evt->midiData[0] &= ~0xf; evt->midiData[0] &= ~0xf;
evt->midiData[0] |= m_routeChannel & 0xf; evt->midiData[0] |= m_routeChannel & 0xf;
} }
(*engine.m_midiReceiver)(std::vector<uint8_t>(std::cbegin(evt->midiData), (*engine.m_midiReceiver)(
std::cbegin(evt->midiData) + evt->byteSize), std::vector<uint8_t>(std::cbegin(evt->midiData), std::cbegin(evt->midiData) + evt->byteSize),
(m_curFrame + evt->deltaFrames) / sampleRate); (m_curFrame + evt->deltaFrames) / sampleRate);
} }
} }
} }
@@ -242,10 +210,7 @@ VstInt32 VSTBackend::canDo(char* text)
return returnCode; return returnCode;
} }
VstPlugCategory VSTBackend::getPlugCategory() VstPlugCategory VSTBackend::getPlugCategory() { return kPlugCategSynth; }
{
return kPlugCategSynth;
}
bool VSTBackend::getEffectName(char* text) bool VSTBackend::getEffectName(char* text)
{ {
@@ -284,10 +249,7 @@ bool VSTBackend::getOutputProperties(VstInt32 index, VstPinProperties* propertie
return returnCode; return returnCode;
} }
VstInt32 VSTBackend::getNumMidiInputChannels() VstInt32 VSTBackend::getNumMidiInputChannels() { return 1; }
{
return 1;
}
void VSTBackend::setSampleRate(float sampleRate) void VSTBackend::setSampleRate(float sampleRate)
{ {
@@ -427,10 +389,6 @@ VstInt32 VSTBackend::setChunk(void* data, VstInt32 byteSize, bool)
return 1; return 1;
} }
} }
AudioEffect* createEffectInstance(audioMasterCallback audioMaster) AudioEffect* createEffectInstance(audioMasterCallback audioMaster) { return new amuse::VSTBackend(audioMaster); }
{
return new amuse::VSTBackend(audioMaster);
}

View File

@@ -21,8 +21,7 @@ class VSTBackend;
class VSTBackendVoiceAllocator : public BooBackendVoiceAllocator class VSTBackendVoiceAllocator : public BooBackendVoiceAllocator
{ {
public: public:
VSTBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) VSTBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : BooBackendVoiceAllocator(booEngine) {}
: BooBackendVoiceAllocator(booEngine) {}
}; };
/** Actual plugin implementation class */ /** Actual plugin implementation class */
@@ -41,6 +40,7 @@ class VSTBackend : public AudioEffectX
int m_routeChannel = -1; int m_routeChannel = -1;
AudioGroupFilePresenter m_filePresenter; AudioGroupFilePresenter m_filePresenter;
VSTEditor m_editor; VSTEditor m_editor;
public: public:
VSTBackend(audioMasterCallback cb); VSTBackend(audioMasterCallback cb);
~VSTBackend(); ~VSTBackend();
@@ -58,9 +58,9 @@ public:
void setSampleRate(float sampleRate); void setSampleRate(float sampleRate);
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);
void setGroup(int groupIdx, bool immediate); void setGroup(int groupIdx, bool immediate);
@@ -72,7 +72,6 @@ public:
VstInt32 getChunk(void** data, bool isPreset); VstInt32 getChunk(void** data, bool isPreset);
VstInt32 setChunk(void* data, VstInt32 byteSize, bool isPreset); VstInt32 setChunk(void* data, VstInt32 byteSize, bool isPreset);
}; };
} }
#endif // __AMUSE_VSTBACKEND_HPP__ #endif // __AMUSE_VSTBACKEND_HPP__

View File

@@ -16,10 +16,7 @@ static HBRUSH gGreyBorderBrush;
namespace amuse namespace amuse
{ {
VSTEditor::VSTEditor(VSTBackend& backend) VSTEditor::VSTEditor(VSTBackend& backend) : AEffEditor(&backend), m_backend(backend) {}
: AEffEditor(&backend), m_backend(backend)
{
}
bool VSTEditor::getRect(ERect** rect) bool VSTEditor::getRect(ERect** rect)
{ {
@@ -27,10 +24,7 @@ bool VSTEditor::getRect(ERect** rect)
return true; return true;
} }
LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd, LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{ {
VSTEditor& editor = *reinterpret_cast<VSTEditor*>(GetWindowLongPtrW(hwnd, 0)); VSTEditor& editor = *reinterpret_cast<VSTEditor*>(GetWindowLongPtrW(hwnd, 0));
switch (uMsg) switch (uMsg)
@@ -101,10 +95,7 @@ LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
} }
} }
LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd, LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{ {
switch (uMsg) switch (uMsg)
{ {
@@ -119,15 +110,12 @@ LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd,
RECT rect; RECT rect;
GetClientRect(hwnd, &rect); GetClientRect(hwnd, &rect);
TRIVERTEX verts[] = TRIVERTEX verts[] = {{rect.left, rect.top, 0x6000, 0x6000, 0x7000, 0xff00},
{ {rect.right, rect.bottom, 0x2000, 0x2000, 0x2800, 0xff00}};
{rect.left, rect.top, 0x6000, 0x6000, 0x7000, 0xff00},
{rect.right, rect.bottom, 0x2000, 0x2000, 0x2800, 0xff00}
};
GRADIENT_RECT grect = {0, 1}; GRADIENT_RECT grect = {0, 1};
GradientFill(dc, verts, 2, &grect, 1, GRADIENT_FILL_RECT_V); GradientFill(dc, verts, 2, &grect, 1, GRADIENT_FILL_RECT_V);
SetTextColor(dc, RGB(255,255,255)); SetTextColor(dc, RGB(255, 255, 255));
SetBkMode(dc, TRANSPARENT); SetBkMode(dc, TRANSPARENT);
SelectObject(dc, GetStockObject(ANSI_VAR_FONT)); SelectObject(dc, GetStockObject(ANSI_VAR_FONT));
rect.left += 6; rect.left += 6;
@@ -160,33 +148,22 @@ bool VSTEditor::open(void* ptr)
{ {
AEffEditor::open(ptr); AEffEditor::open(ptr);
HWND hostView = HWND(ptr); HWND hostView = HWND(ptr);
gGreyBorderBrush = CreateSolidBrush(RGB(100,100,100)); gGreyBorderBrush = CreateSolidBrush(RGB(100, 100, 100));
WNDCLASSW notifyCls = WNDCLASSW notifyCls = {CS_HREDRAW | CS_VREDRAW,
{ WindowProc,
CS_HREDRAW | CS_VREDRAW, 0,
WindowProc, 8,
0, HINSTANCE(hInstance),
8, nullptr,
HINSTANCE(hInstance), nullptr,
nullptr, nullptr,
nullptr, nullptr,
nullptr, L"VSTNotify"};
nullptr,
L"VSTNotify"
};
RegisterClassW(&notifyCls); RegisterClassW(&notifyCls);
m_rootView = CreateWindowW(L"VSTNotify", m_rootView = CreateWindowW(L"VSTNotify", L"", WS_CHILD, 0, 0, m_windowRect.right, m_windowRect.bottom, hostView,
L"", nullptr, HINSTANCE(hInstance), nullptr);
WS_CHILD,
0, 0,
m_windowRect.right,
m_windowRect.bottom,
hostView,
nullptr,
HINSTANCE(hInstance),
nullptr);
SetWindowLongPtrW(m_rootView, 0, LONG_PTR(this)); SetWindowLongPtrW(m_rootView, 0, LONG_PTR(this));
ShowWindow(m_rootView, SW_SHOW); ShowWindow(m_rootView, SW_SHOW);
@@ -203,18 +180,12 @@ bool VSTEditor::open(void* ptr)
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH; column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
column.cx = 199; column.cx = 199;
m_collectionTree = CreateWindowW(WC_TREEVIEW, m_collectionTree =
L"", CreateWindowW(WC_TREEVIEW, L"",
WS_CHILD | WS_CLIPSIBLINGS | TVS_SHOWSELALWAYS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, WS_CHILD | WS_CLIPSIBLINGS | TVS_SHOWSELALWAYS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS,
1, 25, 1, 25, 199, m_windowRect.bottom - m_windowRect.top - 26, m_rootView, nullptr, nullptr, nullptr);
199, TreeView_SetBkColor(m_collectionTree, RGB(64, 64, 64));
m_windowRect.bottom - m_windowRect.top - 26, TreeView_SetTextColor(m_collectionTree, RGB(255, 255, 255));
m_rootView,
nullptr,
nullptr,
nullptr);
TreeView_SetBkColor(m_collectionTree, RGB(64,64,64));
TreeView_SetTextColor(m_collectionTree, RGB(255,255,255));
HTREEITEM rootItemA = TreeView_InsertItem(m_collectionTree, &treeItem); HTREEITEM rootItemA = TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.item.pszText = L"Root B"; treeItem.item.pszText = L"Root B";
HTREEITEM rootItemB = TreeView_InsertItem(m_collectionTree, &treeItem); HTREEITEM rootItemB = TreeView_InsertItem(m_collectionTree, &treeItem);
@@ -231,113 +202,61 @@ bool VSTEditor::open(void* ptr)
TreeView_InsertItem(m_collectionTree, &treeItem); TreeView_InsertItem(m_collectionTree, &treeItem);
ShowWindow(m_collectionTree, SW_SHOW); ShowWindow(m_collectionTree, SW_SHOW);
HWND cHeader = CreateWindowW(WC_HEADER, HWND cHeader = CreateWindowW(WC_HEADER, L"", WS_CHILD, 1, 1, 199, 24, m_rootView, nullptr, nullptr, nullptr);
L"",
WS_CHILD,
1, 1,
199,
24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowLongPtrW(cHeader, GWLP_USERDATA, LONG_PTR(L"Collection")); SetWindowLongPtrW(cHeader, GWLP_USERDATA, LONG_PTR(L"Collection"));
OriginalListViewProc = WNDPROC(SetWindowLongPtr(cHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc))); OriginalListViewProc = WNDPROC(SetWindowLongPtr(cHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
ShowWindow(cHeader, SW_SHOW); ShowWindow(cHeader, SW_SHOW);
HWND gHeader = CreateWindowW(WC_HEADER, HWND gHeader = CreateWindowW(WC_HEADER, L"", WS_CHILD, 201, 1, 199, 24, m_rootView, nullptr, nullptr, nullptr);
L"",
WS_CHILD,
201, 1,
199,
24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowLongPtrW(gHeader, GWLP_USERDATA, LONG_PTR(L"Group")); SetWindowLongPtrW(gHeader, GWLP_USERDATA, LONG_PTR(L"Group"));
OriginalListViewProc = WNDPROC(SetWindowLongPtr(gHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc))); OriginalListViewProc = WNDPROC(SetWindowLongPtr(gHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
ShowWindow(gHeader, SW_SHOW); ShowWindow(gHeader, SW_SHOW);
HWND pHeader = CreateWindowW(WC_HEADER, HWND pHeader = CreateWindowW(WC_HEADER, L"", WS_CHILD, 401, 1, 198, 24, m_rootView, nullptr, nullptr, nullptr);
L"",
WS_CHILD,
401, 1,
198,
24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowLongPtrW(pHeader, GWLP_USERDATA, LONG_PTR(L"Page")); SetWindowLongPtrW(pHeader, GWLP_USERDATA, LONG_PTR(L"Page"));
OriginalListViewProc = WNDPROC(SetWindowLongPtr(pHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc))); OriginalListViewProc = WNDPROC(SetWindowLongPtr(pHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
ShowWindow(pHeader, SW_SHOW); ShowWindow(pHeader, SW_SHOW);
m_collectionAdd = CreateWindowW(WC_BUTTON, m_collectionAdd =
L"+", CreateWindowW(WC_BUTTON, L"+", WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON, 1,
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, m_rootView, nullptr, nullptr, nullptr);
1, m_windowRect.bottom - m_windowRect.top - 25,
25, 24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowFont(m_collectionAdd, GetStockObject(ANSI_FIXED_FONT), FALSE); SetWindowFont(m_collectionAdd, GetStockObject(ANSI_FIXED_FONT), FALSE);
Button_Enable(m_collectionAdd, TRUE); Button_Enable(m_collectionAdd, TRUE);
SetWindowPos(m_collectionAdd, HWND_TOP, 1, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, SWP_SHOWWINDOW); SetWindowPos(m_collectionAdd, HWND_TOP, 1, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, SWP_SHOWWINDOW);
m_collectionRemove = CreateWindowW(WC_BUTTON, m_collectionRemove =
L"-", CreateWindowW(WC_BUTTON, L"-", WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON, 26,
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, m_rootView, nullptr, nullptr, nullptr);
26, m_windowRect.bottom - m_windowRect.top - 25,
25, 24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE); SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE);
Button_Enable(m_collectionRemove, FALSE); Button_Enable(m_collectionRemove, FALSE);
SetWindowPos(m_collectionRemove, HWND_TOP, 26, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, SWP_SHOWWINDOW); SetWindowPos(m_collectionRemove, HWND_TOP, 26, m_windowRect.bottom - m_windowRect.top - 25, 25, 24, SWP_SHOWWINDOW);
m_groupListView =
m_groupListView = CreateWindowW(WC_LISTVIEW, CreateWindowW(WC_LISTVIEW, L"",
L"", WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER, 201, 25, 199, m_windowRect.bottom - m_windowRect.top - 26, m_rootView, nullptr, nullptr, nullptr);
201, 25,
199,
m_windowRect.bottom - m_windowRect.top - 26,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Group"; column.pszText = L"Group";
HWND header = ListView_GetHeader(m_groupListView); HWND header = ListView_GetHeader(m_groupListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText)); SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)); SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_groupListView, RGB(64,64,64)); ListView_SetBkColor(m_groupListView, RGB(64, 64, 64));
ListView_SetTextBkColor(m_groupListView, CLR_NONE); ListView_SetTextBkColor(m_groupListView, CLR_NONE);
ListView_SetTextColor(m_groupListView, RGB(255,255,255)); ListView_SetTextColor(m_groupListView, RGB(255, 255, 255));
ListView_InsertColumn(m_groupListView, 0, &column); ListView_InsertColumn(m_groupListView, 0, &column);
ShowWindow(m_groupListView, SW_SHOW); ShowWindow(m_groupListView, SW_SHOW);
m_pageListView = CreateWindowW(WC_LISTVIEW, m_pageListView =
L"", CreateWindowW(WC_LISTVIEW, L"",
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER, WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER,
401, 25, 401, 25, 198, m_windowRect.bottom - m_windowRect.top - 26, m_rootView, nullptr, nullptr, nullptr);
198,
m_windowRect.bottom - m_windowRect.top - 26,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Page"; column.pszText = L"Page";
column.cx = 198 - GetSystemMetrics(SM_CXVSCROLL); column.cx = 198 - GetSystemMetrics(SM_CXVSCROLL);
header = ListView_GetHeader(m_pageListView); header = ListView_GetHeader(m_pageListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText)); SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)); SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_pageListView, RGB(64,64,64)); ListView_SetBkColor(m_pageListView, RGB(64, 64, 64));
ListView_SetTextBkColor(m_pageListView, CLR_NONE); ListView_SetTextBkColor(m_pageListView, CLR_NONE);
ListView_SetTextColor(m_pageListView, RGB(255,255,255)); ListView_SetTextColor(m_pageListView, RGB(255, 255, 255));
ListView_InsertColumn(m_pageListView, 0, &column); ListView_InsertColumn(m_pageListView, 0, &column);
ShowWindow(m_pageListView, SW_SHOW); ShowWindow(m_pageListView, SW_SHOW);
@@ -468,14 +387,7 @@ void VSTEditor::reselectPage()
} }
} }
void VSTEditor::selectNormalPage(int idx) void VSTEditor::selectNormalPage(int idx) { m_backend.setNormalProgram(idx); }
{
m_backend.setNormalProgram(idx);
}
void VSTEditor::selectDrumPage(int idx)
{
m_backend.setDrumProgram(idx);
}
void VSTEditor::selectDrumPage(int idx) { m_backend.setDrumProgram(idx); }
} }

View File

@@ -36,20 +36,11 @@ class VSTEditor : public AEffEditor
HTREEITEM m_deferredCollectionSel = 0; HTREEITEM m_deferredCollectionSel = 0;
static LRESULT CALLBACK WindowProc( static LRESULT CALLBACK WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
_In_ HWND hwnd, static LRESULT CALLBACK ColHeaderWindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
static LRESULT CALLBACK ColHeaderWindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
void _reselectColumns(); void _reselectColumns();
public: public:
VSTEditor(VSTBackend& backend); VSTEditor(VSTBackend& backend);
@@ -68,7 +59,6 @@ public:
void selectNormalPage(int idx); void selectNormalPage(int idx);
void selectDrumPage(int idx); void selectDrumPage(int idx);
}; };
} }
#endif // __AMUSE_VSTEDITOR_HPP__ #endif // __AMUSE_VSTEDITOR_HPP__

View File

@@ -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,38 +31,37 @@ 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)
{ {
Log.report(logvisor::Info, _S("Extracting %s"), group.first.c_str()); Log.report(logvisor::Info, _S("Extracting %s"), group.first.c_str());
} }
} }
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;
} }
@@ -74,7 +73,8 @@ static bool ExtractAudioGroup(const amuse::SystemString& inPath, const amuse::Sy
Log.report(logvisor::Info, _S("Extracting %s"), pair.first.c_str()); Log.report(logvisor::Info, _S("Extracting %s"), pair.first.c_str());
int extractedVersion; int extractedVersion;
bool isBig; bool isBig;
std::vector<uint8_t> mid = amuse::SongConverter::SongToMIDI(pair.second.m_data.get(), extractedVersion, isBig); std::vector<uint8_t> mid =
amuse::SongConverter::SongToMIDI(pair.second.m_data.get(), extractedVersion, isBig);
fwrite(mid.data(), 1, mid.size(), fp); fwrite(mid.data(), 1, mid.size(), fp);
fclose(fp); fclose(fp);
} }
@@ -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);
@@ -173,14 +173,12 @@ int main(int argc, const amuse::SystemChar** argv)
const amuse::SystemChar* dot = barePath.c_str() + dotPos; const amuse::SystemChar* dot = barePath.c_str() + dotPos;
if (dotPos != amuse::SystemString::npos) if (dotPos != amuse::SystemString::npos)
{ {
if (!amuse::CompareCaseInsensitive(dot, _S(".mid")) || if (!amuse::CompareCaseInsensitive(dot, _S(".mid")) || !amuse::CompareCaseInsensitive(dot, _S(".midi")))
!amuse::CompareCaseInsensitive(dot, _S(".midi")))
{ {
ReportConvType(type); ReportConvType(type);
good = BuildSNG(barePath, argv[2], 1, true); good = BuildSNG(barePath, argv[2], 1, true);
} }
else if (!amuse::CompareCaseInsensitive(dot, _S(".son")) || else if (!amuse::CompareCaseInsensitive(dot, _S(".son")) || !amuse::CompareCaseInsensitive(dot, _S(".sng")))
!amuse::CompareCaseInsensitive(dot, _S(".sng")))
{ {
good = ExtractSNG(argv[1], argv[2]); good = ExtractSNG(argv[1], argv[2]);
} }

View File

@@ -1,24 +1,18 @@
#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");
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 3, 4))) __attribute__((__format__(__printf__, 3, 4)))
#endif #endif
static inline void SNPrintf(boo::SystemChar* str, size_t maxlen, const boo::SystemChar* format, ...) static inline void
SNPrintf(boo::SystemChar* str, size_t maxlen, const boo::SystemChar* format, ...)
{ {
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@@ -30,70 +24,19 @@ static inline void SNPrintf(boo::SystemChar* str, size_t maxlen, const boo::Syst
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
{ {
AppCallback& m_app; AppCallback& m_app;
bool m_tracking = false; bool m_tracking = false;
public: public:
void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat); void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat);
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);
@@ -110,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;
@@ -142,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;
@@ -151,9 +103,10 @@ struct AppCallback : boo::IApplicationCallback
voxCount = m_seq->getVoiceCount(); voxCount = m_seq->getVoiceCount();
program = m_seq->getChanProgram(m_chanId); program = m_seq->getChanProgram(m_chanId);
} }
printf("\r " printf(
"\r %" PRISize " Setup %d, Chan %d, Prog %d, Octave: %d, Vel: %d, VOL: %d%%\r", voxCount, "\r "
m_setupId, m_chanId, program, m_octave, m_velocity, int(std::rint(m_volume * 100))); "\r %" PRISize " Setup %d, Chan %d, Prog %d, Octave: %d, Vel: %d, VOL: %d%%\r",
voxCount, m_setupId, m_chanId, program, m_octave, m_velocity, int(std::rint(m_volume * 100)));
fflush(stdout); fflush(stdout);
} }
@@ -162,11 +115,11 @@ 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);
m_seq->setVolume(m_volume); m_engine->setVolume(m_volume);
if (m_arrData) if (m_arrData)
m_seq->playSong(m_arrData->m_data.get(), false); m_seq->playSong(m_arrData->m_data.get(), false);
@@ -174,21 +127,22 @@ struct AppCallback : boo::IApplicationCallback
UpdateSongDisplay(); UpdateSongDisplay();
} }
void SongLoop(const amuse::SongGroupIndex& index) void SongLoop(const amuse::SongGroupIndex& index, boo::IAudioVoiceEngine& booEngine)
{ {
printf("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n" printf(
"░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░\n" "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n"
"░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░\n" "░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░\n"
"░░░ ▌W▐█ ▌E▐█ ┃ ▌T▐█ ▌Y▐█ ▌U▐█ ┃ ▌O▐█ ▌P▐█ ░░░\n" "░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░\n"
"░░░ │ │ ┃ │ │ │ ┃ │ │ ░░░\n" "░░░ ▌W▐█ ▌E▐█ ┃ ▌T▐█ ▌Y▐█ ▌U▐█ ┃ ▌O▐█ ▌P▐█ ░░░\n"
"░░░ ASDFGHJKL; ░░░\n" "░░░ ░░░\n"
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n" "░░░ A │ S │ D ┃ F │ G │ H │ J ┃ K │ L │ ; ░░░\n"
"<left/right>: cycle MIDI setup, <up/down>: volume, <space>: PANIC\n" "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n"
"<tab>: sustain pedal, <window-Y>: pitch wheel, <window-X>: mod wheel\n" "<left/right>: cycle MIDI setup, <up/down>: volume, <space>: PANIC\n"
"<Z/X>: octave, <C/V>: velocity, <B/N>: channel, <,/.>: program, <Q>: quit\n"); "<tab>: sustain pedal, <window-Y>: pitch wheel, <window-X>: mod wheel\n"
"<Z/X>: octave, <C/V>: velocity, <B/N>: channel, <,/.>: program, <Q>: quit\n");
std::map<int, const std::array<amuse::SongGroupIndex::MIDISetup, 16>*> sortEntries std::map<int, const std::array<amuse::SongGroupIndex::MIDISetup, 16>*> sortEntries(index.m_midiSetups.cbegin(),
(index.m_midiSetups.cbegin(), index.m_midiSetups.cend()); index.m_midiSetups.cend());
auto setupIt = sortEntries.cbegin(); auto setupIt = sortEntries.cbegin();
if (setupIt != sortEntries.cend()) if (setupIt != sortEntries.cend())
{ {
@@ -250,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;
@@ -279,17 +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;
printf("\r " #if EMITTER_TEST
"\r %c SFX %d, VOL: %d%%\r", playing ? '>' : ' ', printf(
m_sfxId, int(std::rint(m_volume * 100))); "\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(
"\r "
"\r %c SFX %d, VOL: %d%%\r",
playing ? '>' : ' ', m_sfxId, int(std::rint(m_volume * 100)));
#endif
fflush(stdout); fflush(stdout);
} }
@@ -300,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");
std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries m_seq = m_engine->seqPlay(m_groupId, 0, nullptr);
(index.m_sfxEntries.cbegin(), index.m_sfxEntries.cend());
std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries(index.m_sfxEntries.cbegin(),
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)
@@ -351,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();
} }
@@ -363,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)
@@ -410,7 +408,8 @@ struct AppCallback : boo::IApplicationCallback
m_seq->nextChanProgram(m_chanId); m_seq->nextChanProgram(m_chanId);
m_updateDisp = true; m_updateDisp = true;
break; break;
default: break; default:
break;
} }
} }
} }
@@ -429,12 +428,22 @@ 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: break; default:
break;
} }
} }
else if (m_seq && m_chanId != -1) else if (m_seq && m_chanId != -1)
@@ -534,7 +543,8 @@ struct AppCallback : boo::IApplicationCallback
case ':': case ':':
m_seq->keyOn(m_chanId, (m_octave + 1) * 12 + 16, m_velocity); m_seq->keyOn(m_chanId, (m_octave + 1) * 12 + 16, m_velocity);
break; break;
default: break; default:
break;
} }
if (!setPanic) if (!setPanic)
@@ -605,7 +615,8 @@ struct AppCallback : boo::IApplicationCallback
case ':': case ':':
m_seq->keyOff(m_chanId, (m_octave + 1) * 12 + 16, m_velocity); m_seq->keyOff(m_chanId, (m_octave + 1) * 12 + 16, m_velocity);
break; break;
default: break; default:
break;
} }
} }
} }
@@ -613,19 +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( tex = ctx.newRenderTexture(100, 100, boo::TextureClampMode::Repeat, 1, 0);
[&](boo::IGraphicsDataFactory::Context& ctx) -> bool
{
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();
@@ -656,8 +664,12 @@ struct AppCallback : boo::IApplicationCallback
} }
std::list<amuse::AudioGroupProject> m_projs; std::list<amuse::AudioGroupProject> m_projs;
std::map<int, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SongGroupIndex*>> allSongGroups; std::map<int, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
std::map<int, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SFXGroupIndex*>> allSFXGroups; const amuse::SongGroupIndex*>>
allSongGroups;
std::map<int, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
const amuse::SFXGroupIndex*>>
allSFXGroups;
size_t totalGroups = 0; size_t totalGroups = 0;
for (auto& grp : data) for (auto& grp : data)
@@ -667,10 +679,10 @@ struct AppCallback : boo::IApplicationCallback
amuse::AudioGroupProject& proj = m_projs.back(); amuse::AudioGroupProject& proj = m_projs.back();
totalGroups += proj.sfxGroups().size() + proj.songGroups().size(); totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
for (auto it = proj.songGroups().begin() ; it != proj.songGroups().end() ; ++it) for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
allSongGroups[it->first] = std::make_pair(&grp, &it->second); allSongGroups[it->first] = std::make_pair(&grp, &it->second);
for (auto it = proj.sfxGroups().begin() ; it != proj.sfxGroups().end() ; ++it) for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
allSFXGroups[it->first] = std::make_pair(&grp, &it->second); allSFXGroups[it->first] = std::make_pair(&grp, &it->second);
} }
@@ -743,8 +755,8 @@ struct AppCallback : boo::IApplicationCallback
break; break;
} }
} }
amuse::Printf(_S(" %d %s (Group %d, Setup %d)\n"), idx++, amuse::Printf(_S(" %d %s (Group %d, Setup %d)\n"), idx++, pair.first.c_str(), grpId,
pair.first.c_str(), grpId, setupId); setupId);
} }
int userSel = 0; int userSel = 0;
@@ -813,17 +825,15 @@ struct AppCallback : boo::IApplicationCallback
printf("Multiple Audio Groups discovered:\n"); printf("Multiple Audio Groups discovered:\n");
for (const auto& pair : allSFXGroups) for (const auto& pair : allSFXGroups)
{ {
amuse::Printf(_S(" %d %s (SFXGroup) %" PRISize " sfx-entries\n"), amuse::Printf(_S(" %d %s (SFXGroup) %" PRISize " sfx-entries\n"), pair.first,
pair.first, pair.second.first->first.c_str(), pair.second.first->first.c_str(), pair.second.second->m_sfxEntries.size());
pair.second.second->m_sfxEntries.size());
} }
for (const auto& pair : allSongGroups) for (const auto& pair : allSongGroups)
{ {
amuse::Printf(_S(" %d %s (SongGroup) %" PRISize " normal-pages, %" PRISize " drum-pages, %" PRISize " MIDI-setups\n"), amuse::Printf(_S(" %d %s (SongGroup) %" PRISize " normal-pages, %" PRISize
pair.first, pair.second.first->first.c_str(), " drum-pages, %" PRISize " MIDI-setups\n"),
pair.second.second->m_normPages.size(), pair.first, pair.second.first->first.c_str(), pair.second.second->m_normPages.size(),
pair.second.second->m_drumPages.size(), pair.second.second->m_drumPages.size(), pair.second.second->m_midiSetups.size());
pair.second.second->m_midiSetups.size());
} }
int userSel = 0; int userSel = 0;
@@ -900,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);
@@ -913,23 +923,26 @@ 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");
} }
return 0; return 0;
} }
void appQuitting(boo::IApplication*) void appQuitting(boo::IApplication*) { m_running = false; }
{
m_running = false;
}
AppCallback(int argc, const boo::SystemChar** argv) AppCallback(int argc, const boo::SystemChar** argv)
: m_argc(argc), m_argv(argv), m_eventRec(*this), m_events(m_eventRec) {} : m_argc(argc), m_argv(argv), m_eventRec(*this), m_events(m_eventRec)
{
}
}; };
void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
@@ -940,10 +953,7 @@ void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods,
m_app.charKeyDown(charCode); m_app.charKeyDown(charCode);
} }
void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods) void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods) { m_app.charKeyUp(charCode); }
{
m_app.charKeyUp(charCode);
}
void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat)
{ {
@@ -958,30 +968,23 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
case boo::ESpecialKey::Up: case boo::ESpecialKey::Up:
if (m_app.m_volume < 1.f) if (m_app.m_volume < 1.f)
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f); m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f);
if (m_app.m_vox) m_app.m_engine->setVolume(m_app.m_volume);
m_app.m_vox->setVolume(m_app.m_volume);
if (m_app.m_seq)
m_app.m_seq->setVolume(m_app.m_volume);
m_app.m_updateDisp = true; m_app.m_updateDisp = true;
break; break;
case boo::ESpecialKey::Down: case boo::ESpecialKey::Down:
if (m_app.m_volume > 0.f) if (m_app.m_volume > 0.f)
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f); m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f);
if (m_app.m_vox) m_app.m_engine->setVolume(m_app.m_volume);
m_app.m_vox->setVolume(m_app.m_volume);
if (m_app.m_seq)
m_app.m_seq->setVolume(m_app.m_volume);
m_app.m_updateDisp = true; m_app.m_updateDisp = true;
break; break;
case boo::ESpecialKey::Esc: case boo::ESpecialKey::Esc:
m_app.m_breakout = true; m_app.m_breakout = true;
default: break; default:
break;
} }
} }
void EventCallback::specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) void EventCallback::specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) {}
{
}
void EventCallback::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton, boo::EModifierKey) void EventCallback::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton, boo::EModifierKey)
{ {
@@ -1028,32 +1031,30 @@ 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, int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, app,
app, _S("amuseplay"), _S("Amuse Player"), 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];
GetModuleFileNameW(nullptr, selfPath, 1024); GetModuleFileNameW(nullptr, selfPath, 1024);
static const boo::SystemChar* booArgv[32] = {}; static const boo::SystemChar* booArgv[32] = {};
booArgv[0] = selfPath; booArgv[0] = selfPath;
for (int i=0 ; i<argc ; ++i) for (int i = 0; i < argc; ++i)
booArgv[i+1] = argv[i]; booArgv[i + 1] = argv[i];
logvisor::CreateWin32Console(); logvisor::CreateWin32Console();
SetConsoleOutputCP(65001); SetConsoleOutputCP(65001);
return wmain(argc+1, booArgv); return wmain(argc + 1, booArgv);
} }
#endif #endif

505
driver/amuserender.cpp Normal file
View File

@@ -0,0 +1,505 @@
#include "amuse/amuse.hpp"
#include "amuse/BooBackend.hpp"
#include "athena/FileReader.hpp"
#include "boo/boo.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp"
#include "logvisor/logvisor.hpp"
#include "optional.hpp"
#include <cstdio>
#include <cstring>
#include <signal.h>
#include <thread>
#include <map>
#include <set>
#include <vector>
#include <unordered_map>
#include <cstdarg>
static logvisor::Module Log("amuserender");
#if __GNUC__
__attribute__((__format__(__printf__, 3, 4)))
#endif
static inline void
SNPrintf(boo::SystemChar* str, size_t maxlen, const boo::SystemChar* format, ...)
{
va_list va;
va_start(va, format);
#if _WIN32
_vsnwprintf(str, maxlen, format, va);
#else
vsnprintf(str, maxlen, format, va);
#endif
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
/* SIGINT will gracefully break write loop */
static bool g_BreakLoop = false;
static void SIGINTHandler(int sig) { g_BreakLoop = true; }
#if _WIN32
int wmain(int argc, const boo::SystemChar** argv)
#else
int main(int argc, const boo::SystemChar** argv)
#endif
{
logvisor::RegisterConsoleLogger();
std::vector<boo::SystemString> m_args;
m_args.reserve(argc);
double rate = NativeSampleRate;
for (int i = 1; i < argc; ++i)
{
#if _WIN32
if (!wcsncmp(argv[i], L"-r", 2))
{
if (argv[i][2])
rate = wcstod(&argv[i][2], nullptr);
else if (argc > (i + 1))
{
rate = wcstod(argv[i + 1], nullptr);
++i;
}
}
else
m_args.push_back(argv[i]);
#else
if (!strncmp(argv[i], "-r", 2))
{
if (argv[i][2])
rate = strtod(&argv[i][2], nullptr);
else if (argc > (i + 1))
{
rate = strtod(argv[i + 1], nullptr);
++i;
}
}
else
m_args.push_back(argv[i]);
#endif
}
/* Load data */
if (m_args.size() < 1)
{
Log.report(logvisor::Error, "Usage: amuserender <group-file> [<songs-file>] [-r <sample-rate>]");
exit(1);
}
amuse::ContainerRegistry::Type cType = amuse::ContainerRegistry::DetectContainerType(m_args[0].c_str());
if (cType == amuse::ContainerRegistry::Type::Invalid)
{
Log.report(logvisor::Error, "invalid/no data at path argument");
exit(1);
}
Log.report(logvisor::Info, _S("Found '%s' Audio Group data"), amuse::ContainerRegistry::TypeToName(cType));
std::vector<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>> data =
amuse::ContainerRegistry::LoadContainer(m_args[0].c_str());
if (data.empty())
{
Log.report(logvisor::Error, "invalid/no data at path argument");
exit(1);
}
int m_groupId = -1;
int m_setupId = -1;
const amuse::SystemString* m_groupName = nullptr;
const amuse::SystemString* m_songName = nullptr;
amuse::ContainerRegistry::SongData* m_arrData = nullptr;
bool m_sfxGroup = false;
std::list<amuse::AudioGroupProject> m_projs;
std::map<int,
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SongGroupIndex*>>
allSongGroups;
std::map<int,
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SFXGroupIndex*>>
allSFXGroups;
size_t totalGroups = 0;
for (auto& grp : data)
{
/* Load project to assemble group list */
m_projs.push_back(amuse::AudioGroupProject::CreateAudioGroupProject(grp.second));
amuse::AudioGroupProject& proj = m_projs.back();
totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
allSongGroups[it->first] = std::make_pair(&grp, &it->second);
for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
allSFXGroups[it->first] = std::make_pair(&grp, &it->second);
}
/* Attempt loading song */
std::vector<std::pair<amuse::SystemString, amuse::ContainerRegistry::SongData>> songs;
if (m_args.size() > 1)
songs = amuse::ContainerRegistry::LoadSongs(m_args[1].c_str());
else
songs = amuse::ContainerRegistry::LoadSongs(m_args[0].c_str());
if (songs.size())
{
bool play = true;
if (m_args.size() <= 1)
{
bool prompt = true;
while (true)
{
if (prompt)
{
printf("Render Song? (Y/N): ");
prompt = false;
}
char userSel;
if (scanf("%c", &userSel) <= 0 || userSel == '\n')
continue;
userSel = tolower(userSel);
if (userSel == 'n')
play = false;
else if (userSel != 'y')
{
prompt = true;
continue;
}
break;
}
}
if (play)
{
/* Get song selection from user */
if (songs.size() > 1)
{
/* Ask user to specify which song */
printf("Multiple Songs discovered:\n");
int idx = 0;
for (const auto& pair : songs)
{
const amuse::ContainerRegistry::SongData& sngData = pair.second;
int16_t grpId = sngData.m_groupId;
int16_t setupId = sngData.m_setupId;
if (sngData.m_groupId == -1 && sngData.m_setupId != -1)
{
for (const auto& pair : allSongGroups)
{
for (const auto& setup : pair.second.second->m_midiSetups)
{
if (setup.first == sngData.m_setupId)
{
grpId = pair.first;
break;
}
}
if (grpId != -1)
break;
}
}
amuse::Printf(_S(" %d %s (Group %d, Setup %d)\n"), idx++, pair.first.c_str(), grpId, setupId);
}
int userSel = 0;
printf("Enter Song Number: ");
if (scanf("%d", &userSel) <= 0)
{
Log.report(logvisor::Error, "unable to parse prompt");
exit(1);
}
if (userSel < songs.size())
{
m_arrData = &songs[userSel].second;
m_groupId = m_arrData->m_groupId;
m_setupId = m_arrData->m_setupId;
m_songName = &songs[userSel].first;
}
else
{
Log.report(logvisor::Error, "unable to find Song %d", userSel);
exit(1);
}
}
else if (songs.size() == 1)
{
m_arrData = &songs[0].second;
m_groupId = m_arrData->m_groupId;
m_setupId = m_arrData->m_setupId;
m_songName = &songs[0].first;
}
}
}
/* Get group selection via setup search */
if (m_groupId == -1 && m_setupId != -1)
{
for (const auto& pair : allSongGroups)
{
for (const auto& setup : pair.second.second->m_midiSetups)
{
if (setup.first == m_setupId)
{
m_groupId = pair.first;
m_groupName = &pair.second.first->first;
break;
}
}
if (m_groupId != -1)
break;
}
}
/* Get group selection via user */
if (m_groupId != -1)
{
auto songSearch = allSongGroups.find(m_groupId);
auto sfxSearch = allSFXGroups.find(m_groupId);
if (songSearch != allSongGroups.end())
{
m_sfxGroup = false;
m_groupName = &songSearch->second.first->first;
}
else if (sfxSearch != allSFXGroups.end())
{
m_sfxGroup = true;
m_groupName = &sfxSearch->second.first->first;
}
else
{
Log.report(logvisor::Error, "unable to find Group %d", m_groupId);
exit(1);
}
}
else if (totalGroups > 1)
{
/* Ask user to specify which group in project */
printf("Multiple Audio Groups discovered:\n");
for (const auto& pair : allSFXGroups)
{
amuse::Printf(_S(" %d %s (SFXGroup) %" PRISize " sfx-entries\n"), pair.first,
pair.second.first->first.c_str(), pair.second.second->m_sfxEntries.size());
}
for (const auto& pair : allSongGroups)
{
amuse::Printf(_S(" %d %s (SongGroup) %" PRISize " normal-pages, %" PRISize " drum-pages, %" PRISize
" MIDI-setups\n"),
pair.first, pair.second.first->first.c_str(), pair.second.second->m_normPages.size(),
pair.second.second->m_drumPages.size(), pair.second.second->m_midiSetups.size());
}
int userSel = 0;
printf("Enter Group Number: ");
if (scanf("%d", &userSel) <= 0)
{
Log.report(logvisor::Error, "unable to parse prompt");
exit(1);
}
auto songSearch = allSongGroups.find(userSel);
auto sfxSearch = allSFXGroups.find(userSel);
if (songSearch != allSongGroups.end())
{
m_groupId = userSel;
m_groupName = &songSearch->second.first->first;
m_sfxGroup = false;
}
else if (sfxSearch != allSFXGroups.end())
{
m_groupId = userSel;
m_groupName = &sfxSearch->second.first->first;
m_sfxGroup = true;
}
else
{
Log.report(logvisor::Error, "unable to find Group %d", userSel);
exit(1);
}
}
else if (totalGroups == 1)
{
/* Load one and only group */
if (allSongGroups.size())
{
const auto& pair = *allSongGroups.cbegin();
m_groupId = pair.first;
m_groupName = &pair.second.first->first;
m_sfxGroup = false;
}
else
{
const auto& pair = *allSFXGroups.cbegin();
m_groupId = pair.first;
m_groupName = &pair.second.first->first;
m_sfxGroup = true;
}
}
else
{
Log.report(logvisor::Error, "empty project");
exit(1);
}
/* Make final group selection */
amuse::IntrusiveAudioGroupData* selData = nullptr;
const amuse::SongGroupIndex* songIndex = nullptr;
const amuse::SFXGroupIndex* sfxIndex = nullptr;
auto songSearch = allSongGroups.find(m_groupId);
if (songSearch != allSongGroups.end())
{
selData = &songSearch->second.first->second;
songIndex = songSearch->second.second;
std::set<int> sortSetups;
for (auto& pair : songIndex->m_midiSetups)
sortSetups.insert(pair.first);
if (m_setupId == -1)
{
/* Ask user to specify which group in project */
printf("Multiple MIDI Setups:\n");
for (int setup : sortSetups)
printf(" %d\n", setup);
int userSel = 0;
printf("Enter Setup Number: ");
if (scanf("%d", &userSel) <= 0)
{
Log.report(logvisor::Error, "unable to parse prompt");
exit(1);
}
m_setupId = userSel;
}
if (sortSetups.find(m_setupId) == sortSetups.cend())
{
Log.report(logvisor::Error, "unable to find setup %d", m_setupId);
exit(1);
}
}
else
{
auto sfxSearch = allSFXGroups.find(m_groupId);
if (sfxSearch != allSFXGroups.end())
{
selData = &sfxSearch->second.first->second;
sfxIndex = sfxSearch->second.second;
}
}
if (!selData)
{
Log.report(logvisor::Error, "unable to select audio group data");
exit(1);
}
if (m_sfxGroup)
{
Log.report(logvisor::Error, "amuserender is currently only able to render SongGroups");
exit(1);
}
/* WAV out path */
amuse::SystemChar pathOut[1024];
SNPrintf(pathOut, 1024, _S("%s-%s.wav"), m_groupName->c_str(), m_songName->c_str());
Log.report(logvisor::Info, _S("Writing to %s"), pathOut);
/* Build voice engine */
std::unique_ptr<boo::IAudioVoiceEngine> voxEngine = boo::NewWAVAudioVoiceEngine(pathOut, rate);
amuse::BooBackendVoiceAllocator booBackend(*voxEngine);
amuse::Engine engine(booBackend, amuse::AmplitudeMode::PerSample);
/* Load group into engine */
const amuse::AudioGroup* group = engine.addAudioGroup(*selData);
if (!group)
{
Log.report(logvisor::Error, "unable to add audio group");
exit(1);
}
/* Enter playback loop */
std::shared_ptr<amuse::Sequencer> seq = engine.seqPlay(m_groupId, m_setupId, m_arrData->m_data.get());
size_t wroteFrames = 0;
signal(SIGINT, SIGINTHandler);
do
{
voxEngine->pumpAndMixVoices();
wroteFrames += voxEngine->get5MsFrames();
printf("\rFrame %" PRISize, wroteFrames);
fflush(stdout);
} while (!g_BreakLoop && (seq->state() == amuse::SequencerState::Playing || seq->getVoiceCount() != 0));
printf("\n");
return 0;
}
#if _WIN32
#include <shellapi.h>
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
{
signal(SIGABRT, abortHandler);
signal(SIGSEGV, abortHandler);
signal(SIGILL, abortHandler);
signal(SIGFPE, abortHandler);
int argc = 0;
const boo::SystemChar** argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc));
static boo::SystemChar selfPath[1024];
GetModuleFileNameW(nullptr, selfPath, 1024);
static const boo::SystemChar* booArgv[32] = {};
booArgv[0] = selfPath;
for (int i = 0; i < argc; ++i)
booArgv[i + 1] = argv[i];
logvisor::CreateWin32Console();
SetConsoleOutputCP(65001);
return wmain(argc + 1, booArgv);
}
#endif

View File

@@ -9,8 +9,7 @@ namespace amuse
{ {
class AudioGroupData; class AudioGroupData;
using Sample = std::pair<AudioGroupSampleDirectory::Entry, using Sample = std::pair<AudioGroupSampleDirectory::Entry, AudioGroupSampleDirectory::ADPCMParms>;
AudioGroupSampleDirectory::ADPCMParms>;
/** Runtime audio group index container */ /** Runtime audio group index container */
class AudioGroup class AudioGroup
@@ -21,20 +20,20 @@ class AudioGroup
const unsigned char* m_samp; const unsigned char* m_samp;
DataFormat m_fmt; DataFormat m_fmt;
bool m_valid; bool m_valid;
public: public:
operator bool() const {return m_valid;} operator bool() const { return m_valid; }
AudioGroup(const AudioGroupData& data, GCNDataTag); AudioGroup(const AudioGroupData& data, GCNDataTag);
AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag); AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag);
AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag); AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag);
const Sample* getSample(int sfxId) const; const Sample* getSample(int sfxId) const;
const unsigned char* getSampleData(uint32_t offset) const; const unsigned char* getSampleData(uint32_t offset) const;
const AudioGroupProject& getProj() const {return m_proj;} const AudioGroupProject& getProj() const { return m_proj; }
const AudioGroupPool& getPool() const {return m_pool;} const AudioGroupPool& getPool() const { return m_pool; }
const AudioGroupSampleDirectory& getSdir() const {return m_sdir;} const AudioGroupSampleDirectory& getSdir() const { return m_sdir; }
DataFormat getDataFormat() const {return m_fmt;} DataFormat getDataFormat() const { return m_fmt; }
}; };
} }
#endif // __AMUSE_AUDIOGROUP_HPP__ #endif // __AMUSE_AUDIOGROUP_HPP__

View File

@@ -10,6 +10,7 @@ namespace amuse
class AudioGroupData class AudioGroupData
{ {
friend class Engine; friend class Engine;
protected: protected:
unsigned char* m_proj; unsigned char* m_proj;
size_t m_projSz; size_t m_projSz;
@@ -19,90 +20,107 @@ protected:
size_t m_sdirSz; size_t m_sdirSz;
unsigned char* m_samp; unsigned char* m_samp;
size_t m_sampSz; size_t m_sampSz;
DataFormat m_fmt; DataFormat m_fmt;
bool m_absOffs; bool m_absOffs;
AudioGroupData(unsigned char* proj, size_t projSz, AudioGroupData(unsigned char* proj, size_t projSz, unsigned char* pool, size_t poolSz, unsigned char* sdir,
unsigned char* pool, size_t poolSz, size_t sdirSz, unsigned char* samp, size_t sampSz, DataFormat fmt, bool absOffs)
unsigned char* sdir, size_t sdirSz, : m_proj(proj)
unsigned char* samp, size_t sampSz, , m_projSz(projSz)
DataFormat fmt, bool absOffs) , m_pool(pool)
: m_proj(proj), m_projSz(projSz), , m_poolSz(poolSz)
m_pool(pool), m_poolSz(poolSz), , m_sdir(sdir)
m_sdir(sdir), m_sdirSz(sdirSz), , m_sdirSz(sdirSz)
m_samp(samp), m_sampSz(sampSz), , m_samp(samp)
m_fmt(fmt), m_absOffs(absOffs) {} , m_sampSz(sampSz)
public: , m_fmt(fmt)
AudioGroupData(unsigned char* proj, size_t projSz, , m_absOffs(absOffs)
unsigned char* pool, size_t poolSz,
unsigned char* sdir, size_t sdirSz,
unsigned char* samp, size_t sampSz, GCNDataTag)
: m_proj(proj), m_projSz(projSz),
m_pool(pool), m_poolSz(poolSz),
m_sdir(sdir), m_sdirSz(sdirSz),
m_samp(samp), m_sampSz(sampSz),
m_fmt(DataFormat::GCN), m_absOffs(true) {}
AudioGroupData(unsigned char* proj, size_t projSz,
unsigned char* pool, size_t poolSz,
unsigned char* sdir, size_t sdirSz,
unsigned char* samp, size_t sampSz, bool absOffs, N64DataTag)
: m_proj(proj), m_projSz(projSz),
m_pool(pool), m_poolSz(poolSz),
m_sdir(sdir), m_sdirSz(sdirSz),
m_samp(samp), m_sampSz(sampSz),
m_fmt(DataFormat::N64), m_absOffs(absOffs) {}
AudioGroupData(unsigned char* proj, size_t projSz,
unsigned char* pool, size_t poolSz,
unsigned char* sdir, size_t sdirSz,
unsigned char* samp, size_t sampSz, bool absOffs, PCDataTag)
: m_proj(proj), m_projSz(projSz),
m_pool(pool), m_poolSz(poolSz),
m_sdir(sdir), m_sdirSz(sdirSz),
m_samp(samp), m_sampSz(sampSz),
m_fmt(DataFormat::PC), m_absOffs(absOffs) {}
const unsigned char* getProj() const {return m_proj;}
const unsigned char* getPool() const {return m_pool;}
const unsigned char* getSdir() const {return m_sdir;}
const unsigned char* getSamp() const {return m_samp;}
unsigned char* getProj() {return m_proj;}
unsigned char* getPool() {return m_pool;}
unsigned char* getSdir() {return m_sdir;}
unsigned char* getSamp() {return m_samp;}
size_t getProjSize() const {return m_projSz;}
size_t getPoolSize() const {return m_poolSz;}
size_t getSdirSize() const {return m_sdirSz;}
size_t getSampSize() const {return m_sampSz;}
operator bool() const
{ {
return m_proj != nullptr && m_pool != nullptr && m_sdir != nullptr && m_samp != nullptr;
} }
DataFormat getDataFormat() const {return m_fmt;} public:
bool getAbsoluteProjOffsets() const {return m_absOffs;} AudioGroupData(unsigned char* proj, size_t projSz, unsigned char* pool, size_t poolSz, unsigned char* sdir,
size_t sdirSz, unsigned char* samp, size_t sampSz, GCNDataTag)
: m_proj(proj)
, m_projSz(projSz)
, m_pool(pool)
, m_poolSz(poolSz)
, m_sdir(sdir)
, m_sdirSz(sdirSz)
, m_samp(samp)
, m_sampSz(sampSz)
, m_fmt(DataFormat::GCN)
, m_absOffs(true)
{
}
AudioGroupData(unsigned char* proj, size_t projSz, unsigned char* pool, size_t poolSz, unsigned char* sdir,
size_t sdirSz, unsigned char* samp, size_t sampSz, bool absOffs, N64DataTag)
: m_proj(proj)
, m_projSz(projSz)
, m_pool(pool)
, m_poolSz(poolSz)
, m_sdir(sdir)
, m_sdirSz(sdirSz)
, m_samp(samp)
, m_sampSz(sampSz)
, m_fmt(DataFormat::N64)
, m_absOffs(absOffs)
{
}
AudioGroupData(unsigned char* proj, size_t projSz, unsigned char* pool, size_t poolSz, unsigned char* sdir,
size_t sdirSz, unsigned char* samp, size_t sampSz, bool absOffs, PCDataTag)
: m_proj(proj)
, m_projSz(projSz)
, m_pool(pool)
, m_poolSz(poolSz)
, m_sdir(sdir)
, m_sdirSz(sdirSz)
, m_samp(samp)
, m_sampSz(sampSz)
, m_fmt(DataFormat::PC)
, m_absOffs(absOffs)
{
}
const unsigned char* getProj() const { return m_proj; }
const unsigned char* getPool() const { return m_pool; }
const unsigned char* getSdir() const { return m_sdir; }
const unsigned char* getSamp() const { return m_samp; }
unsigned char* getProj() { return m_proj; }
unsigned char* getPool() { return m_pool; }
unsigned char* getSdir() { return m_sdir; }
unsigned char* getSamp() { return m_samp; }
size_t getProjSize() const { return m_projSz; }
size_t getPoolSize() const { return m_poolSz; }
size_t getSdirSize() const { return m_sdirSz; }
size_t getSampSize() const { return m_sampSz; }
operator bool() const { return m_proj != nullptr && m_pool != nullptr && m_sdir != nullptr && m_samp != nullptr; }
DataFormat getDataFormat() const { return m_fmt; }
bool getAbsoluteProjOffsets() const { return m_absOffs; }
}; };
/** A buffer-owning version of AudioGroupData */ /** A buffer-owning version of AudioGroupData */
class IntrusiveAudioGroupData : public AudioGroupData class IntrusiveAudioGroupData : public AudioGroupData
{ {
bool m_owns = true; bool m_owns = true;
public: public:
using AudioGroupData::AudioGroupData; using AudioGroupData::AudioGroupData;
~IntrusiveAudioGroupData(); ~IntrusiveAudioGroupData();
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; }
}; };
} }
#endif // __AMUSE_AUDIOGROUPDATA_HPP__ #endif // __AMUSE_AUDIOGROUPDATA_HPP__

View File

@@ -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,35 +22,31 @@ 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 {return decayCoarse == 128 ? 1.0 : ((sustainCoarse * 6.25 + sustainFine * 0.0244) / 100.0);} double getSustain() const { return sustain / double(0x1000); }
double getRelease() const {return (releaseCoarse * 255 + releaseFine) / 1000.0;} double getRelease() const { return release / 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) */
struct ADSRDLS struct ADSRDLS
{ {
uint32_t attack; /* 16.16 Time-cents */ uint32_t attack; /* 16.16 Time-cents */
uint32_t decay; /* 16.16 Time-cents */ uint32_t decay; /* 16.16 Time-cents */
uint16_t sustain; /* 0x1000 == 100% */ uint16_t sustain; /* 0x1000 == 100% */
uint16_t release; /* milliseconds */ uint16_t release; /* milliseconds */
uint32_t velToAttack; /* 16.16, 1000.0 == 100%; attack = <attack> + (vel/128) * <velToAttack> */ uint32_t velToAttack; /* 16.16, 1000.0 == 100%; attack = <attack> + (vel/128) * <velToAttack> */
uint32_t keyToDecay; /* 16.16, 1000.0 == 100%; decay = <decay> + (note/128) * <keyToDecay> */ uint32_t keyToDecay; /* 16.16, 1000.0 == 100%; decay = <decay> + (note/128) * <keyToDecay> */
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)
@@ -96,6 +92,7 @@ class AudioGroupPool
std::unordered_map<ObjectId, const unsigned char*> m_tables; std::unordered_map<ObjectId, const unsigned char*> m_tables;
std::unordered_map<ObjectId, const Keymap*> m_keymaps; std::unordered_map<ObjectId, const Keymap*> m_keymaps;
std::unordered_map<ObjectId, std::vector<const LayerMapping*>> m_layers; std::unordered_map<ObjectId, std::vector<const LayerMapping*>> m_layers;
public: public:
AudioGroupPool(const unsigned char* data); AudioGroupPool(const unsigned char* data);
AudioGroupPool(const unsigned char* data, PCDataTag); AudioGroupPool(const unsigned char* data, PCDataTag);
@@ -103,12 +100,9 @@ public:
const Keymap* keymap(ObjectId id) const; const Keymap* keymap(ObjectId id) const;
const std::vector<const LayerMapping*>* layer(ObjectId id) const; const std::vector<const LayerMapping*>* layer(ObjectId id) const;
const ADSR* tableAsAdsr(ObjectId id) const; const ADSR* tableAsAdsr(ObjectId id) const;
const ADSRDLS* tableAsAdsrDLS(ObjectId id) const const ADSRDLS* tableAsAdsrDLS(ObjectId id) const { return reinterpret_cast<const ADSRDLS*>(tableAsAdsr(id)); }
{return reinterpret_cast<const ADSRDLS*>(tableAsAdsr(id));} const Curve* tableAsCurves(ObjectId id) const { return reinterpret_cast<const Curve*>(tableAsAdsr(id)); }
const Curve* tableAsCurves(ObjectId id) const
{return reinterpret_cast<const Curve*>(tableAsAdsr(id));}
}; };
} }
#endif // __AMUSE_AUDIOGROUPPOOL_HPP__ #endif // __AMUSE_AUDIOGROUPPOOL_HPP__

View File

@@ -76,8 +76,8 @@ class AudioGroupProject
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convNormalPages; std::unique_ptr<SongGroupIndex::PageEntry[]> m_convNormalPages;
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convDrumPages; std::unique_ptr<SongGroupIndex::PageEntry[]> m_convDrumPages;
std::unique_ptr<std::array<SongGroupIndex::MIDISetup, 16>[]> m_convMidiSetups; std::unique_ptr<std::array<SongGroupIndex::MIDISetup, 16>[]> m_convMidiSetups;
void _allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag); void _allocateConvBuffers(const unsigned char* data, N64DataTag);
void _allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag); void _allocateConvBuffers(const unsigned char* data, PCDataTag);
public: public:
AudioGroupProject(const unsigned char* data, GCNDataTag); AudioGroupProject(const unsigned char* data, GCNDataTag);
@@ -88,10 +88,9 @@ public:
const SongGroupIndex* getSongGroupIndex(int groupId) const; const SongGroupIndex* getSongGroupIndex(int groupId) const;
const SFXGroupIndex* getSFXGroupIndex(int groupId) const; const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
const std::unordered_map<int, SongGroupIndex>& songGroups() const {return m_songGroups;} const std::unordered_map<int, SongGroupIndex>& songGroups() const { return m_songGroups; }
const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const {return m_sfxGroups;} const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
}; };
} }
#endif // __AMUSE_AUDIOGROUPPROJECT_HPP__ #endif // __AMUSE_AUDIOGROUPPROJECT_HPP__

View File

@@ -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
@@ -12,6 +12,7 @@ namespace amuse
class AudioGroupSampleDirectory class AudioGroupSampleDirectory
{ {
friend class AudioGroup; friend class AudioGroup;
public: public:
struct Entry struct Entry
{ {
@@ -26,8 +27,7 @@ public:
uint32_t m_adpcmParmOffset; uint32_t m_adpcmParmOffset;
void swapBig(); void swapBig();
}; };
union ADPCMParms union ADPCMParms {
{
struct DSPParms struct DSPParms
{ {
uint16_t m_bytesPerFrame; uint16_t m_bytesPerFrame;
@@ -44,17 +44,17 @@ public:
void swapBigDSP(); void swapBigDSP();
void swapBigVADPCM(); void swapBigVADPCM();
}; };
private: private:
std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>> m_entries; std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>> m_entries;
public: public:
AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag); AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag);
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, bool absOffs, N64DataTag);
bool absOffs, N64DataTag);
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag); AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const {return m_entries;}
};
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
};
} }
#endif // __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__ #endif // __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__

View File

@@ -22,18 +22,21 @@ class BooBackendVoice : public IBackendVoice
struct VoiceCallback : boo::IAudioVoiceCallback struct VoiceCallback : boo::IAudioVoiceCallback
{ {
BooBackendVoice& m_parent; BooBackendVoice& m_parent;
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, size_t channels, double dt, int busId, int16_t* in, int16_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, 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, BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch);
double sampleRate, bool dynamicPitch);
BooBackendVoice(boo::IAudioSubmix& submix, Voice& clientVox,
double sampleRate, bool dynamicPitch);
void resetSampleRate(double sampleRate); void resetSampleRate(double sampleRate);
void setMatrixCoefficients(const float coefs[8], bool slew);
void setSubmixMatrixCoefficients(const float coefs[8], bool slew); void resetChannelLevels();
void setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew);
void setPitchRatio(double ratio, bool slew); void setPitchRatio(double ratio, bool slew);
void start(); void start();
void stop(); void stop();
@@ -43,26 +46,23 @@ public:
class BooBackendSubmix : public IBackendSubmix class BooBackendSubmix : public IBackendSubmix
{ {
friend class BooBackendVoiceAllocator; friend class BooBackendVoiceAllocator;
friend class BooBackendVoice;
Submix& m_clientSmx; Submix& m_clientSmx;
struct SubmixCallback : boo::IAudioSubmixCallback struct SubmixCallback : boo::IAudioSubmixCallback
{ {
BooBackendSubmix& m_parent; BooBackendSubmix& m_parent;
bool canApplyEffect() const; bool canApplyEffect() const;
void applyEffect(int16_t* audio, size_t frameCount, void applyEffect(int16_t* audio, size_t frameCount, const boo::ChannelMap& chanMap, double sampleRate) const;
const boo::ChannelMap& chanMap, double sampleRate) const; void applyEffect(int32_t* audio, size_t frameCount, const boo::ChannelMap& chanMap, double sampleRate) const;
void applyEffect(int32_t* audio, size_t frameCount, void applyEffect(float* audio, size_t frameCount, const boo::ChannelMap& chanMap, double sampleRate) const;
const boo::ChannelMap& chanMap, double sampleRate) const;
void applyEffect(float* audio, size_t frameCount,
const boo::ChannelMap& chanMap, double sampleRate) const;
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); BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId);
BooBackendSubmix(boo::IAudioSubmix& parent, Submix& clientSmx); void setSendLevel(IBackendSubmix* submix, float level, bool slew);
void setChannelGains(const float gains[8]);
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
double getSampleRate() const; double getSampleRate() const;
SubmixFormat getSampleFormat() const; SubmixFormat getSampleFormat() const;
}; };
@@ -116,21 +116,24 @@ 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);
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch); std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx); 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 on5MsInterval(boo::IAudioVoiceEngine& engine, double dt);
void onPumpCycleComplete(boo::IAudioVoiceEngine& engine);
}; };
} }
#endif // __AMUSE_BOO_BACKEND_HPP__ #endif // __AMUSE_BOO_BACKEND_HPP__

View File

@@ -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
{ {
@@ -26,30 +38,29 @@ namespace amuse
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
using SystemString = std::wstring; using SystemString = std::wstring;
using SystemChar = wchar_t; using SystemStringView = std::wstring_view;
# ifndef _S using SystemChar = wchar_t;
# define _S(val) L ## val #ifndef _S
# endif #define _S(val) L##val
typedef struct _stat Sstat; #endif
static inline int Mkdir(const wchar_t* path, int) {return _wmkdir(path);} typedef struct _stat Sstat;
static inline int Stat(const wchar_t* path, Sstat* statout) {return _wstat(path, statout);} 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); }
#else #else
using SystemString = std::string; using SystemString = std::string;
using SystemChar = char; using SystemStringView = std::string_view;
# ifndef _S using SystemChar = char;
# define _S(val) val #ifndef _S
# endif #define _S(val) val
typedef struct stat Sstat; #endif
static inline int Mkdir(const char* path, mode_t mode) {return mkdir(path, mode);} typedef struct stat Sstat;
static inline int Stat(const char* path, Sstat* statout) {return stat(path, statout);} static inline int Mkdir(const char* path, mode_t mode) { return mkdir(path, mode); }
static inline int Stat(const char* path, Sstat* statout) { return stat(path, statout); }
#endif #endif
#if _WIN32 #if _WIN32
static inline int CompareCaseInsensitive(const char* a, const char* b) static inline int CompareCaseInsensitive(const char* a, const char* b) { return _stricmp(a, b); }
{
return _stricmp(a, b);
}
#endif #endif
static inline int CompareCaseInsensitive(const SystemChar* a, const SystemChar* b) static inline int CompareCaseInsensitive(const SystemChar* a, const SystemChar* b)
@@ -62,35 +73,30 @@ static inline int CompareCaseInsensitive(const SystemChar* a, const SystemChar*
} }
template <typename T> template <typename T>
static inline T clamp(T a, T val, T b) {return std::max<T>(a, std::min<T>(b, val));} static inline T clamp(T a, T val, T b)
{
return std::max<T>(a, std::min<T>(b, val));
}
template <typename T> template <typename T>
static inline T ClampFull(float in) {return in;} inline T ClampFull(float in)
{
template <> if (std::is_floating_point<T>())
inline int16_t ClampFull<int16_t>(float in) {
{ return std::min<T>(std::max<T>(in, -1.f), 1.f);
if (in < SHRT_MIN) }
return SHRT_MIN; else
else if (in > SHRT_MAX) {
return SHRT_MAX; constexpr T MAX = std::numeric_limits<T>::max();
return in; constexpr T MIN = std::numeric_limits<T>::min();
}
if (in < MIN)
template <> return MIN;
inline int32_t ClampFull<int32_t>(float in) else if (in > MAX)
{ return MAX;
if (in < INT_MIN) else
return INT_MIN; return in;
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
@@ -98,9 +104,10 @@ inline float ClampFull<float>(float in)
#endif #endif
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 1, 2))) __attribute__((__format__(__printf__, 1, 2)))
#endif #endif
static inline void Printf(const SystemChar* fmt, ...) static inline void
Printf(const SystemChar* fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
@@ -113,9 +120,10 @@ static inline void Printf(const SystemChar* fmt, ...)
} }
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 3, 4))) __attribute__((__format__(__printf__, 3, 4)))
#endif #endif
static inline void SNPrintf(SystemChar* str, size_t maxlen, const SystemChar* format, ...) static inline void
SNPrintf(SystemChar* str, size_t maxlen, const SystemChar* format, ...)
{ {
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@@ -181,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
@@ -220,24 +237,20 @@ static inline T bswap64(T val)
#elif _WIN32 #elif _WIN32
return _byteswap_uint64(val); return _byteswap_uint64(val);
#else #else
return ((val & 0xFF00000000000000ULL) >> 56) | return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x00FF000000000000ULL) >> 40) | ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000FF00000000ULL) >> 8) | ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
((val & 0x00000000FF000000ULL) << 8) |
((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) |
((val & 0x00000000000000FFULL) << 56);
#endif #endif
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline int16_t SBig(int16_t val) {return bswap16(val);} static inline int16_t SBig(int16_t val) { return bswap16(val); }
static inline uint16_t SBig(uint16_t val) {return bswap16(val);} static inline uint16_t SBig(uint16_t val) { return bswap16(val); }
static inline int32_t SBig(int32_t val) {return bswap32(val);} static inline int32_t SBig(int32_t val) { return bswap32(val); }
static inline uint32_t SBig(uint32_t val) {return bswap32(val);} static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
static inline int64_t SBig(int64_t val) {return bswap64(val);} static inline int64_t SBig(int64_t val) { return bswap64(val); }
static inline uint64_t SBig(uint64_t val) {return bswap64(val);} static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
static inline float SBig(float val) static inline float SBig(float val)
{ {
int32_t ival = bswap32(*((int32_t*)(&val))); int32_t ival = bswap32(*((int32_t*)(&val)));
@@ -249,28 +262,27 @@ static inline double SBig(double val)
return *((double*)(&ival)); return *((double*)(&ival));
} }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \ #define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif #endif
static inline int16_t SLittle(int16_t val) {return val;} static inline int16_t SLittle(int16_t val) { return val; }
static inline uint16_t SLittle(uint16_t val) {return val;} static inline uint16_t SLittle(uint16_t val) { return val; }
static inline int32_t SLittle(int32_t val) {return val;} static inline int32_t SLittle(int32_t val) { return val; }
static inline uint32_t SLittle(uint32_t val) {return val;} static inline uint32_t SLittle(uint32_t val) { return val; }
static inline int64_t SLittle(int64_t val) {return val;} static inline int64_t SLittle(int64_t val) { return val; }
static inline uint64_t SLittle(uint64_t val) {return val;} static inline uint64_t SLittle(uint64_t val) { return val; }
static inline float SLittle(float val) {return val;} static inline float SLittle(float val) { return val; }
static inline double SLittle(double val) {return val;} static inline double SLittle(double val) { return val; }
#ifndef SLITTLE #ifndef SLITTLE
#define SLITTLE(q) (q) #define SLITTLE(q) (q)
#endif #endif
#else #else
static inline int16_t SLittle(int16_t val) {return bswap16(val);} static inline int16_t SLittle(int16_t val) { return bswap16(val); }
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);} static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
static inline int32_t SLittle(int32_t val) {return bswap32(val);} static inline int32_t SLittle(int32_t val) { return bswap32(val); }
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);} static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
static inline int64_t SLittle(int64_t val) {return bswap64(val);} static inline int64_t SLittle(int64_t val) { return bswap64(val); }
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);} static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
static inline float SLittle(float val) static inline float SLittle(float val)
{ {
int32_t ival = bswap32(*((int32_t*)(&val))); int32_t ival = bswap32(*((int32_t*)(&val)));
@@ -282,18 +294,17 @@ static inline double SLittle(double val)
return *((double*)(&ival)); return *((double*)(&ival));
} }
#ifndef SLITTLE #ifndef SLITTLE
#define SLITTLE(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \ #define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
#endif #endif
static inline int16_t SBig(int16_t val) {return val;} static inline int16_t SBig(int16_t val) { return val; }
static inline uint16_t SBig(uint16_t val) {return val;} static inline uint16_t SBig(uint16_t val) { return val; }
static inline int32_t SBig(int32_t val) {return val;} static inline int32_t SBig(int32_t val) { return val; }
static inline uint32_t SBig(uint32_t val) {return val;} static inline uint32_t SBig(uint32_t val) { return val; }
static inline int64_t SBig(int64_t val) {return val;} static inline int64_t SBig(int64_t val) { return val; }
static inline uint64_t SBig(uint64_t val) {return val;} static inline uint64_t SBig(uint64_t val) { return val; }
static inline float SBig(float val) {return val;} static inline float SBig(float val) { return val; }
static inline double SBig(double val) {return val;} static inline double SBig(double val) { return val; }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) (q) #define SBIG(q) (q)
#endif #endif
@@ -308,14 +319,19 @@ enum class DataFormat
}; };
/** Meta-type for selecting GameCube (MusyX 2.0) data formats */ /** Meta-type for selecting GameCube (MusyX 2.0) data formats */
struct GCNDataTag {}; struct GCNDataTag
{
};
/** Meta-type for selecting N64 (MusyX 1.0) data formats */ /** Meta-type for selecting N64 (MusyX 1.0) data formats */
struct N64DataTag {}; struct N64DataTag
{
};
/** Meta-type for selecting PC (MusyX 1.0) data formats */ /** Meta-type for selecting PC (MusyX 1.0) data formats */
struct PCDataTag {}; struct PCDataTag
{
};
} }
#endif // __AMUSE_COMMON_HPP__ #endif // __AMUSE_COMMON_HPP__

View File

@@ -21,8 +21,7 @@ public:
MetroidPrime2, MetroidPrime2,
RogueSquadronPC, RogueSquadronPC,
RogueSquadronN64, RogueSquadronN64,
BattleForNabooPC, Factor5N64Rev,
BattleForNabooN64,
RogueSquadron2, RogueSquadron2,
RogueSquadron3 RogueSquadron3
}; };
@@ -33,15 +32,17 @@ public:
int16_t m_groupId; int16_t m_groupId;
int16_t m_setupId; int16_t m_setupId;
SongData(std::unique_ptr<uint8_t[]>&& data, size_t size, int16_t groupId, int16_t setupId) SongData(std::unique_ptr<uint8_t[]>&& data, size_t size, int16_t groupId, int16_t setupId)
: m_data(std::move(data)), m_size(size), m_groupId(groupId), m_setupId(setupId) {} : m_data(std::move(data)), m_size(size), m_groupId(groupId), m_setupId(setupId)
{
}
}; };
static const SystemChar* TypeToName(Type tp); static const SystemChar* TypeToName(Type tp);
static Type DetectContainerType(const SystemChar* path); static Type DetectContainerType(const SystemChar* path);
static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadContainer(const SystemChar* path); static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadContainer(const SystemChar* path);
static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadContainer(const SystemChar* path, Type& typeOut); static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadContainer(const SystemChar* path,
Type& typeOut);
static std::vector<std::pair<SystemString, SongData>> LoadSongs(const SystemChar* path); static std::vector<std::pair<SystemString, SongData>> LoadSongs(const SystemChar* path);
}; };
} }
#endif // __AMUSE_CONTAINERREGISTRY_HPP__ #endif // __AMUSE_CONTAINERREGISTRY_HPP__

View File

@@ -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,28 +47,22 @@ 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, DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
bool sizeSort=false, bool reverse=false, bool noHidden=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);
operator bool() const {return m_entries.size() != 0;} operator bool() const { return m_entries.size() != 0; }
size_t size() const {return m_entries.size();} size_t size() const { return m_entries.size(); }
std::vector<Entry>::const_iterator begin() const {return m_entries.cbegin();} std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
std::vector<Entry>::const_iterator end() const {return m_entries.cend();} std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
}; };
} }
#endif // __AMUSE_DIRECTORY_ENUMERATOR__ #endif // __AMUSE_DIRECTORY_ENUMERATOR__

View File

@@ -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
{ {
@@ -12,16 +12,15 @@ class EffectBaseTypeless
{ {
public: public:
virtual ~EffectBaseTypeless() = default; virtual ~EffectBaseTypeless() = default;
virtual void resetOutputSampleRate(double sampleRate)=0; virtual void resetOutputSampleRate(double sampleRate) = 0;
}; };
template <typename T> template <typename T>
class EffectBase : public EffectBaseTypeless class EffectBase : public EffectBaseTypeless
{ {
public: public:
virtual void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap)=0; virtual void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) = 0;
}; };
} }
#endif // __AMUSE_EFFECTBASE_HPP__ #endif // __AMUSE_EFFECTBASE_HPP__

View File

@@ -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,17 +12,30 @@ 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
{ {
uint32_t x90_baseDelay; /**< [5, 15] minimum value (in ms) for computed delay */ uint32_t x90_baseDelay; /**< [5, 15] minimum value (in ms) for computed delay */
uint32_t x94_variation; /**< [0, 5] time error (in ms) to set delay within */ uint32_t x94_variation; /**< [0, 5] time error (in ms) to set delay within */
uint32_t x98_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */ uint32_t x98_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */
bool m_dirty = true; /**< needs update of internal parameter data */ bool m_dirty = true; /**< needs update of internal parameter data */
template <typename T> template <typename T>
friend class EffectChorusImp; friend class EffectChorusImp;
EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period); EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
public: public:
template <typename T> template <typename T>
using ImpType = EffectChorusImp<T>; using ImpType = EffectChorusImp<T>;
@@ -47,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 */
@@ -56,32 +76,32 @@ class EffectChorusImp : public EffectBase<T>, public EffectChorus
T* x0_lastChans[8][AMUSE_CHORUS_NUM_BLOCKS] = {}; /**< Evenly-allocated pointer-table for each channel's delay */ T* x0_lastChans[8][AMUSE_CHORUS_NUM_BLOCKS] = {}; /**< Evenly-allocated pointer-table for each channel's delay */
uint8_t x24_currentLast = 1; /**< Last 5ms block-idx to be processed */ uint8_t x24_currentLast = 1; /**< Last 5ms block-idx to be processed */
T x28_oldChans[8][4] = {}; /**< Unprocessed history of previous 4 samples */ T x28_oldChans[8][4] = {}; /**< Unprocessed history of previous 4 samples */
uint32_t x58_currentPosLo = 0; /**< 16.7 fixed-point low-part of sample index */ uint32_t x58_currentPosLo = 0; /**< 16.7 fixed-point low-part of sample index */
uint32_t x5c_currentPosHi = 0; /**< 16.7 fixed-point high-part of sample index */ uint32_t x5c_currentPosHi = 0; /**< 16.7 fixed-point high-part of sample index */
int32_t x60_pitchOffset; /**< packed 16.16 fixed-point value of pitchHi and pitchLo quantities */ int32_t x60_pitchOffset; /**< packed 16.16 fixed-point value of pitchHi and pitchLo quantities */
uint32_t x64_pitchOffsetPeriodCount; /**< trigger value for flipping SRC state */ uint32_t x64_pitchOffsetPeriodCount; /**< trigger value for flipping SRC state */
uint32_t x68_pitchOffsetPeriod; /**< intermediate block window quantity for calculating SRC state */ uint32_t x68_pitchOffsetPeriod; /**< intermediate block window quantity for calculating SRC state */
struct SrcInfo struct SrcInfo
{ {
T* x6c_dest; /**< selected channel's live buffer */ T* x6c_dest; /**< selected channel's live buffer */
T* x70_smpBase; /**< selected channel's delay buffer */ T* x70_smpBase; /**< selected channel's delay buffer */
T* x74_old; /**< selected channel's 4-sample history buffer */ T* x74_old; /**< selected channel's 4-sample history buffer */
uint32_t x78_posLo; /**< 16.7 fixed-point low-part of sample index */ uint32_t x78_posLo; /**< 16.7 fixed-point low-part of sample index */
uint32_t x7c_posHi; /**< 16.7 fixed-point high-part of sample index */ uint32_t x7c_posHi; /**< 16.7 fixed-point high-part of sample index */
uint32_t x80_pitchLo; /**< 16.7 fixed-point low-part of sample-rate conversion differential */ uint32_t x80_pitchLo; /**< 16.7 fixed-point low-part of sample-rate conversion differential */
uint32_t x84_pitchHi; /**< 16.7 fixed-point low-part of sample-rate conversion differential */ uint32_t x84_pitchHi; /**< 16.7 fixed-point low-part of sample-rate conversion differential */
uint32_t x88_trigger; /**< total count of samples per channel across all blocks */ uint32_t x88_trigger; /**< total count of samples per channel across all blocks */
uint32_t x8c_target = 0; /**< value to reset to when trigger hit */ uint32_t x8c_target = 0; /**< value to reset to when trigger hit */
void doSrc1(size_t blockSamples, size_t chanCount); void doSrc1(size_t blockSamples, size_t chanCount);
void doSrc2(size_t blockSamples, size_t chanCount); void doSrc2(size_t blockSamples, size_t chanCount);
} x6c_src; } x6c_src;
uint32_t m_sampsPerMs; /**< canonical count of samples per ms for the current backend */ uint32_t m_sampsPerMs; /**< canonical count of samples per ms for the current backend */
uint32_t m_blockSamples; /**< count of samples in a 5ms block */ uint32_t m_blockSamples; /**< count of samples in a 5ms block */
void _setup(double sampleRate); void _setup(double sampleRate);
@@ -90,10 +110,12 @@ 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);
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); EffectChorusImp(const EffectChorusInfo& info, double sampleRate)
void resetOutputSampleRate(double sampleRate) {_setup(sampleRate);} : EffectChorusImp(info.baseDelay, info.variation, info.period, sampleRate) {}
};
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
} }
#endif // __AMUSE_EFFECTCHORUS_HPP__ #endif // __AMUSE_EFFECTCHORUS_HPP__

View File

@@ -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,14 +12,46 @@ 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
{ {
protected: protected:
uint32_t x3c_delay[8]; /**< [10, 5000] time in ms of each channel's delay */ uint32_t x3c_delay[8]; /**< [10, 5000] time in ms of each channel's delay */
uint32_t x48_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */ uint32_t x48_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */
uint32_t x54_output[8]; /**< [0, 100] total output percent */ uint32_t x54_output[8]; /**< [0, 100] total output percent */
bool m_dirty = true; /**< needs update of internal parameter data */ bool m_dirty = true; /**< needs update of internal parameter data */
public: public:
template <typename T> template <typename T>
using ImpType = EffectDelayImp<T>; using ImpType = EffectDelayImp<T>;
@@ -26,7 +59,7 @@ public:
void setDelay(uint32_t delay) void setDelay(uint32_t delay)
{ {
delay = clamp(10u, delay, 5000u); delay = clamp(10u, delay, 5000u);
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
x3c_delay[i] = delay; x3c_delay[i] = delay;
m_dirty = true; m_dirty = true;
} }
@@ -40,7 +73,7 @@ public:
void setFeedback(uint32_t feedback) void setFeedback(uint32_t feedback)
{ {
feedback = clamp(0u, feedback, 100u); feedback = clamp(0u, feedback, 100u);
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
x48_feedback[i] = feedback; x48_feedback[i] = feedback;
m_dirty = true; m_dirty = true;
} }
@@ -55,39 +88,53 @@ public:
void setOutput(uint32_t output) void setOutput(uint32_t output)
{ {
output = clamp(0u, output, 100u); output = clamp(0u, output, 100u);
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
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 */
template <typename T> template <typename T>
class EffectDelayImp : public EffectBase<T>, public EffectDelay class EffectDelayImp : public EffectBase<T>, public EffectDelay
{ {
uint32_t x0_currentSize[8]; /**< per-channel delay-line buffer sizes */ uint32_t x0_currentSize[8]; /**< per-channel delay-line buffer sizes */
uint32_t xc_currentPos[8]; /**< per-channel block-index */ uint32_t xc_currentPos[8]; /**< per-channel block-index */
uint32_t x18_currentFeedback[8]; /**< [0, 128] feedback attenuator */ uint32_t x18_currentFeedback[8]; /**< [0, 128] feedback attenuator */
uint32_t x24_currentOutput[8]; /**< [0, 128] total attenuator */ uint32_t x24_currentOutput[8]; /**< [0, 128] total attenuator */
std::unique_ptr<T[]> x30_chanLines[8]; /**< delay-line buffers for each channel */ std::unique_ptr<T[]> x30_chanLines[8]; /**< delay-line buffers for each channel */
uint32_t m_sampsPerMs; /**< canonical count of samples per ms for the current backend */ uint32_t m_sampsPerMs; /**< canonical count of samples per ms for the current backend */
uint32_t m_blockSamples; /**< count of samples in a 5ms block */ uint32_t m_blockSamples; /**< count of samples in a 5ms block */
void _setup(double sampleRate); void _setup(double sampleRate);
void _update(); void _update();
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);
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); EffectDelayImp(const EffectDelayInfo& info, double sampleRate);
void resetOutputSampleRate(double sampleRate) {_setup(sampleRate);}
};
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
} }
#endif // __AMUSE_EFFECTDELAY_HPP__ #endif // __AMUSE_EFFECTDELAY_HPP__

View File

@@ -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
{ {
@@ -31,19 +60,20 @@ class EffectReverbHiImp;
class EffectReverbStd class EffectReverbStd
{ {
protected: protected:
float x140_x1c8_coloration; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */ float x140_x1c8_coloration; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a
float x144_x1cc_mix; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */ room */
float x148_x1d0_time; /**< [0.01, 10.0] time in seconds for reflection decay */ float x144_x1cc_mix; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */
float x14c_x1d4_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float x148_x1d0_time; /**< [0.01, 10.0] time in seconds for reflection decay */
float x150_x1d8_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */ float x14c_x1d4_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
bool m_dirty = true; /**< needs update of internal parameter data */ float x150_x1d8_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */
bool m_dirty = true; /**< needs update of internal parameter data */
template <typename T> template <typename T>
friend class EffectReverbStdImp; friend class EffectReverbStdImp;
template <typename T> template <typename T>
friend class EffectReverbHiImp; friend class EffectReverbHiImp;
EffectReverbStd(float coloration, float mix, float time, EffectReverbStd(float coloration, float mix, float time, float damping, float preDelay);
float damping, float preDelay);
public: public:
template <typename T> template <typename T>
using ImpType = EffectReverbStdImp<T>; using ImpType = EffectReverbStdImp<T>;
@@ -77,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 */
@@ -86,8 +125,8 @@ class EffectReverbHi : public EffectReverbStd
template <typename T> template <typename T>
friend class EffectReverbHiImp; friend class EffectReverbHiImp;
EffectReverbHi(float coloration, float mix, float time, EffectReverbHi(float coloration, float mix, float time, float damping, float preDelay, float crosstalk);
float damping, float preDelay, float crosstalk);
public: public:
template <typename T> template <typename T>
using ImpType = EffectReverbHiImp<T>; using ImpType = EffectReverbHiImp<T>;
@@ -97,48 +136,61 @@ 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 */
template <typename T> template <typename T>
class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd
{ {
ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */ ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */
ReverbDelayLine x78_C[8][2] = {}; /**< Comb delay lines */ ReverbDelayLine x78_C[8][2] = {}; /**< Comb delay lines */
float xf0_allPassCoef = 0.f; /**< All-pass mix coefficient */ float xf0_allPassCoef = 0.f; /**< All-pass mix coefficient */
float xf4_combCoef[8][2] = {}; /**< Comb mix coefficients */ float xf4_combCoef[8][2] = {}; /**< Comb mix coefficients */
float x10c_lpLastout[8] = {}; /**< Last low-pass results */ float x10c_lpLastout[8] = {}; /**< Last low-pass results */
float x118_level = 0.f; /**< Internal wet/dry mix factor */ float x118_level = 0.f; /**< Internal wet/dry mix factor */
float x11c_damping = 0.f; /**< Low-pass damping */ float x11c_damping = 0.f; /**< Low-pass damping */
int32_t x120_preDelayTime = 0; /**< Sample count of pre-delay */ int32_t x120_preDelayTime = 0; /**< Sample count of pre-delay */
std::unique_ptr<float[]> x124_preDelayLine[8]; /**< Dedicated pre-delay buffers */ std::unique_ptr<float[]> x124_preDelayLine[8]; /**< Dedicated pre-delay buffers */
float* x130_preDelayPtr[8] = {}; /**< Current pre-delay pointers */ float* x130_preDelayPtr[8] = {}; /**< Current pre-delay pointers */
double m_sampleRate; /**< copy of sample rate */ double m_sampleRate; /**< copy of sample rate */
void _setup(double sampleRate); void _setup(double sampleRate);
void _update(); void _update();
public: public:
EffectReverbStdImp(float coloration, float mix, float time, EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate);
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); }
}; };
/** High-quality 3-stage reverb with per-channel low-pass and crosstalk */ /** High-quality 3-stage reverb with per-channel low-pass and crosstalk */
template <typename T> template <typename T>
class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi
{ {
ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */ ReverbDelayLine x0_AP[8][2] = {}; /**< All-pass delay lines */
ReverbDelayLine x78_LP[8] = {}; /**< Per-channel low-pass delay-lines */ ReverbDelayLine x78_LP[8] = {}; /**< Per-channel low-pass delay-lines */
ReverbDelayLine xb4_C[8][3] = {}; /**< Comb delay lines */ ReverbDelayLine xb4_C[8][3] = {}; /**< Comb delay lines */
float x168_allPassCoef = 0.f; /**< All-pass mix coefficient */ float x168_allPassCoef = 0.f; /**< All-pass mix coefficient */
float x16c_combCoef[8][3] = {}; /**< Comb mix coefficients */ float x16c_combCoef[8][3] = {}; /**< Comb mix coefficients */
float x190_lpLastout[8] = {}; /**< Last low-pass results */ float x190_lpLastout[8] = {}; /**< Last low-pass results */
float x19c_level = 0.f; /**< Internal wet/dry mix factor */ float x19c_level = 0.f; /**< Internal wet/dry mix factor */
float x1a0_damping = 0.f; /**< Low-pass damping */ float x1a0_damping = 0.f; /**< Low-pass damping */
int32_t x1a4_preDelayTime = 0; /**< Sample count of pre-delay */ int32_t x1a4_preDelayTime = 0; /**< Sample count of pre-delay */
std::unique_ptr<float[]> x1ac_preDelayLine[8]; /**< Dedicated pre-delay buffers */ std::unique_ptr<float[]> x1ac_preDelayLine[8]; /**< Dedicated pre-delay buffers */
float* x1b8_preDelayPtr[8] = {}; /**< Current pre-delay pointers */ float* x1b8_preDelayPtr[8] = {}; /**< Current pre-delay pointers */
float x1a8_internalCrosstalk = 0.f; float x1a8_internalCrosstalk = 0.f;
double m_sampleRate; /**< copy of sample rate */ double m_sampleRate; /**< copy of sample rate */
@@ -146,13 +198,16 @@ class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi
void _update(); void _update();
void _handleReverb(T* audio, int chanIdx, int chanCount, int sampleCount); void _handleReverb(T* audio, int chanIdx, int chanCount, int sampleCount);
void _doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount); void _doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount);
public:
EffectReverbHiImp(float coloration, float mix, float time,
float damping, float preDelay, float crosstalk, double sampleRate);
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) {_setup(sampleRate);}
};
public:
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
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 resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
} }
#endif // __AMUSE_EFFECTREVERB_HPP__ #endif // __AMUSE_EFFECTREVERB_HPP__

View File

@@ -2,35 +2,66 @@
#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; }
}; };
} }
#endif // __AMUSE_EMITTER_HPP__ #endif // __AMUSE_EMITTER_HPP__

View File

@@ -7,8 +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 "IBackendVoiceAllocator.hpp"
namespace amuse namespace amuse
{ {
@@ -22,7 +25,7 @@ class IMIDIReader;
enum class AmplitudeMode enum class AmplitudeMode
{ {
PerSample, /**< Per-sample amplitude evaluation (dt = 1.0 / sampleRate, rather CPU demanding) */ PerSample, /**< Per-sample amplitude evaluation (dt = 1.0 / sampleRate, rather CPU demanding) */
BlockLinearized /**< Per-block lerp amplitude evaluation (dt = 160.0 / sampleRate) */ BlockLinearized /**< Per-block lerp amplitude evaluation (dt = 160.0 / sampleRate) */
}; };
@@ -32,6 +35,7 @@ class Engine
friend class Voice; friend class Voice;
friend class Emitter; friend class Emitter;
friend class Sequencer; friend class Sequencer;
friend class Studio;
friend struct Sequencer::ChannelState; friend struct Sequencer::ChannelState;
IBackendVoiceAllocator& m_backend; IBackendVoiceAllocator& m_backend;
@@ -40,38 +44,38 @@ 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<Submix> m_activeSubmixes; std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
bool m_defaultStudioReady = false;
std::shared_ptr<Studio> m_defaultStudio;
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;
std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const; std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const;
std::list<std::shared_ptr<Voice>>::iterator std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
_allocateVoice(const AudioGroup& group, int groupId, double sampleRate, bool dynamicPitch, bool emitter,
bool dynamicPitch, bool emitter, Submix* smx); std::weak_ptr<Studio> studio);
std::list<std::shared_ptr<Sequencer>>::iterator std::list<std::shared_ptr<Sequencer>>::iterator _allocateSequencer(const AudioGroup& group, int groupId,
_allocateSequencer(const AudioGroup& group, int groupId, int setupId, std::weak_ptr<Studio> studio);
int setupId, Submix* smx); std::shared_ptr<Studio> _allocateStudio(bool mainOut);
std::list<Submix>::iterator _allocateSubmix(Submix* smx);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
std::list<std::shared_ptr<Sequencer>>::iterator _destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it); std::list<std::shared_ptr<Sequencer>>::iterator
std::list<Submix>::iterator _destroySubmix(std::list<Submix>::iterator it); _destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
std::list<Submix>::iterator _removeSubmix(std::list<Submix>::iterator it);
void _bringOutYourDead(); void _bringOutYourDead();
void _5MsCallback(double dt);
public: public:
~Engine(); ~Engine();
Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode=AmplitudeMode::PerSample); Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode = AmplitudeMode::PerSample);
/** 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);
@@ -79,23 +83,46 @@ public:
/** Remove audio group from engine */ /** Remove audio group from engine */
void removeAudioGroup(const AudioGroupData& data); void removeAudioGroup(const AudioGroupData& data);
/** Create new Submix (a.k.a 'Studio') within root mix engine */ /** Access engine's default studio */
Submix* addSubmix(Submix* parent=nullptr); std::shared_ptr<Studio> getDefaultStudio() { return m_defaultStudio; }
/** Remove Submix and deallocate */ /** Create new Studio within engine */
void removeSubmix(Submix* smx); std::shared_ptr<Studio> addStudio(bool mainOut);
/** Start soundFX playing from loaded audio groups */ /** Start soundFX playing from loaded audio groups */
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan, Submix* smx=nullptr); std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan, std::weak_ptr<Studio> smx);
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan)
{
return fxStart(sfxId, vol, pan, m_defaultStudio);
}
/** 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, std::shared_ptr<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
float falloff, int sfxId, float minVol, float maxVol, int sfxId, float minVol, float maxVol, bool doppler,
Submix* smx=nullptr); 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,
Submix* smx=nullptr); std::weak_ptr<Studio> smx);
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData)
{
return seqPlay(groupId, songId, arrData, m_defaultStudio);
}
/** Set total volume of engine */
void setVolume(float vol);
/** Find voice from VoiceId */ /** Find voice from VoiceId */
std::shared_ptr<Voice> findVoice(int vid); std::shared_ptr<Voice> findVoice(int vid);
@@ -107,12 +134,19 @@ public:
void sendMacroMessage(ObjectId macroId, int32_t val); void sendMacroMessage(ObjectId macroId, int32_t val);
/** Obtain next random number from engine's PRNG */ /** Obtain next random number from engine's PRNG */
uint32_t nextRandom() {return m_random();} uint32_t nextRandom() { return m_random(); }
/** 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);
};
} }
#endif // __AMUSE_ENGINE_HPP__ #endif // __AMUSE_ENGINE_HPP__

View File

@@ -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
{ {
@@ -21,13 +21,12 @@ class Entity
* but shared_ptrs are issued to the client so it can safely track state */ * but shared_ptrs are issued to the client so it can safely track state */
friend class Engine; friend class Engine;
friend class SoundMacroState; friend class SoundMacroState;
protected: 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;
@@ -35,26 +34,25 @@ protected:
int m_groupId; int m_groupId;
ObjectId m_objectId = 0xffff; /* if applicable */ ObjectId m_objectId = 0xffff; /* if applicable */
public: public:
Entity(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid=ObjectId()) Entity(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid = ObjectId())
: m_engine(engine), m_audioGroup(group), m_groupId(groupId), m_objectId(oid) {} : m_engine(engine), m_audioGroup(group), m_groupId(groupId), m_objectId(oid)
{
}
~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; }
const AudioGroup& getAudioGroup() const {return m_audioGroup;} const AudioGroup& getAudioGroup() const { return m_audioGroup; }
int getGroupId() const {return m_groupId;} int getGroupId() const { return m_groupId; }
ObjectId getObjectId() const {return m_objectId;} ObjectId getObjectId() const { return m_objectId; }
}; };
/** Curves for mapping velocity to volume and other functional mappings /** Curves for mapping velocity to volume and other functional mappings
* (defined here for visibility)*/ * (defined here for visibility)*/
using Curve = uint8_t[128]; using Curve = uint8_t[128];
} }
#endif // __AMUSE_ENTITY_HPP__ #endif // __AMUSE_ENTITY_HPP__

View File

@@ -19,15 +19,17 @@ public:
Release, Release,
Complete Complete
}; };
private: private:
State m_phase = State::Attack; /**< Current envelope state */ State m_phase = State::Attack; /**< Current envelope state */
double m_attackTime = 0.02; /**< Time of attack in seconds */ double m_attackTime = 0.01; /**< Time of attack in seconds */
double m_decayTime = 0.0; /**< Time of decay in seconds */ double m_decayTime = 0.0; /**< Time of decay in seconds */
double m_sustainFactor = 1.0; /**< Evaluated sustain percentage */ double m_sustainFactor = 1.0; /**< Evaluated sustain percentage */
double m_releaseTime = 0.02; /**< Time of release in seconds */ double m_releaseTime = 0.01; /**< Time of release in seconds */
double m_releaseStartFactor = 0.0; /**< Level at whenever release event occurs */ double m_releaseStartFactor = 0.0; /**< Level at whenever release event occurs */
double m_curTime = 0.0; /**< Current time of envelope stage in seconds */ double m_curTime = 0.0; /**< Current time of envelope stage in seconds */
bool m_adsrSet = false; bool m_adsrSet = false;
public: public:
void reset(const ADSR* adsr); void reset(const ADSR* adsr);
void reset(const ADSRDLS* adsr, int8_t note, int8_t vel); void reset(const ADSRDLS* adsr, int8_t note, int8_t vel);
@@ -35,10 +37,9 @@ public:
void keyOff(); void keyOff();
float advance(double dt, const Voice& vox); float advance(double dt, const Voice& vox);
float advance(double dt); float advance(double dt);
bool isComplete() const {return m_phase == State::Complete;} bool isComplete() const { return m_phase == State::Complete; }
bool isAdsrSet() const {return m_adsrSet;} bool isAdsrSet() const { return m_adsrSet; }
}; };
} }
#endif // __AMUSE_ENVELOPE_HPP__ #endif // __AMUSE_ENVELOPE_HPP__

View File

@@ -21,19 +21,15 @@ class IBackendSubmix
public: public:
virtual ~IBackendSubmix() = default; virtual ~IBackendSubmix() = default;
/** Set channel-gains for submix (AudioChannel enum for array index) */ /** Set send level for submix (AudioChannel enum for array index) */
virtual void setChannelGains(const float gains[8])=0; virtual void setSendLevel(IBackendSubmix* submix, float level, bool slew) = 0;
/** Amuse obtains a new voice from the platform outputting to this submix */
virtual std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)=0;
/** Amuse gets fixed sample rate of submix this way */ /** Amuse gets fixed sample rate of submix this way */
virtual double getSampleRate() const=0; virtual double getSampleRate() const = 0;
/** Amuse gets fixed sample format of submix this way */ /** Amuse gets fixed sample format of submix this way */
virtual SubmixFormat getSampleFormat() const=0; virtual SubmixFormat getSampleFormat() const = 0;
}; };
} }
#endif // __AMUSE_IBACKENDSUBMIX_HPP__ #endif // __AMUSE_IBACKENDSUBMIX_HPP__

View File

@@ -3,6 +3,7 @@
namespace amuse namespace amuse
{ {
class IBackendSubmix;
/** Same channel enums from boo, used for matrix coefficient table index */ /** Same channel enums from boo, used for matrix coefficient table index */
enum class AudioChannel enum class AudioChannel
@@ -32,24 +33,23 @@ public:
virtual ~IBackendVoice() = default; virtual ~IBackendVoice() = default;
/** Set new sample rate into platform voice (may result in artifacts while playing) */ /** Set new sample rate into platform voice (may result in artifacts while playing) */
virtual void resetSampleRate(double sampleRate)=0; virtual void resetSampleRate(double sampleRate) = 0;
/** Reset channel-gains to silence and unbind all submixes */
virtual void resetChannelLevels() = 0;
/** Set channel-gains for audio source (AudioChannel enum for array index) */ /** Set channel-gains for audio source (AudioChannel enum for array index) */
virtual void setMatrixCoefficients(const float coefs[8], bool slew)=0; virtual void setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew) = 0;
/** Set submix-channel-gains for audio source (AudioChannel enum for array index) */
virtual void setSubmixMatrixCoefficients(const float coefs[8], bool slew)=0;
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */ /** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
virtual void setPitchRatio(double ratio, bool slew)=0; virtual void setPitchRatio(double ratio, bool slew) = 0;
/** Instructs platform to begin consuming sample data; invoking callback as needed */ /** Instructs platform to begin consuming sample data; invoking callback as needed */
virtual void start()=0; virtual void start() = 0;
/** Instructs platform to stop consuming sample data */ /** Instructs platform to stop consuming sample data */
virtual void stop()=0; virtual void stop() = 0;
}; };
} }
#endif // __AMUSE_IBACKENDVOICE_HPP__ #endif // __AMUSE_IBACKENDVOICE_HPP__

View File

@@ -27,9 +27,9 @@ enum class AudioChannelSet
class IMIDIReader class IMIDIReader
{ {
public: public:
virtual ~IMIDIReader()=default; virtual ~IMIDIReader() = default;
virtual std::string description()=0; virtual std::string description() = 0;
virtual void pumpReader(double dt)=0; virtual void pumpReader(double dt) = 0;
}; };
/** Client-implemented voice allocator */ /** Client-implemented voice allocator */
@@ -39,29 +39,26 @@ public:
virtual ~IBackendVoiceAllocator() = default; virtual ~IBackendVoiceAllocator() = default;
/** Amuse obtains a new voice from the platform this way */ /** Amuse obtains a new voice from the platform this way */
virtual std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, virtual std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch) = 0;
double sampleRate,
bool dynamicPitch)=0;
/** Amuse obtains a new submix from the platform this way */ /** Amuse obtains a new submix from the platform this way */
virtual std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx)=0; virtual std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut, int busId) = 0;
/** Amuse obtains a list of all MIDI devices this way */ /** Amuse obtains a list of all MIDI devices this way */
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices()=0; virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() = 0;
/** Amuse obtains an interactive MIDI-in connection from the OS this way */ /** Amuse obtains an interactive MIDI-in connection from the OS this way */
virtual std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name=nullptr)=0; virtual std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name = nullptr) = 0;
/** 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 */ /** Set volume of main mix out */
virtual void pumpAndMixVoices()=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;
}; };
} }
#endif // __AMUSE_IBACKENDVOICEALLOCATOR_HPP__ #endif // __AMUSE_IBACKENDVOICEALLOCATOR_HPP__

View File

@@ -1,15 +1,30 @@
#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; }
}; };
} }
#endif // __AMUSE_LISTENER_HPP__ #endif // __AMUSE_LISTENER_HPP__

View File

@@ -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>
@@ -12,44 +11,51 @@
namespace amuse namespace amuse
{ {
class Submix; class Studio;
class Voice; class Voice;
/** State of sequencer over lifetime */ /** State of sequencer over lifetime */
enum class SequencerState enum class SequencerState
{ {
Playing, /**< Sequencer actively playing arrangement */ Playing, /**< Sequencer actively playing arrangement */
Interactive, /**< Interactive sequencer for live MIDI message processing, will not automatically die */ Interactive, /**< Interactive sequencer for live MIDI message processing, will not automatically die */
Dead /**< Set when arrangement complete and `dieOnEnd` was set, or manually with die() */ Dead /**< Set when arrangement complete and `dieOnEnd` was set, or manually with die() */
}; };
/** Multi-voice lifetime manager and polyphonic parameter tracking */ /** Multi-voice lifetime manager and polyphonic parameter tracking */
class Sequencer : public Entity class Sequencer : public Entity
{ {
friend class Engine; friend class Engine;
const SongGroupIndex* m_songGroup = nullptr; /**< Quick access to song group project index */ const SongGroupIndex* m_songGroup = nullptr; /**< Quick access to song group project index */
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */ const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */ const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */
std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */ std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */ std::shared_ptr<Studio> m_studio; /**< Studio this sequencer outputs to */
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */ const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
SongState m_songState; /**< State of current arrangement playback */ SongState m_songState; /**< State of current arrangement playback */
double m_ticksPerSec = 1000.0; /**< Current ticks per second (tempo) for arrangement data */ double m_ticksPerSec = 1000.0; /**< Current ticks per second (tempo) for arrangement data */
SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */ SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */
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;
@@ -57,9 +63,9 @@ class Sequencer : public Entity
std::weak_ptr<Voice> m_lastVoice; std::weak_ptr<Voice> m_lastVoice;
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */ int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */ float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
int8_t m_curProgram = 0; /**< MIDI program number */ int8_t m_curProgram = 0; /**< MIDI program number */
float m_curVol = 1.f; /**< Current volume of channel */ float m_curVol = 1.f; /**< Current volume of channel */
float m_curPan = 0.f; /**< Current panning of channel */ float m_curPan = 0.f; /**< Current panning of channel */
void _bringOutYourDead(); void _bringOutYourDead();
size_t getVoiceCount() const; size_t getVoiceCount() const;
@@ -77,26 +83,26 @@ 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();
public: public:
~Sequencer(); ~Sequencer();
Sequencer(Engine& engine, const AudioGroup& group, int groupId, Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
const SongGroupIndex* songGroup, int setupId, Submix* smx); std::weak_ptr<Studio> studio);
Sequencer(Engine& engine, const AudioGroup& group, int groupId, Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
const SFXGroupIndex* sfxGroup, Submix* smx); std::weak_ptr<Studio> studio);
/** Advance current song data (if any) */ /** Advance current song data (if any) */
void advance(double dt); void advance(double dt);
/** Obtain pointer to Sequencer's Submix */ /** Obtain pointer to Sequencer's Submix */
Submix* getSubmix() {return m_submix;} std::shared_ptr<Studio> getStudio() { return m_studio; }
/** Get current state of sequencer */ /** Get current state of sequencer */
SequencerState state() const {return m_state;} SequencerState state() const { return m_state; }
/** Get number of active voices */ /** Get number of active voices */
size_t getVoiceCount() const; size_t getVoiceCount() const;
@@ -114,10 +120,10 @@ public:
void setPitchWheel(uint8_t chan, float pitchWheel); void setPitchWheel(uint8_t chan, float pitchWheel);
/** Send keyoffs to all active notes, silence immediately if `now` set */ /** Send keyoffs to all active notes, silence immediately if `now` set */
void allOff(bool now=false); void allOff(bool now = false);
/** Send keyoffs to all active notes on specified channel, silence immediately if `now` set */ /** Send keyoffs to all active notes on specified channel, silence immediately if `now` set */
void allOff(uint8_t chan, bool now=false); void allOff(uint8_t chan, bool now = false);
/** Stop all voices in `kg`, stops immediately (no KeyOff) when `now` set */ /** Stop all voices in `kg`, stops immediately (no KeyOff) when `now` set */
void killKeygroup(uint8_t kg, bool now); void killKeygroup(uint8_t kg, bool now);
@@ -132,13 +138,13 @@ public:
void setTempo(double ticksPerSec); void setTempo(double ticksPerSec);
/** Play MIDI arrangement */ /** Play MIDI arrangement */
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;
@@ -153,9 +159,8 @@ public:
void prevChanProgram(int8_t chanId); void prevChanProgram(int8_t chanId);
/** Manually kill sequencer for deferred release from engine */ /** Manually kill sequencer for deferred release from engine */
void kill() {m_state = SequencerState::Dead;} void kill() { m_state = SequencerState::Dead; }
}; };
} }
#endif // __AMUSE_SEQUENCER_HPP__ #endif // __AMUSE_SEQUENCER_HPP__

View File

@@ -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
{ {
@@ -13,7 +13,6 @@ public:
static std::vector<uint8_t> SongToMIDI(const unsigned char* data, int& versionOut, bool& isBig); static std::vector<uint8_t> SongToMIDI(const unsigned char* data, int& versionOut, bool& isBig);
static std::vector<uint8_t> MIDIToSong(const std::vector<uint8_t>& data, int version, bool big); static std::vector<uint8_t> MIDIToSong(const std::vector<uint8_t>& data, int version, bool big);
}; };
} }
#endif // __AMUSE_SONGCONVERTER_HPP__ #endif // __AMUSE_SONGCONVERTER_HPP__

View File

@@ -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
@@ -51,14 +50,14 @@ class SongState
/** Tempo change entry */ /** Tempo change entry */
struct TempoChange struct TempoChange
{ {
uint32_t m_tick; /**< Relative song ticks from previous tempo change */ uint32_t m_tick; /**< Relative song ticks from previous tempo change */
uint32_t m_tempo; /**< Tempo value in beats-per-minute (at 384 ticks per quarter-note) */ uint32_t m_tempo; /**< Tempo value in beats-per-minute (at 384 ticks per quarter-note) */
void swapBig(); void swapBig();
}; };
const unsigned char* m_songData = nullptr; /**< Base pointer to active song */ const unsigned char* m_songData = nullptr; /**< Base pointer to active song */
int m_sngVersion; /**< Detected song revision, 1 has RLE-compressed delta-times */ int m_sngVersion; /**< Detected song revision, 1 has RLE-compressed delta-times */
bool m_bigEndian; /**< True if loaded song is big-endian data */ bool m_bigEndian; /**< True if loaded song is big-endian data */
/** State of a single track within arrangement */ /** State of a single track within arrangement */
struct Track struct Track
@@ -71,38 +70,41 @@ 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 */
const unsigned char* m_data = nullptr; /**< Pointer to upcoming command data */ const unsigned char* m_data = nullptr; /**< Pointer to upcoming command data */
const unsigned char* m_pitchWheelData = nullptr; /**< Pointer to upcoming pitch data */ const unsigned char* m_pitchWheelData = nullptr; /**< Pointer to upcoming pitch data */
const unsigned char* m_modWheelData = nullptr; /**< Pointer to upcoming modulation data */ const unsigned char* m_modWheelData = nullptr; /**< Pointer to upcoming modulation data */
uint32_t m_lastPitchTick = 0; /**< Last position of pitch wheel change */ uint32_t m_lastPitchTick = 0; /**< Last position of pitch wheel change */
int32_t m_lastPitchVal = 0; /**< Last value of pitch */ int32_t m_lastPitchVal = 0; /**< Last value of pitch */
uint32_t m_lastModTick = 0; /**< Last position of mod wheel change */ uint32_t m_lastModTick = 0; /**< Last position of mod wheel change */
int32_t m_lastModVal = 0; /**< Last value of mod */ int32_t m_lastModVal = 0; /**< Last value of mod */
std::array<int, 128> m_remNoteLengths; /**< Remaining ticks per note */ std::array<int, 128> m_remNoteLengths; /**< Remaining ticks per note */
int32_t m_eventWaitCountdown = 0; /**< Current wait in ticks */ int32_t m_eventWaitCountdown = 0; /**< Current wait in ticks */
int32_t m_lastN64EventTick = 0; /**< Last command time on this channel (for computing delta times from absolute times in N64 songs) */ int32_t m_lastN64EventTick =
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 */
const TempoChange* m_tempoPtr = nullptr; const TempoChange* m_tempoPtr = nullptr;
uint32_t m_tempo = 120; /**< Current tempo (beats per minute) */ uint32_t m_tempo = 120; /**< Current tempo (beats per minute) */
uint32_t m_curTick = 0; /**< Current playback position for all channels */ uint32_t m_curTick = 0; /**< Current playback position for all channels */
SongPlayState m_songState = SongPlayState::Playing; /**< High-level state of Song playback */ SongPlayState m_songState = SongPlayState::Playing; /**< High-level state of Song playback */
double m_curDt = 0.f; /**< Cumulative dt value for time-remainder tracking */ double m_curDt = 0.f; /**< Cumulative dt value for time-remainder tracking */
public: public:
/** Determine SNG version /** Determine SNG version
@@ -119,9 +121,8 @@ public:
bool advance(Sequencer& seq, double dt); bool advance(Sequencer& seq, double dt);
/** Get current song tempo in BPM */ /** Get current song tempo in BPM */
uint32_t getTempo() const {return m_tempo;} uint32_t getTempo() const { return m_tempo; }
}; };
} }
#endif // __AMUSE_SONGSTATE_HPP__ #endif // __AMUSE_SONGSTATE_HPP__

View File

@@ -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
{ {
@@ -72,33 +77,33 @@ class SoundMacroState
SendMessage, SendMessage,
GetMessage, GetMessage,
GetVid, GetVid,
AddAgeCount = 0x30, AddAgeCount = 0x30, /* unimplemented */
SetAgeCount, SetAgeCount, /* unimplemented */
SendFlag, SendFlag, /* unimplemented */
PitchWheelR, PitchWheelR,
SetPriority, SetPriority = 0x36, /* unimplemented */
AddPriority, AddPriority, /* unimplemented */
AgeCntSpeed, AgeCntSpeed, /* unimplemented */
AgeCntVel, AgeCntVel, /* unimplemented */
VolSelect = 0x40, VolSelect = 0x40,
PanSelect, PanSelect,
PitchWheelSelect, PitchWheelSelect,
ModWheelSelect, ModWheelSelect,
PedalSelect, PedalSelect,
PortamentoSelect, PortamentoSelect,
ReverbSelect, ReverbSelect, /* serves as PostASelect */
SpanSelect, SpanSelect,
DopplerSelect, DopplerSelect,
TremoloSelect, TremoloSelect,
PreASelect, PreASelect,
PreBSelect, PreBSelect,
PostBSelect, PostBSelect,
AuxAFXSelect, AuxAFXSelect, /* unimplemented */
AuxBFXSelect, AuxBFXSelect, /* unimplemented */
SetupLFO = 0x50, SetupLFO = 0x50,
ModeSelect = 0x58, ModeSelect = 0x58,
SetKeygroup, SetKeygroup,
SRCmodeSelect, SRCmodeSelect, /* unimplemented */
AddVars = 0x60, AddVars = 0x60,
SubVars, SubVars,
MulVars, MulVars,
@@ -119,35 +124,46 @@ 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 */
uint8_t m_initKey; /**< Key played for this macro invocation */ uint8_t m_initKey; /**< Key played for this macro invocation */
uint8_t m_curVel; /**< Current velocity played for this macro invocation */ uint8_t m_curVel; /**< Current velocity played for this macro invocation */
uint8_t m_curMod; /**< Current modulation played for this macro invocation */ uint8_t m_curMod; /**< Current modulation played for this macro invocation */
uint32_t m_curPitch; /**< Current key played for this macro invocation (in cents) */ uint32_t m_curPitch; /**< Current key played for this macro invocation (in cents) */
double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */ double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */
bool m_keyoff; /**< keyoff message has been received */ bool m_keyoff; /**< keyoff message has been received */
bool m_sampleEnd; /**< sample has finished playback */ bool m_sampleEnd; /**< sample has finished playback */
bool m_inWait = false; /**< set when timer/keyoff/sampleend wait active */ bool m_inWait = false; /**< set when timer/keyoff/sampleend wait active */
bool m_indefiniteWait = false; /**< set when timer wait is indefinite (keyoff/sampleend only) */ bool m_indefiniteWait = false; /**< set when timer wait is indefinite (keyoff/sampleend only) */
bool m_keyoffWait = false; /**< set when active wait is a keyoff wait */ bool m_keyoffWait = false; /**< set when active wait is a keyoff wait */
bool m_sampleEndWait = false; /**< set when active wait is a sampleend wait */ bool m_sampleEndWait = false; /**< set when active wait is a sampleend wait */
double m_waitCountdown; /**< countdown timer for active wait */ double m_waitCountdown; /**< countdown timer for active wait */
int m_loopCountdown = -1; /**< countdown for current loop */ int m_loopCountdown = -1; /**< countdown for current loop */
int m_lastPlayMacroVid = -1; /**< VoiceId from last PlayMacro command */ int m_lastPlayMacroVid = -1; /**< VoiceId from last PlayMacro command */
bool m_useAdsrControllers; /**< when set, use the following controllers for envelope times */ bool m_useAdsrControllers; /**< when set, use the following controllers for envelope times */
uint8_t m_midiAttack; /**< Attack MIDI controller */ uint8_t m_midiAttack; /**< Attack MIDI controller */
uint8_t m_midiDecay; /**< Decay MIDI controller */ uint8_t m_midiDecay; /**< Decay MIDI controller */
uint8_t m_midiSustain; /**< Sustain MIDI controller */ uint8_t m_midiSustain; /**< Sustain MIDI controller */
uint8_t m_midiRelease; /**< Release MIDI controller */ uint8_t m_midiRelease; /**< Release MIDI controller */
uint8_t m_portamentoMode = 2; /**< (0: Off, 1: On, 2: MIDI specified) */ uint8_t m_portamentoMode = 2; /**< (0: Off, 1: On, 2: MIDI specified) */
uint8_t m_portamentoType = 0; /**< (0: New key pressed while old key pressed, 1: Always) */ uint8_t m_portamentoType = 0; /**< (0: New key pressed while old key pressed, 1: Always) */
float m_portamentoTime = 0.5f; /**< portamento transition time, 0.f will perform legato */ float m_portamentoTime = 0.5f; /**< portamento transition time, 0.f will perform legato */
/** Used to build a multi-component formula for overriding controllers */ /** Used to build a multi-component formula for overriding controllers */
@@ -174,19 +190,20 @@ class SoundMacroState
VarType m_varType; VarType m_varType;
Component(uint8_t midiCtrl, float scale, Combine combine, VarType varType) Component(uint8_t midiCtrl, float scale, Combine combine, VarType varType)
: m_midiCtrl(midiCtrl), m_scale(scale), m_combine(combine), m_varType(varType) {} : m_midiCtrl(midiCtrl), m_scale(scale), m_combine(combine), m_varType(varType)
{
}
}; };
std::vector<Component> m_comps; /**< Components built up by the macro */ std::vector<Component> m_comps; /**< Components built up by the macro */
/** Combine additional component(s) to formula */ /** Combine additional component(s) to formula */
void addComponent(uint8_t midiCtrl, float scale, void addComponent(uint8_t midiCtrl, float scale, Combine combine, VarType varType);
Combine combine, VarType varType);
/** Calculate value */ /** Calculate value */
float evaluate(const Voice& vox, const SoundMacroState& st) const; float evaluate(double time, const Voice& vox, const SoundMacroState& st) const;
/** Determine if able to use */ /** Determine if able to use */
operator bool() const {return m_comps.size() != 0;} operator bool() const { return m_comps.size() != 0; }
}; };
Evaluator m_volumeSel; Evaluator m_volumeSel;
@@ -217,8 +234,8 @@ class SoundMacroState
public: public:
/** initialize state for SoundMacro data at `ptr` */ /** initialize state for SoundMacro data at `ptr` */
void initialize(const unsigned char* ptr, int step, bool swapData); void initialize(const unsigned char* ptr, int step, bool swapData);
void initialize(const unsigned char* ptr, int step, double ticksPerSec, void initialize(const unsigned char* ptr, int step, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool swapData); uint8_t midiMod, bool swapData);
/** advances `dt` seconds worth of commands in the SoundMacro /** advances `dt` seconds worth of commands in the SoundMacro
* @return `true` if END reached * @return `true` if END reached
@@ -231,7 +248,6 @@ public:
/** sample end event */ /** sample end event */
void sampleEndNotify(Voice& vox); void sampleEndNotify(Voice& vox);
}; };
} }
#endif // __AMUSE_SOUNDMACROSTATE_HPP__ #endif // __AMUSE_SOUNDMACROSTATE_HPP__

54
include/amuse/Studio.hpp Normal file
View File

@@ -0,0 +1,54 @@
#ifndef __AMUSE_STUDIO_HPP__
#define __AMUSE_STUDIO_HPP__
#include <memory>
#include <list>
#include "Entity.hpp"
#include "Voice.hpp"
#include "Submix.hpp"
#include <type_traits>
namespace amuse
{
class Studio
{
friend class Engine;
Engine& m_engine;
Submix m_master;
Submix m_auxA;
Submix m_auxB;
struct StudioSend
{
std::shared_ptr<Studio> m_targetStudio;
float m_dryLevel;
float m_auxALevel;
float m_auxBLevel;
StudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
: m_targetStudio(studio), m_dryLevel(dry), m_auxALevel(auxA), m_auxBLevel(auxB)
{
}
};
std::list<StudioSend> m_studiosOut;
#ifndef NDEBUG
bool _cyclicCheck(Studio* leaf);
#endif
public:
Studio(Engine& engine, bool mainOut);
/** Register a target Studio to send this Studio's mixing busses */
void addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB);
/** Advise submixes of changing sample rate */
void resetOutputSampleRate(double sampleRate);
Submix& getMaster() { return m_master; }
Submix& getAuxA() { return m_auxA; }
Submix& getAuxB() { return m_auxB; }
Engine& getEngine() { return m_engine; }
};
}
#endif // __AMUSE_STUDIO_HPP__

View File

@@ -23,27 +23,14 @@ class Submix
friend class Voice; friend class Voice;
friend class Sequencer; friend class Sequencer;
Engine& m_root; Engine& m_root;
Submix* m_submix = nullptr; /**< Parent submix of this submix (or NULL if mixing to main output) */ std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */ std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */
bool m_destroyed = false;
void _destroy();
public: public:
Submix(Engine& engine, Submix* smx); Submix(Engine& engine);
~Submix()
{
#ifndef NDEBUG
/* Ensure proper destruction procedure followed */
assert(m_destroyed);
#endif
}
/** Obtain pointer to Submix's parent Submix */
Submix* getParentSubmix() {return m_submix;}
/** Add new effect to effect stack and assume ownership */ /** Add new effect to effect stack and assume ownership */
template <class T, class ...Args> template <class T, class... Args>
T& makeEffect(Args... args) T& makeEffect(Args... args)
{ {
switch (m_backendSubmix->getSampleFormat()) switch (m_backendSubmix->getSampleFormat())
@@ -73,22 +60,33 @@ 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, EffectReverbStd& makeReverbStd(float coloration, float mix, float time, float damping, float preDelay);
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, EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
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(); }
/** Returns true when an effect callback is bound */ /** Returns true when an effect callback is bound */
bool canApplyEffect() const {return m_effectStack.size() != 0;} bool canApplyEffect() const { return m_effectStack.size() != 0; }
/** in/out transformation entry for audio effect */ /** in/out transformation entry for audio effect */
void applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const; void applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const;
@@ -102,9 +100,8 @@ public:
/** advice effects of changing sample rate */ /** advice effects of changing sample rate */
void resetOutputSampleRate(double sampleRate); void resetOutputSampleRate(double sampleRate);
Engine& getEngine() {return m_root;} Engine& getEngine() { return m_root; }
}; };
} }
#endif // __AMUSE_SUBMIX_HPP__ #endif // __AMUSE_SUBMIX_HPP__

View File

@@ -1,25 +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__

View File

@@ -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"
@@ -14,7 +14,7 @@
namespace amuse namespace amuse
{ {
class IBackendVoice; class IBackendVoice;
class Submix; class Studio;
struct Keymap; struct Keymap;
struct LayerMapping; struct LayerMapping;
@@ -22,8 +22,8 @@ struct LayerMapping;
enum class VoiceState enum class VoiceState
{ {
Playing, /**< SoundMacro actively executing, not in KeyOff */ Playing, /**< SoundMacro actively executing, not in KeyOff */
KeyOff, /**< KeyOff event issued, macro beginning fade-out */ KeyOff, /**< KeyOff event issued, macro beginning fade-out */
Dead /**< Default state, causes Engine to remove voice at end of pump cycle */ Dead /**< Default state, causes Engine to remove voice at end of pump cycle */
}; };
/** Individual source of audio */ /** Individual source of audio */
@@ -33,111 +33,123 @@ class Voice : public Entity
friend class Sequencer; friend class Sequencer;
friend class SoundMacroState; friend class SoundMacroState;
friend class Envelope; friend class Envelope;
int m_vid; /**< VoiceID of this voice instance */ friend class Emitter;
bool m_emitter; /**< Voice is part of an Emitter */ int m_vid; /**< VoiceID of this voice instance */
Submix* m_submix = nullptr; /**< Submix this voice outputs to (or NULL for the main output mix) */ bool m_emitter; /**< Voice is part of an Emitter */
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */ std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
SoundMacroState m_state; /**< State container for SoundMacro playback */ SoundMacroState m_state; /**< State container for SoundMacro playback */
SoundMacroState::EventTrap m_keyoffTrap; /**< Trap for keyoff (SoundMacro overrides default envelope behavior) */ SoundMacroState::EventTrap m_keyoffTrap; /**< Trap for keyoff (SoundMacro overrides default envelope behavior) */
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */ SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */ SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
std::list<int32_t> m_messageQueue; /**< Messages pending processing for SoundMacros in this voice */ std::list<int32_t> m_messageQueue; /**< Messages pending processing for SoundMacros in this voice */
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */ std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */ uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
enum class SampleFormat : uint8_t enum class SampleFormat : uint8_t
{ {
DSP, /**< GCN DSP-ucode ADPCM (very common for GameCube games) */ DSP, /**< GCN DSP-ucode ADPCM (very common for GameCube games) */
DSP_DRUM, /**< GCN DSP-ucode ADPCM (seems to be set into drum samples for expanding their amplitude appropriately) */ DSP_DRUM, /**< GCN DSP-ucode ADPCM (seems to be set into drum samples for expanding their amplitude
appropriately) */
PCM, /**< Big-endian PCM found in MusyX2 demo GM instruments */ PCM, /**< Big-endian PCM found in MusyX2 demo GM instruments */
N64, /**< 2-stage VADPCM coding with SAMP-embedded codebooks */ N64, /**< 2-stage VADPCM coding with SAMP-embedded codebooks */
PCM_PC /**< Little-endian PCM found in PC Rogue Squadron (actually enum 0 which conflicts with DSP-ADPCM) */ PCM_PC /**< Little-endian PCM found in PC Rogue Squadron (actually enum 0 which conflicts with DSP-ADPCM) */
}; };
const Sample* m_curSample = nullptr; /**< Current sample entry playing */ const Sample* m_curSample = nullptr; /**< Current sample entry playing */
const unsigned char* m_curSampleData = nullptr; /**< Current sample data playing */ const unsigned char* m_curSampleData = nullptr; /**< Current sample data playing */
SampleFormat m_curFormat; /**< Current sample format playing */ SampleFormat m_curFormat; /**< Current sample format playing */
uint32_t m_curSamplePos = 0; /**< Current sample position */ uint32_t m_curSamplePos = 0; /**< Current sample position */
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_voiceTime = 0.0; /**< Current seconds of voice playback (per-sample resolution) */ double m_sampleRate = NativeSampleRate; /**< Current sample rate computed from relative sample key or SETPITCH */
uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */ double m_voiceTime = 0.0; /**< Current seconds of voice playback (per-sample resolution) */
float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */ uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */
float m_nextLevel = 0.f; /**< Next computed level used for lerp-mode amplitude */ float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */
float m_nextLevel = 0.f; /**< Next computed level used for lerp-mode amplitude */
VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */ VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */
bool m_sustained = false; /**< Sustain pedal pressed for this voice */ bool m_sustained = false; /**< Sustain pedal pressed for this voice */
bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */ bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */
uint8_t m_curAftertouch = 0; /**< Aftertouch value (key pressure when 'bottoming out') */ uint8_t m_curAftertouch = 0; /**< Aftertouch value (key pressure when 'bottoming out') */
float m_targetUserVol = 1.f; /**< Target user volume of voice (slewed to prevent audible aliasing) */ float m_targetUserVol = 1.f; /**< Target user volume of voice (slewed to prevent audible aliasing) */
float m_curUserVol = 1.f; /**< Current user volume of voice */ float m_curUserVol = 1.f; /**< Current user volume of voice */
float m_curVol = 1.f; /**< Current volume of voice */ float m_curVol = 1.f; /**< Current volume of voice */
float m_curReverbVol = 0.f; /**< Current reverb volume of voice */ float m_curReverbVol = 0.f; /**< Current reverb volume of voice */
float m_userPan = 0.f; /**< User pan of voice */ float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
float m_curPan = 0.f; /**< Current pan of voice */ float m_userPan = 0.f; /**< User pan of voice */
float m_userSpan = 0.f; /**< User span of voice */ float m_curPan = 0.f; /**< Current pan of voice */
float m_curSpan = 0.f; /**< Current surround pan of voice */ float m_userSpan = -1.f; /**< User span of voice */
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */ float m_curSpan = -1.f; /**< Current surround pan of voice */
int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */ 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_pitchWheelDown = 600; /**< Down range for pitchwheel control in cents */ int32_t m_pitchWheelDown = 600; /**< Down range for pitchwheel control in cents */
int32_t m_pitchWheelVal = 0; /**< Current resolved pitchwheel delta for control */ int32_t m_pitchWheelVal = 0; /**< Current resolved pitchwheel delta for control */
int32_t m_curPitch; /**< Current base pitch in cents */ int32_t m_curPitch; /**< Current base pitch in cents */
bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */ bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */
bool m_needsSlew = false; /**< next _setTotalPitch will be slewed */
Envelope m_volAdsr; /**< Volume envelope */ Envelope m_volAdsr; /**< Volume envelope */
double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */ double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */
double m_envelopeDur; /**< requested duration of last ENVELOPE command */ double m_envelopeDur; /**< requested duration of last ENVELOPE command */
float m_envelopeStart; /**< initial value for last ENVELOPE command */ float m_envelopeStart; /**< initial value for last ENVELOPE command */
float m_envelopeEnd; /**< final value for last ENVELOPE command */ float m_envelopeEnd; /**< final value for last ENVELOPE command */
const Curve* m_envelopeCurve; /**< curve to use for ENVELOPE command */ const Curve* m_envelopeCurve; /**< curve to use for ENVELOPE command */
bool m_pitchEnv = false; /**< Pitch envelope activated */ bool m_pitchEnv = false; /**< Pitch envelope activated */
Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */ Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */
int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */ int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */
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 */
uint8_t m_pitchSweep2Times = 0; /**< Remaining times to advance PITCHSWEEP2 controller */ uint8_t m_pitchSweep2Times = 0; /**< Remaining times to advance PITCHSWEEP2 controller */
uint8_t m_pitchSweep1It = 0; /**< Current iteration of PITCHSWEEP1 controller */ uint8_t m_pitchSweep1It = 0; /**< Current iteration of PITCHSWEEP1 controller */
uint8_t m_pitchSweep2It = 0; /**< Current iteration of PITCHSWEEP2 controller */ uint8_t m_pitchSweep2It = 0; /**< Current iteration of PITCHSWEEP2 controller */
float m_panningTime = -1.f; /**< time since last PANNING command, -1 for no active pan-sweep */ float m_panningTime = -1.f; /**< time since last PANNING command, -1 for no active pan-sweep */
float m_panningDur; /**< requested duration of last PANNING command */ float m_panningDur; /**< requested duration of last PANNING command */
uint8_t m_panPos; /**< initial pan value of last PANNING command */ uint8_t m_panPos; /**< initial pan value of last PANNING command */
int8_t m_panWidth; /**< delta pan value to target of last PANNING command */ int8_t m_panWidth; /**< delta pan value to target of last PANNING command */
float m_spanningTime = -1.f; /**< time since last SPANNING command, -1 for no active span-sweep */ float m_spanningTime = -1.f; /**< time since last SPANNING command, -1 for no active span-sweep */
float m_spanningDur; /**< requested duration of last SPANNING command */ float m_spanningDur; /**< requested duration of last SPANNING command */
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 */
int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */ float m_vibratoTime = -1.f; /**< time since last VIBRATO command, -1 for no active vibrato */
int32_t m_vibratoModLevel = 0; /**< scale of vibrato mod-wheel influence (in cents) */ int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */
float m_vibratoPeriod = 0.f; /**< vibrato wave period-time, 0.f will disable vibrato */ 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 */
bool m_vibratoModWheel = false; /**< vibrato scaled with mod-wheel if set */ bool m_vibratoModWheel = false; /**< vibrato scaled with mod-wheel if set */
float m_tremoloScale = 0.f; /**< minimum volume factor produced via LFO */ float m_tremoloScale = 0.f; /**< minimum volume factor produced via LFO */
float m_tremoloModScale = 0.f; /**< minimum volume factor produced via LFO, scaled via mod wheel */ float m_tremoloModScale = 0.f; /**< minimum volume factor produced via LFO, scaled via mod wheel */
float m_lfoPeriods[2] = {}; /**< time-periods for LFO1 and LFO2 */ float m_lfoPeriods[2] = {}; /**< time-periods for LFO1 and LFO2 */
std::unique_ptr<int8_t[]> m_ctrlValsSelf; /**< Self-owned MIDI Controller values */ std::unique_ptr<int8_t[]> m_ctrlValsSelf; /**< Self-owned MIDI Controller values */
int8_t* m_extCtrlVals = nullptr; /**< MIDI Controller values (external storage) */ int8_t* m_extCtrlVals = nullptr; /**< MIDI Controller values (external storage) */
void _destroy(); void _destroy();
bool _checkSamplePos(bool& looped); bool _checkSamplePos(bool& looped);
void _doKeyOff(); void _doKeyOff();
void _macroKeyOff(); void _macroKeyOff();
void _macroSampleEnd(); void _macroSampleEnd();
bool _advanceSample(int16_t& samp, int32_t& curPitch); void _procSamplePre(int16_t& samp);
template <typename T>
T _procSampleMaster(double time, T samp);
template <typename T>
T _procSampleAuxA(double time, T samp);
template <typename T>
T _procSampleAuxB(double time, T samp);
void _setTotalPitch(int32_t cents, bool slew); void _setTotalPitch(int32_t cents, bool slew);
bool _isRecursivelyDead(); bool _isRecursivelyDead();
void _bringOutYourDead(); void _bringOutYourDead();
@@ -148,36 +160,50 @@ class Voice : public Entity
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch); std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
bool _loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec, bool _loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec, uint8_t midiKey,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc=false); uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
bool _loadKeymap(const Keymap* keymap, int macroStep, double ticksPerSec, bool _loadKeymap(const Keymap* keymap, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc=false); uint8_t midiMod, bool pushPc = false);
bool _loadLayer(const std::vector<const LayerMapping*>& layer, int macroStep, double ticksPerSec, bool _loadLayer(const std::vector<const LayerMapping*>& layer, int macroStep, double ticksPerSec, uint8_t midiKey,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc=false); uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
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);
public: public:
~Voice(); ~Voice();
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, Submix* smx); Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, std::weak_ptr<Studio> studio);
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, Submix* smx); Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
std::weak_ptr<Studio> studio);
/** Called before each supplyAudio invocation to prepare voice
* backend for possible parameter updates */
void preSupplyAudio(double dt);
/** Request specified count of audio frames (samples) from voice, /** Request specified count of audio frames (samples) from voice,
* internally advancing the voice stream */ * internally advancing the voice stream */
size_t supplyAudio(size_t frames, int16_t* data); size_t supplyAudio(size_t frames, int16_t* data);
/** Obtain pointer to Voice's Submix */ /** Called three times after resampling supplyAudio output, voice should
Submix* getSubmix() {return m_submix;} * perform volume processing / send routing for each aux bus and master */
void routeAudio(size_t frames, 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, double dt, int busId, float* in, float* out);
/** Obtain pointer to Voice's Studio */
std::shared_ptr<Studio> getStudio() { return m_studio; }
/** Get current state of voice */ /** Get current state of voice */
VoiceState state() const {return m_voxState;} VoiceState state() const { return m_voxState; }
/** Get VoiceId of this voice (unique to all currently-playing voices) */ /** Get VoiceId of this voice (unique to all currently-playing voices) */
int vid() const {return m_vid;} int vid() const { return m_vid; }
/** Get max VoiceId of this voice and any contained children */ /** Get max VoiceId of this voice and any contained children */
int maxVid() const; int maxVid() const;
@@ -186,9 +212,8 @@ public:
std::shared_ptr<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep); std::shared_ptr<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep);
/** Load specified Sound Object from within group into voice */ /** Load specified Sound Object from within group into voice */
bool loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, bool loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, uint8_t midiMod, bool pushPc = false);
bool pushPc=false);
/** Signals voice to begin fade-out (or defer if sustained), eventually reaching silence */ /** Signals voice to begin fade-out (or defer if sustained), eventually reaching silence */
void keyOff(); void keyOff();
@@ -211,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);
@@ -233,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);
@@ -242,10 +270,10 @@ public:
void setTremolo(float tremoloScale, float tremoloModScale); void setTremolo(float tremoloScale, float tremoloModScale);
/** Setup LFO1 for voice */ /** Setup LFO1 for voice */
void setLFO1Period(float period) {m_lfoPeriods[0] = period;} void setLFO1Period(float period) { m_lfoPeriods[0] = period; }
/** Setup LFO2 for voice */ /** Setup LFO2 for voice */
void setLFO2Period(float period) {m_lfoPeriods[1] = period;} void setLFO2Period(float period) { m_lfoPeriods[1] = period; }
/** Setup pitch sweep controller 1 */ /** Setup pitch sweep controller 1 */
void setPitchSweep1(uint8_t times, int16_t add); void setPitchSweep1(uint8_t times, int16_t add);
@@ -256,6 +284,9 @@ public:
/** Set reverb mix for voice */ /** Set reverb mix for voice */
void setReverbVol(float rvol); void setReverbVol(float rvol);
/** Set AuxB volume for voice */
void setAuxBVol(float bvol);
/** Set envelope for voice */ /** Set envelope for voice */
void setAdsr(ObjectId adsrId, bool dls); void setAdsr(ObjectId adsrId, bool dls);
@@ -275,10 +306,10 @@ public:
void setAftertouch(uint8_t aftertouch); void setAftertouch(uint8_t aftertouch);
/** Assign voice to keygroup for coordinated mass-silencing */ /** Assign voice to keygroup for coordinated mass-silencing */
void setKeygroup(uint8_t kg) {m_keygroup = kg;} void setKeygroup(uint8_t kg) { m_keygroup = kg; }
/** Get note played on voice */ /** Get note played on voice */
uint8_t getLastNote() const {return m_state.m_initKey;} uint8_t getLastNote() const { return m_state.m_initKey; }
/** Do portamento glide; returns `false` if portamento disabled */ /** Do portamento glide; returns `false` if portamento disabled */
bool doPortamento(uint8_t newNote); bool doPortamento(uint8_t newNote);
@@ -289,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];
@@ -316,19 +347,17 @@ public:
} }
/** Get MIDI pitch wheel value on voice */ /** Get MIDI pitch wheel value on voice */
float getPitchWheel() const {return m_curPitchWheel;} float getPitchWheel() const { return m_curPitchWheel; }
/** Get MIDI aftertouch value on voice */ /** Get MIDI aftertouch value on voice */
int8_t getAftertouch() const {return m_curAftertouch;} int8_t getAftertouch() const { return m_curAftertouch; }
/** Get count of all voices in hierarchy, including this one */ /** Get count of all voices in hierarchy, including this one */
size_t getTotalVoices() const; size_t getTotalVoices() const;
/** Recursively mark voice as dead for Engine to deallocate on next cycle */ /** Recursively mark voice as dead for Engine to deallocate on next cycle */
void kill(); void kill();
}; };
} }
#endif // __AMUSE_VOICE_HPP__ #endif // __AMUSE_VOICE_HPP__

View File

@@ -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"

View File

@@ -5,28 +5,31 @@ namespace amuse
{ {
AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag) AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
: m_proj(data.getProj(), GCNDataTag{}), : m_proj(data.getProj(), GCNDataTag{})
m_pool(data.getPool()), , m_pool(data.getPool())
m_sdir(data.getSdir(), GCNDataTag{}), , m_sdir(data.getSdir(), GCNDataTag{})
m_samp(data.getSamp()), , m_samp(data.getSamp())
m_fmt(DataFormat::GCN) , m_fmt(DataFormat::GCN)
{} {
}
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag) AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
: m_proj(data.getProj(), absOffs, N64DataTag{}), : m_proj(data.getProj(), absOffs, N64DataTag{})
m_pool(data.getPool()), , m_pool(data.getPool())
m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{}), , m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{})
m_samp(data.getSamp()), , m_samp(data.getSamp())
m_fmt(DataFormat::N64) , m_fmt(DataFormat::N64)
{} {
}
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag) AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
: m_proj(data.getProj(), absOffs, PCDataTag{}), : m_proj(data.getProj(), absOffs, PCDataTag{})
m_pool(data.getPool(), PCDataTag{}), , m_pool(data.getPool(), PCDataTag{})
m_sdir(data.getSdir(), absOffs, PCDataTag{}), , m_sdir(data.getSdir(), absOffs, PCDataTag{})
m_samp(data.getSamp()), , m_samp(data.getSamp())
m_fmt(DataFormat::PC) , m_fmt(DataFormat::PC)
{} {
}
const Sample* AudioGroup::getSample(int sfxId) const const Sample* AudioGroup::getSample(int sfxId) const
{ {
@@ -36,9 +39,5 @@ const Sample* AudioGroup::getSample(int sfxId) const
return &search->second; return &search->second;
} }
const unsigned char* AudioGroup::getSampleData(uint32_t offset) const const unsigned char* AudioGroup::getSampleData(uint32_t offset) const { return m_samp + offset; }
{
return m_samp + offset;
}
} }

View File

@@ -14,16 +14,15 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
} }
} }
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other) IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other) noexcept
: AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz, : AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz, other.m_sdir, other.m_sdirSz, other.m_samp,
other.m_sdir, other.m_sdirSz, other.m_samp, other.m_sampSz, other.m_sampSz, other.m_fmt, other.m_absOffs)
other.m_fmt, other.m_absOffs)
{ {
m_owns = other.m_owns; m_owns = other.m_owns;
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)
{ {
@@ -45,5 +44,4 @@ IntrusiveAudioGroupData& IntrusiveAudioGroupData::operator=(IntrusiveAudioGroupD
return *this; return *this;
} }
} }

View File

@@ -70,10 +70,10 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4)); ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
std::vector<const LayerMapping*>& mappingsOut = m_layers[id]; std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
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;
@@ -130,10 +130,10 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data, PCDataTag)
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4); ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
std::vector<const LayerMapping*>& mappingsOut = m_layers[id]; std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
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;
@@ -172,5 +172,4 @@ const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
return nullptr; return nullptr;
return reinterpret_cast<const ADSR*>(search->second); return reinterpret_cast<const ADSR*>(search->second);
} }
} }

View File

@@ -96,7 +96,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, GCNDataTag)
idx.m_sfxEntries.reserve(count); idx.m_sfxEntries.reserve(count);
const SFXGroupIndex::SFXEntry* entries = const SFXGroupIndex::SFXEntry* entries =
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(data + header.pageTableOff + 4); reinterpret_cast<const SFXGroupIndex::SFXEntry*>(data + header.pageTableOff + 4);
for (int i=0 ; i<count ; ++i) for (int i = 0; i < count; ++i)
{ {
idx.m_sfxEntries[SBig(entries->defineId)] = entries; idx.m_sfxEntries[SBig(entries->defineId)] = entries;
++entries; ++entries;
@@ -152,7 +152,7 @@ struct MusyX1MIDISetup
} }
}; };
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag) void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataTag)
{ {
size_t normPageCount = 0; size_t normPageCount = 0;
size_t drumPageCount = 0; size_t drumPageCount = 0;
@@ -161,7 +161,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data); const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff) while (group->groupEndOff != 0xffffffff)
{ {
const unsigned char* subData = absOffs ? data : data + 8; const unsigned char* subData = data + 8;
GroupHeader header = *group; GroupHeader header = *group;
header.swapBig(); header.swapBig();
@@ -187,20 +187,16 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
/* MIDI setups */ /* MIDI setups */
const uint8_t* setupData = subData + header.midiSetupsOff; const uint8_t* setupData = subData + header.midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff) const uint8_t* setupEnd = subData + header.groupEndOff;
while (setupData < setupEnd)
{ {
++midiSetupCount; ++midiSetupCount;
setupData += 8 * 16 + 4; setupData += 8 * 16 + 4;
} }
} }
if (absOffs) data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff); group = reinterpret_cast<const GroupHeader*>(data);
else
{
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
} }
if (normPageCount) if (normPageCount)
@@ -208,12 +204,13 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
if (drumPageCount) if (drumPageCount)
m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]); m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]);
if (midiSetupCount) if (midiSetupCount)
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[midiSetupCount]); m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[ midiSetupCount ]);
} }
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag) AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag)
{ {
_allocateConvBuffers(data, absOffs, N64DataTag{}); if (!absOffs)
_allocateConvBuffers(data, N64DataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get(); SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get(); SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get(); std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@@ -232,42 +229,77 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N6
SongGroupIndex& idx = m_songGroups[header.groupId]; SongGroupIndex& idx = m_songGroups[header.groupId];
bIdx = &idx; bIdx = &idx;
/* Normal pages */ if (absOffs)
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
while (normEntries->objId != 0xffff)
{ {
normEntries->setIntoMusyX2(*normPagesBuf); /* Normal pages */
idx.m_normPages[normEntries->programNo] = normPagesBuf; const SongGroupIndex::PageEntry* normEntries =
++normEntries; reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.pageTableOff);
++normPagesBuf; while (normEntries->objId != 0xffff)
{
idx.m_normPages[normEntries->programNo] = normEntries;
++normEntries;
}
/* Drum pages */
const SongGroupIndex::PageEntry* drumEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.drumTableOff);
while (drumEntries->objId != 0xffff)
{
idx.m_drumPages[drumEntries->programNo] = drumEntries;
++drumEntries;
}
/* MIDI setups */
const uint8_t* setupData = data + header.midiSetupsOff;
const uint8_t* setupEnd = data + header.groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
idx.m_midiSetups[songId] =
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
setupData += 5 * 16 + 4;
}
} }
else
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
while (drumEntries->objId != 0xffff)
{ {
drumEntries->setIntoMusyX2(*drumPagesBuf); /* Normal pages */
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf; const MusyX1PageEntry* normEntries =
++drumEntries; reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
++drumPagesBuf; while (normEntries->objId != 0xffff)
} {
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
}
/* MIDI setups */ /* Drum pages */
const uint8_t* setupData = subData + header.midiSetupsOff; const MusyX1PageEntry* drumEntries =
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff) reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
{ while (drumEntries->objId != 0xffff)
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData)); {
const std::array<MusyX1MIDISetup, 16>* midiSetups = drumEntries->setIntoMusyX2(*drumPagesBuf);
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4); idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
for (int i=0 ; i<16 ; ++i) /* MIDI setups */
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]); const uint8_t* setupData = subData + header.midiSetupsOff;
const uint8_t* setupEnd = subData + header.groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
idx.m_midiSetups[songId] = midiSetupsBuf; for (int i = 0; i < 16; ++i)
setupData += 8 * 16 + 4; (*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
++midiSetupsBuf;
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
}
} }
} }
else if (header.type == GroupType::SFX) else if (header.type == GroupType::SFX)
@@ -278,7 +310,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N6
/* SFX entries */ /* SFX entries */
uint16_t count = SBig(*reinterpret_cast<const uint16_t*>(subData + header.pageTableOff)); uint16_t count = SBig(*reinterpret_cast<const uint16_t*>(subData + header.pageTableOff));
idx.m_sfxEntries.reserve(count); idx.m_sfxEntries.reserve(count);
for (int i=0 ; i<count ; ++i) for (int i = 0; i < count; ++i)
{ {
const SFXGroupIndex::SFXEntry* entries = const SFXGroupIndex::SFXEntry* entries =
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + header.pageTableOff + 4 + i * 12); reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + header.pageTableOff + 4 + i * 12);
@@ -304,7 +336,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N6
} }
} }
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag) void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTag)
{ {
size_t normPageCount = 0; size_t normPageCount = 0;
size_t drumPageCount = 0; size_t drumPageCount = 0;
@@ -313,13 +345,13 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data); const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff) while (group->groupEndOff != 0xffffffff)
{ {
const unsigned char* subData = absOffs ? data : data + 8; const unsigned char* subData = data + 8;
if (group->type == GroupType::Song) if (group->type == GroupType::Song)
{ {
/* Normal pages */ /* Normal pages */
const MusyX1PageEntry* normEntries = const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff); reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
while (normEntries->objId != 0xffff) while (normEntries->objId != 0xffff)
{ {
++normPageCount; ++normPageCount;
@@ -328,7 +360,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
/* Drum pages */ /* Drum pages */
const MusyX1PageEntry* drumEntries = const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff); reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
while (drumEntries->objId != 0xffff) while (drumEntries->objId != 0xffff)
{ {
++drumPageCount; ++drumPageCount;
@@ -337,20 +369,16 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
/* MIDI setups */ /* MIDI setups */
const uint8_t* setupData = subData + group->midiSetupsOff; const uint8_t* setupData = subData + group->midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff) const uint8_t* setupEnd = subData + group->groupEndOff;
while (setupData < setupEnd)
{ {
++midiSetupCount; ++midiSetupCount;
setupData += 8 * 16 + 4; setupData += 8 * 16 + 4;
} }
} }
if (absOffs) data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data + group->groupEndOff); group = reinterpret_cast<const GroupHeader*>(data);
else
{
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
} }
if (normPageCount) if (normPageCount)
@@ -358,12 +386,13 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
if (drumPageCount) if (drumPageCount)
m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]); m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]);
if (midiSetupCount) if (midiSetupCount)
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[midiSetupCount]); m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[ midiSetupCount ]);
} }
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag) AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag)
{ {
_allocateConvBuffers(data, absOffs, PCDataTag{}); if (!absOffs)
_allocateConvBuffers(data, PCDataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get(); SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get(); SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get(); std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@@ -380,42 +409,77 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PC
SongGroupIndex& idx = m_songGroups[group->groupId]; SongGroupIndex& idx = m_songGroups[group->groupId];
bIdx = &idx; bIdx = &idx;
/* Normal pages */ if (absOffs)
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
while (normEntries->objId != 0xffff)
{ {
normEntries->setIntoMusyX2(*normPagesBuf); /* Normal pages */
idx.m_normPages[normEntries->programNo] = normPagesBuf; const SongGroupIndex::PageEntry* normEntries =
++normEntries; reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->pageTableOff);
++normPagesBuf; while (normEntries->objId != 0xffff)
{
idx.m_normPages[normEntries->programNo] = normEntries;
++normEntries;
}
/* Drum pages */
const SongGroupIndex::PageEntry* drumEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->drumTableOff);
while (drumEntries->objId != 0xffff)
{
idx.m_drumPages[drumEntries->programNo] = drumEntries;
++drumEntries;
}
/* MIDI setups */
const uint8_t* setupData = data + group->midiSetupsOff;
const uint8_t* setupEnd = data + group->groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
idx.m_midiSetups[songId] =
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
setupData += 5 * 16 + 4;
}
} }
else
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
while (drumEntries->objId != 0xffff)
{ {
drumEntries->setIntoMusyX2(*drumPagesBuf); /* Normal pages */
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf; const MusyX1PageEntry* normEntries =
++drumEntries; reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
++drumPagesBuf; while (normEntries->objId != 0xffff)
} {
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
}
/* MIDI setups */ /* Drum pages */
const uint8_t* setupData = subData + group->midiSetupsOff; const MusyX1PageEntry* drumEntries =
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff) reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
{ while (drumEntries->objId != 0xffff)
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData); {
const std::array<MusyX1MIDISetup, 16>* midiSetups = drumEntries->setIntoMusyX2(*drumPagesBuf);
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4); idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
for (int i=0 ; i<16 ; ++i) /* MIDI setups */
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]); const uint8_t* setupData = subData + group->midiSetupsOff;
const uint8_t* setupEnd = subData + group->groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
idx.m_midiSetups[songId] = midiSetupsBuf; for (int i = 0; i < 16; ++i)
setupData += 8 * 16 + 4; (*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
++midiSetupsBuf;
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
}
} }
} }
else if (group->type == GroupType::SFX) else if (group->type == GroupType::SFX)
@@ -426,10 +490,10 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PC
/* SFX entries */ /* SFX entries */
uint16_t count = *reinterpret_cast<const uint16_t*>(subData + group->pageTableOff); uint16_t count = *reinterpret_cast<const uint16_t*>(subData + group->pageTableOff);
idx.m_sfxEntries.reserve(count); idx.m_sfxEntries.reserve(count);
for (int i=0 ; i<count ; ++i) for (int i = 0; i < count; ++i)
{ {
const SFXGroupIndex::SFXEntry* entries = const SFXGroupIndex::SFXEntry* entries =
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + group->pageTableOff + 4 + i * 12); reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + group->pageTableOff + 4 + i * 12);
idx.m_sfxEntries[entries->defineId] = entries; idx.m_sfxEntries[entries->defineId] = entries;
} }
} }
@@ -481,5 +545,4 @@ const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
return nullptr; return nullptr;
return &search->second; return &search->second;
} }
} }

View File

@@ -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
{ {
@@ -22,7 +22,7 @@ void AudioGroupSampleDirectory::ADPCMParms::swapBigDSP()
dsp.m_bytesPerFrame = SBig(dsp.m_bytesPerFrame); dsp.m_bytesPerFrame = SBig(dsp.m_bytesPerFrame);
dsp.m_hist2 = SBig(dsp.m_hist2); dsp.m_hist2 = SBig(dsp.m_hist2);
dsp.m_hist1 = SBig(dsp.m_hist1); dsp.m_hist1 = SBig(dsp.m_hist1);
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
dsp.m_coefs[i][0] = SBig(dsp.m_coefs[i][0]); dsp.m_coefs[i][0] = SBig(dsp.m_coefs[i][0]);
dsp.m_coefs[i][1] = SBig(dsp.m_coefs[i][1]); dsp.m_coefs[i][1] = SBig(dsp.m_coefs[i][1]);
@@ -32,7 +32,7 @@ void AudioGroupSampleDirectory::ADPCMParms::swapBigDSP()
void AudioGroupSampleDirectory::ADPCMParms::swapBigVADPCM() void AudioGroupSampleDirectory::ADPCMParms::swapBigVADPCM()
{ {
int16_t* allCoefs = reinterpret_cast<int16_t*>(vadpcm.m_coefs[0][0]); int16_t* allCoefs = reinterpret_cast<int16_t*>(vadpcm.m_coefs[0][0]);
for (int i=0 ; i<128 ; ++i) for (int i = 0; i < 128; ++i)
allCoefs[i] = SBig(allCoefs[i]); allCoefs[i] = SBig(allCoefs[i]);
} }
@@ -41,8 +41,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
const unsigned char* cur = data; const unsigned char* cur = data;
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff) while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{ {
const AudioGroupSampleDirectory::Entry* ent = const AudioGroupSampleDirectory::Entry* ent = reinterpret_cast<const AudioGroupSampleDirectory::Entry*>(cur);
reinterpret_cast<const AudioGroupSampleDirectory::Entry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[SBig(ent->m_sfxId)]; std::pair<Entry, ADPCMParms>& store = m_entries[SBig(ent->m_sfxId)];
store.first = *ent; store.first = *ent;
@@ -51,8 +50,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
if (store.first.m_adpcmParmOffset) if (store.first.m_adpcmParmOffset)
{ {
const AudioGroupSampleDirectory::ADPCMParms* adpcm = const AudioGroupSampleDirectory::ADPCMParms* adpcm =
reinterpret_cast<const AudioGroupSampleDirectory::ADPCMParms*>(data + reinterpret_cast<const AudioGroupSampleDirectory::ADPCMParms*>(data + store.first.m_adpcmParmOffset);
store.first.m_adpcmParmOffset);
store.second.dsp = adpcm->dsp; store.second.dsp = adpcm->dsp;
store.second.swapBigDSP(); store.second.swapBigDSP();
} }
@@ -129,8 +127,7 @@ struct MusyX1AbsSdirEntry
} }
}; };
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData,
const unsigned char* sampData,
bool absOffs, N64DataTag) bool absOffs, N64DataTag)
{ {
const unsigned char* cur = data; const unsigned char* cur = data;
@@ -169,8 +166,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
} }
} }
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag)
bool absOffs, PCDataTag)
{ {
const unsigned char* cur = data; const unsigned char* cur = data;
@@ -199,5 +195,4 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
} }
} }
} }
} }

View File

@@ -6,73 +6,68 @@
namespace amuse namespace amuse
{ {
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&, void BooBackendVoice::VoiceCallback::preSupplyAudio(boo::IAudioVoice&, double dt)
size_t frames, int16_t* data) {
m_parent.m_clientVox.preSupplyAudio(dt);
}
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&, size_t frames, int16_t* data)
{ {
return m_parent.m_clientVox.supplyAudio(frames, data); return m_parent.m_clientVox.supplyAudio(frames, data);
} }
BooBackendVoice::BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out)
double sampleRate, bool dynamicPitch)
: m_clientVox(clientVox), m_cb(*this),
m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
{}
BooBackendVoice::BooBackendVoice(boo::IAudioSubmix& submix, Voice& clientVox,
double sampleRate, bool dynamicPitch)
: m_clientVox(clientVox), m_cb(*this),
m_booVoice(submix.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
{}
void BooBackendVoice::resetSampleRate(double sampleRate)
{ {
m_booVoice->resetSampleRate(sampleRate); m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
} }
void BooBackendVoice::setMatrixCoefficients(const float coefs[8], bool slew) void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out)
{ {
m_booVoice->setMonoMatrixCoefficients(coefs, slew); m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
} }
void BooBackendVoice::setSubmixMatrixCoefficients(const float coefs[8], bool slew) void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out)
{ {
m_booVoice->setMonoSubmixMatrixCoefficients(coefs, slew); m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
} }
void BooBackendVoice::setPitchRatio(double ratio, bool slew) BooBackendVoice::BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch)
: m_clientVox(clientVox), m_cb(*this), m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
{ {
m_booVoice->setPitchRatio(ratio, slew);
} }
void BooBackendVoice::start() void BooBackendVoice::resetSampleRate(double sampleRate) { m_booVoice->resetSampleRate(sampleRate); }
void BooBackendVoice::resetChannelLevels() { m_booVoice->resetChannelLevels(); }
void BooBackendVoice::setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew)
{ {
m_booVoice->start(); BooBackendSubmix& smx = *reinterpret_cast<BooBackendSubmix*>(submix);
m_booVoice->setMonoChannelLevels(smx.m_booSubmix.get(), coefs, slew);
} }
void BooBackendVoice::stop() void BooBackendVoice::setPitchRatio(double ratio, bool slew) { m_booVoice->setPitchRatio(ratio, slew); }
{
m_booVoice->stop();
}
bool BooBackendSubmix::SubmixCallback::canApplyEffect() const void BooBackendVoice::start() { m_booVoice->start(); }
{
return m_parent.m_clientSmx.canApplyEffect();
}
void BooBackendSubmix::SubmixCallback::applyEffect(int16_t* audio, size_t frameCount, void BooBackendVoice::stop() { m_booVoice->stop(); }
const boo::ChannelMap& chanMap, double) const
bool BooBackendSubmix::SubmixCallback::canApplyEffect() const { return m_parent.m_clientSmx.canApplyEffect(); }
void BooBackendSubmix::SubmixCallback::applyEffect(int16_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
double) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap)); return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
} }
void BooBackendSubmix::SubmixCallback::applyEffect(int32_t* audio, size_t frameCount, void BooBackendSubmix::SubmixCallback::applyEffect(int32_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
const boo::ChannelMap& chanMap, double) const double) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap)); return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
} }
void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, size_t frameCount, void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, size_t frameCount, const boo::ChannelMap& chanMap,
const boo::ChannelMap& chanMap, double) const double) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap)); return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
} }
@@ -82,40 +77,22 @@ void BooBackendSubmix::SubmixCallback::resetOutputSampleRate(double sampleRate)
m_parent.m_clientSmx.resetOutputSampleRate(sampleRate); m_parent.m_clientSmx.resetOutputSampleRate(sampleRate);
} }
BooBackendSubmix::BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx) BooBackendSubmix::BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId)
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(engine.allocateNewSubmix(&m_cb)) : m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(engine.allocateNewSubmix(mainOut, &m_cb, busId))
{}
BooBackendSubmix::BooBackendSubmix(boo::IAudioSubmix& parent, Submix& clientSmx)
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(parent.allocateNewSubmix(&m_cb))
{}
void BooBackendSubmix::setChannelGains(const float gains[8])
{ {
m_booSubmix->setChannelGains(gains);
} }
std::unique_ptr<IBackendVoice> void BooBackendSubmix::setSendLevel(IBackendSubmix* submix, float level, bool slew)
BooBackendSubmix::allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)
{ {
return std::make_unique<BooBackendVoice>(*m_booSubmix, clientVox, sampleRate, dynamicPitch); BooBackendSubmix& smx = *reinterpret_cast<BooBackendSubmix*>(submix);
m_booSubmix->setSendLevel(smx.m_booSubmix.get(), level, slew);
} }
double BooBackendSubmix::getSampleRate() const double BooBackendSubmix::getSampleRate() const { return m_booSubmix->getSampleRate(); }
{
return m_booSubmix->getSampleRate();
}
SubmixFormat BooBackendSubmix::getSampleFormat() const SubmixFormat BooBackendSubmix::getSampleFormat() const { return SubmixFormat(m_booSubmix->getSampleFormat()); }
{
return SubmixFormat(m_booSubmix->getSampleFormat());
}
std::string BooBackendMIDIReader::description() { return m_midiIn->description(); }
std::string BooBackendMIDIReader::description()
{
return m_midiIn->description();
}
BooBackendMIDIReader::~BooBackendMIDIReader() {} BooBackendMIDIReader::~BooBackendMIDIReader() {}
@@ -128,25 +105,25 @@ BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name, boo
auto devices = voxAlloc.m_booEngine.enumerateMIDIDevices(); auto devices = voxAlloc.m_booEngine.enumerateMIDIDevices();
for (const auto& dev : devices) for (const auto& dev : devices)
{ {
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(dev.first.c_str(), m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(
std::bind(&BooBackendMIDIReader::_MIDIReceive, this, dev.first.c_str(),
std::placeholders::_1, std::placeholders::_2)); std::bind(&BooBackendMIDIReader::_MIDIReceive, this, std::placeholders::_1, std::placeholders::_2));
if (m_midiIn) if (m_midiIn)
return; return;
} }
m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(std::bind(&BooBackendMIDIReader::_MIDIReceive, this, m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(
std::placeholders::_1, std::placeholders::_2)); std::bind(&BooBackendMIDIReader::_MIDIReceive, this, std::placeholders::_1, std::placeholders::_2));
} }
else else
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(name, m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(
std::bind(&BooBackendMIDIReader::_MIDIReceive, this, name, std::bind(&BooBackendMIDIReader::_MIDIReceive, this, std::placeholders::_1, std::placeholders::_2));
std::placeholders::_1, std::placeholders::_2));
} }
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes, double time) void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes, double time)
{ {
std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{}); std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{});
if (m_useLock) lk.lock(); if (m_useLock)
lk.lock();
m_queue.emplace_back(time, std::move(bytes)); m_queue.emplace_back(time, std::move(bytes));
#if 0 #if 0
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON); openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
@@ -160,14 +137,15 @@ void BooBackendMIDIReader::pumpReader(double dt)
dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */ dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */
std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{}); std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{});
if (m_useLock) lk.lock(); if (m_useLock)
lk.lock();
if (m_queue.empty()) if (m_queue.empty())
return; return;
/* Determine range of buffer updates within this period */ /* Determine range of buffer updates within this period */
auto periodEnd = m_queue.cbegin(); auto periodEnd = m_queue.cbegin();
double startPt = m_queue.front().first; double startPt = m_queue.front().first;
for (; periodEnd != m_queue.cend() ; ++periodEnd) for (; periodEnd != m_queue.cend(); ++periodEnd)
{ {
double delta = periodEnd->first - startPt; double delta = periodEnd->first - startPt;
if (delta > dt) if (delta > dt)
@@ -178,7 +156,7 @@ void BooBackendMIDIReader::pumpReader(double dt)
return; return;
/* Dispatch buffers */ /* Dispatch buffers */
for (auto it = m_queue.begin() ; it != periodEnd ;) for (auto it = m_queue.begin(); it != periodEnd;)
{ {
#if 0 #if 0
char str[64]; char str[64];
@@ -216,9 +194,7 @@ void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
#endif #endif
} }
void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/) void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/) {}
{
}
void BooBackendMIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value) void BooBackendMIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
{ {
@@ -232,9 +208,7 @@ void BooBackendMIDIReader::programChange(uint8_t chan, uint8_t program)
seq->setChanProgram(chan, program); seq->setChanProgram(chan, program);
} }
void BooBackendMIDIReader::channelPressure(uint8_t /*chan*/, uint8_t /*pressure*/) void BooBackendMIDIReader::channelPressure(uint8_t /*chan*/, uint8_t /*pressure*/) {}
{
}
void BooBackendMIDIReader::pitchBend(uint8_t chan, int16_t pitch) void BooBackendMIDIReader::pitchBend(uint8_t chan, int16_t pitch)
{ {
@@ -242,20 +216,15 @@ void BooBackendMIDIReader::pitchBend(uint8_t chan, int16_t pitch)
seq->setPitchWheel(chan, (pitch - 0x2000) / float(0x2000)); seq->setPitchWheel(chan, (pitch - 0x2000) / float(0x2000));
} }
void BooBackendMIDIReader::allSoundOff(uint8_t chan) void BooBackendMIDIReader::allSoundOff(uint8_t chan)
{ {
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers()) for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
seq->allOff(chan, true); seq->allOff(chan, true);
} }
void BooBackendMIDIReader::resetAllControllers(uint8_t /*chan*/) void BooBackendMIDIReader::resetAllControllers(uint8_t /*chan*/) {}
{
}
void BooBackendMIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) void BooBackendMIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
{
}
void BooBackendMIDIReader::allNotesOff(uint8_t chan) void BooBackendMIDIReader::allNotesOff(uint8_t chan)
{ {
@@ -263,67 +232,43 @@ void BooBackendMIDIReader::allNotesOff(uint8_t chan)
seq->allOff(chan, false); seq->allOff(chan, false);
} }
void BooBackendMIDIReader::omniMode(uint8_t /*chan*/, bool /*on*/) void BooBackendMIDIReader::omniMode(uint8_t /*chan*/, bool /*on*/) {}
{
}
void BooBackendMIDIReader::polyMode(uint8_t /*chan*/, bool /*on*/) void BooBackendMIDIReader::polyMode(uint8_t /*chan*/, bool /*on*/) {}
{
}
void BooBackendMIDIReader::sysex(const void* /*data*/, size_t /*len*/) {}
void BooBackendMIDIReader::sysex(const void* /*data*/, size_t /*len*/) void BooBackendMIDIReader::timeCodeQuarterFrame(uint8_t /*message*/, uint8_t /*value*/) {}
{
}
void BooBackendMIDIReader::timeCodeQuarterFrame(uint8_t /*message*/, uint8_t /*value*/) void BooBackendMIDIReader::songPositionPointer(uint16_t /*pointer*/) {}
{
}
void BooBackendMIDIReader::songPositionPointer(uint16_t /*pointer*/) void BooBackendMIDIReader::songSelect(uint8_t /*song*/) {}
{
}
void BooBackendMIDIReader::songSelect(uint8_t /*song*/) void BooBackendMIDIReader::tuneRequest() {}
{
}
void BooBackendMIDIReader::tuneRequest() void BooBackendMIDIReader::startSeq() {}
{
}
void BooBackendMIDIReader::continueSeq() {}
void BooBackendMIDIReader::startSeq() void BooBackendMIDIReader::stopSeq() {}
{
}
void BooBackendMIDIReader::continueSeq()
{
}
void BooBackendMIDIReader::stopSeq()
{
}
void BooBackendMIDIReader::reset()
{
}
void BooBackendMIDIReader::reset() {}
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
: m_booEngine(booEngine) : m_booEngine(booEngine)
{} {
booEngine.setCallbackInterface(this);
}
std::unique_ptr<IBackendVoice> std::unique_ptr<IBackendVoice> BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate,
BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch) bool dynamicPitch)
{ {
return std::make_unique<BooBackendVoice>(m_booEngine, clientVox, sampleRate, dynamicPitch); return std::make_unique<BooBackendVoice>(m_booEngine, clientVox, sampleRate, dynamicPitch);
} }
std::unique_ptr<IBackendSubmix> BooBackendVoiceAllocator::allocateSubmix(Submix& clientSmx) std::unique_ptr<IBackendSubmix> BooBackendVoiceAllocator::allocateSubmix(Submix& clientSmx, bool mainOut, int busId)
{ {
return std::make_unique<BooBackendSubmix>(m_booEngine, clientSmx); return std::make_unique<BooBackendSubmix>(m_booEngine, clientSmx, mainOut, busId);
} }
std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enumerateMIDIDevices() std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enumerateMIDIDevices()
@@ -339,19 +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() AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); }
void BooBackendVoiceAllocator::setVolume(float vol) { m_booEngine.setVolume(vol); }
void BooBackendVoiceAllocator::on5MsInterval(boo::IAudioVoiceEngine& engine, double dt)
{ {
return AudioChannelSet(m_booEngine.getAvailableSet()); if (m_cbInterface)
m_cbInterface->_on5MsInterval(*this, dt);
} }
void BooBackendVoiceAllocator::pumpAndMixVoices() void BooBackendVoiceAllocator::onPumpCycleComplete(boo::IAudioVoiceEngine& engine)
{ {
m_booEngine.pumpAndMixVoices(); if (m_cbInterface)
m_cbInterface->_onPumpCycleComplete(*this);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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]:

View File

@@ -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
@@ -8,11 +8,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#endif #endif
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif #endif
#include <map> #include <map>
@@ -22,11 +22,10 @@
namespace amuse namespace amuse
{ {
DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode, DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, bool noHidden)
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
@@ -61,7 +60,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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:
@@ -75,16 +74,17 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue; continue;
SystemString fp(path); SystemString fp(path);
fp +=_S('/'); fp += _S('/');
fp += d.cFileName; fp += d.cFileName;
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -115,11 +115,12 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -140,11 +141,12 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -158,7 +160,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
#else #else
DIR* dir = opendir(path); DIR* dir = opendir(path.data());
if (!dir) if (!dir)
return; return;
const dirent* d; const dirent* d;
@@ -187,7 +189,7 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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:
@@ -206,11 +208,12 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -240,11 +243,12 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -265,11 +269,12 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
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));
else else
for (auto& e : sort) for (auto& e : sort)
@@ -283,5 +288,4 @@ DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
#endif #endif
} }
} }

View File

View File

@@ -1,153 +1,155 @@
#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
{ {
/* 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 */
EffectChorus::EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period) EffectChorus::EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period)
: x90_baseDelay(clamp(5u, baseDelay, 15u)), : x90_baseDelay(clamp(5u, baseDelay, 15u))
x94_variation(clamp(0u, variation, 5u)), , x94_variation(clamp(0u, variation, 5u))
x98_period(clamp(500u, period, 10000u)) , x98_period(clamp(500u, period, 10000u))
{} {
}
template <typename T> template <typename T>
EffectChorusImp<T>::EffectChorusImp(uint32_t baseDelay, uint32_t variation, EffectChorusImp<T>::EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate)
uint32_t period, double sampleRate)
: EffectChorus(baseDelay, variation, period) : EffectChorus(baseDelay, variation, period)
{ {
_setup(sampleRate); _setup(sampleRate);
@@ -165,8 +167,8 @@ void EffectChorusImp<T>::_setup(double sampleRate)
memset(buf, 0, m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8 * sizeof(T)); memset(buf, 0, m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8 * sizeof(T));
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS; size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
for (int c=0 ; c<8 ; ++c) for (int c = 0; c < 8; ++c)
for (int i=0 ; i<AMUSE_CHORUS_NUM_BLOCKS ; ++i) for (int i = 0; i < AMUSE_CHORUS_NUM_BLOCKS; ++i)
x0_lastChans[c][i] = buf + chanPitch * c + m_blockSamples * i; x0_lastChans[c][i] = buf + chanPitch * c + m_blockSamples * i;
x6c_src.x88_trigger = chanPitch; x6c_src.x88_trigger = chanPitch;
@@ -207,7 +209,7 @@ void EffectChorusImp<T>::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount)
float cur = x70_smpBase[x7c_posHi]; float cur = x70_smpBase[x7c_posHi];
T* dest = x6c_dest; T* dest = x6c_dest;
for (size_t i=0 ; i<blockSamples ; ++i) for (size_t i = 0; i < blockSamples; ++i)
{ {
const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc]; const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc];
@@ -248,7 +250,7 @@ void EffectChorusImp<T>::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount)
float cur = x70_smpBase[x7c_posHi]; float cur = x70_smpBase[x7c_posHi];
T* dest = x6c_dest; T* dest = x6c_dest;
for (size_t i=0 ; i<blockSamples ; ++i) for (size_t i = 0; i < blockSamples; ++i)
{ {
const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc]; const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc];
++x7c_posHi; ++x7c_posHi;
@@ -305,25 +307,18 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
_update(); _update();
size_t remFrames = frameCount; size_t remFrames = frameCount;
for (size_t f=0 ; f<frameCount ;) for (size_t f = 0; f < frameCount;)
{ {
uint8_t next = x24_currentLast + 1; uint8_t next = x24_currentLast + 1;
uint8_t buf = next % 3; uint8_t buf = next % 3;
T* bufs[8] = T* bufs[8] = {
{ x0_lastChans[0][buf], x0_lastChans[1][buf], x0_lastChans[2][buf], x0_lastChans[3][buf],
x0_lastChans[0][buf], x0_lastChans[4][buf], x0_lastChans[5][buf], x0_lastChans[6][buf], x0_lastChans[7][buf],
x0_lastChans[1][buf],
x0_lastChans[2][buf],
x0_lastChans[3][buf],
x0_lastChans[4][buf],
x0_lastChans[5][buf],
x0_lastChans[6][buf],
x0_lastChans[7][buf],
}; };
T* inBuf = audio; T* inBuf = audio;
for (size_t s=0 ; f<frameCount && s<m_blockSamples ; ++s, ++f) for (size_t s = 0; f < frameCount && s < m_blockSamples; ++s, ++f)
for (size_t c=0 ; c<chanMap.m_channelCount && c<8 ; ++c) for (size_t c = 0; c < chanMap.m_channelCount && c < 8; ++c)
*bufs[c]++ = *inBuf++; *bufs[c]++ = *inBuf++;
x6c_src.x84_pitchHi = (x60_pitchOffset >> 16) + 1; x6c_src.x84_pitchHi = (x60_pitchOffset >> 16) + 1;
@@ -338,7 +333,7 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
T* outBuf = audio; T* outBuf = audio;
size_t bs = std::min(remFrames, size_t(m_blockSamples)); size_t bs = std::min(remFrames, size_t(m_blockSamples));
for (size_t c=0 ; c<chanMap.m_channelCount && c<8 ; ++c) for (size_t c = 0; c < chanMap.m_channelCount && c < 8; ++c)
{ {
x6c_src.x7c_posHi = x5c_currentPosHi; x6c_src.x7c_posHi = x5c_currentPosHi;
x6c_src.x78_posLo = x58_currentPosLo; x6c_src.x78_posLo = x58_currentPosLo;
@@ -355,7 +350,8 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
case 1: case 1:
x6c_src.doSrc2(bs, chanMap.m_channelCount); x6c_src.doSrc2(bs, chanMap.m_channelCount);
break; break;
default: break; default:
break;
} }
} }
@@ -374,5 +370,4 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
template class EffectChorusImp<int16_t>; template class EffectChorusImp<int16_t>;
template class EffectChorusImp<int32_t>; template class EffectChorusImp<int32_t>;
template class EffectChorusImp<float>; template class EffectChorusImp<float>;
} }

View File

@@ -1,21 +1,20 @@
#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
{ {
template <typename T> template <typename T>
EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate)
uint32_t initOutput, double sampleRate)
{ {
initDelay = clamp(10u, initDelay, 5000u); initDelay = clamp(10u, initDelay, 5000u);
initFeedback = clamp(0u, initFeedback, 100u); initFeedback = clamp(0u, initFeedback, 100u);
initOutput = clamp(0u, initOutput, 100u); initOutput = clamp(0u, initOutput, 100u);
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x3c_delay[i] = initDelay; x3c_delay[i] = initDelay;
x48_feedback[i] = initFeedback; x48_feedback[i] = initFeedback;
@@ -25,6 +24,19 @@ EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback,
_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)
{ {
@@ -37,7 +49,7 @@ void EffectDelayImp<T>::_setup(double sampleRate)
template <typename T> template <typename T>
void EffectDelayImp<T>::_update() void EffectDelayImp<T>::_update()
{ {
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x0_currentSize[i] = ((x3c_delay[i] - 5) * m_sampsPerMs + 159) / 160; x0_currentSize[i] = ((x3c_delay[i] - 5) * m_sampsPerMs + 159) / 160;
xc_currentPos[i] = 0; xc_currentPos[i] = 0;
@@ -57,12 +69,12 @@ void EffectDelayImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMa
if (m_dirty) if (m_dirty)
_update(); _update();
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];
@@ -78,5 +90,4 @@ void EffectDelayImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMa
template class EffectDelayImp<int16_t>; template class EffectDelayImp<int16_t>;
template class EffectDelayImp<int32_t>; template class EffectDelayImp<int32_t>;
template class EffectDelayImp<float>; template class EffectDelayImp<float>;
} }

View File

@@ -1,11 +1,13 @@
#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
{ {
/* clang-format off */
/* Comb-filter delays */ /* Comb-filter delays */
static const size_t CTapDelays[] = static const size_t CTapDelays[] =
{ {
@@ -34,6 +36,8 @@ static const size_t LPTapDelays[] =
73 73
}; };
/* clang-format on */
void ReverbDelayLine::allocate(int32_t delay) void ReverbDelayLine::allocate(int32_t delay)
{ {
delay += 2; delay += 2;
@@ -53,24 +57,23 @@ void ReverbDelayLine::setdelay(int32_t delay)
x4_outPoint += x8_length; x4_outPoint += x8_length;
} }
EffectReverbStd::EffectReverbStd(float coloration, float mix, float time, EffectReverbStd::EffectReverbStd(float coloration, float mix, float time, float damping, float preDelay)
float damping, float preDelay) : x140_x1c8_coloration(clamp(0.f, coloration, 1.f))
: x140_x1c8_coloration(clamp(0.f, coloration, 1.f)), , x144_x1cc_mix(clamp(0.f, mix, 1.f))
x144_x1cc_mix(clamp(0.f, mix, 1.f)), , x148_x1d0_time(clamp(0.01f, time, 10.f))
x148_x1d0_time(clamp(0.01f, time, 10.f)), , x14c_x1d4_damping(clamp(0.f, damping, 1.f))
x14c_x1d4_damping(clamp(0.f, damping, 1.f)), , x150_x1d8_preDelay(clamp(0.f, preDelay, 0.1f))
x150_x1d8_preDelay(clamp(0.f, preDelay, 0.1f)) {
{} }
EffectReverbHi::EffectReverbHi(float coloration, float mix, float time, EffectReverbHi::EffectReverbHi(float coloration, float mix, float time, float damping, float preDelay, float crosstalk)
float damping, float preDelay, float crosstalk) : EffectReverbStd(coloration, mix, time, damping, preDelay), x1dc_crosstalk(clamp(0.f, crosstalk, 1.0f))
: EffectReverbStd(coloration, mix, time, damping, preDelay), {
x1dc_crosstalk(clamp(0.f, crosstalk, 1.0f)) }
{}
template <typename T> template <typename T>
EffectReverbStdImp<T>::EffectReverbStdImp(float coloration, float mix, float time, EffectReverbStdImp<T>::EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay,
float damping, float preDelay, double sampleRate) double sampleRate)
: EffectReverbStd(coloration, mix, time, damping, preDelay) : EffectReverbStd(coloration, mix, time, damping, preDelay)
{ {
_setup(sampleRate); _setup(sampleRate);
@@ -87,21 +90,22 @@ 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;
for (int c=0 ; c<8 ; ++c) double rateRatio = m_sampleRate / NativeSampleRate;
for (int c = 0; c < 8; ++c)
{ {
for (int t=0 ; t<2 ; ++t) for (int t = 0; t < 2; ++t)
{ {
ReverbDelayLine& combLine = x78_C[c][t]; ReverbDelayLine& combLine = x78_C[c][t];
size_t tapDelay = CTapDelays[t] * m_sampleRate / 32000.0; size_t tapDelay = CTapDelays[t] * rateRatio;
combLine.allocate(tapDelay); combLine.allocate(tapDelay);
combLine.setdelay(tapDelay); combLine.setdelay(tapDelay);
xf4_combCoef[c][t] = std::pow(10.f, tapDelay * -3.f / timeSamples); xf4_combCoef[c][t] = std::pow(10.f, tapDelay * -3.f / timeSamples);
} }
for (int t=0 ; t<2 ; ++t) for (int t = 0; t < 2; ++t)
{ {
ReverbDelayLine& allPassLine = x0_AP[c][t]; ReverbDelayLine& allPassLine = x0_AP[c][t];
size_t tapDelay = APTapDelays[t] * m_sampleRate / 32000.0; size_t tapDelay = APTapDelays[t] * rateRatio;
allPassLine.allocate(tapDelay); allPassLine.allocate(tapDelay);
allPassLine.setdelay(tapDelay); allPassLine.setdelay(tapDelay);
} }
@@ -119,7 +123,7 @@ void EffectReverbStdImp<T>::_update()
if (x150_x1d8_preDelay != 0.f) if (x150_x1d8_preDelay != 0.f)
{ {
x120_preDelayTime = m_sampleRate * x150_x1d8_preDelay; x120_preDelayTime = m_sampleRate * x150_x1d8_preDelay;
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x124_preDelayLine[i].reset(new float[x120_preDelayTime]); x124_preDelayLine[i].reset(new float[x120_preDelayTime]);
memset(x124_preDelayLine[i].get(), 0, x120_preDelayTime * sizeof(float)); memset(x124_preDelayLine[i].get(), 0, x120_preDelayTime * sizeof(float));
@@ -129,7 +133,7 @@ void EffectReverbStdImp<T>::_update()
else else
{ {
x120_preDelayTime = 0; x120_preDelayTime = 0;
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x124_preDelayLine[i] = nullptr; x124_preDelayLine[i] = nullptr;
x130_preDelayPtr[i] = nullptr; x130_preDelayPtr[i] = nullptr;
@@ -148,9 +152,9 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
float dampWet = x118_level * 0.6f; float dampWet = x118_level * 0.6f;
float dampDry = 0.6f - dampWet; float dampDry = 0.6f - dampWet;
for (size_t f=0 ; f<frameCount ; f+=160) for (size_t f = 0; f < frameCount; f += 160)
{ {
for (unsigned c=0 ; c<chanMap.m_channelCount ; ++c) for (unsigned c = 0; c < chanMap.m_channelCount; ++c)
{ {
float* combCoefs = xf4_combCoef[c]; float* combCoefs = xf4_combCoef[c];
float& lpLastOut = x10c_lpLastout[c]; float& lpLastOut = x10c_lpLastout[c];
@@ -162,7 +166,7 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
ReverbDelayLine* linesAP = x0_AP[c]; ReverbDelayLine* linesAP = x0_AP[c];
int procSamples = std::min(size_t(160), frameCount - f); int procSamples = std::min(size_t(160), frameCount - f);
for (int s=0 ; s<procSamples ; ++s) for (int s = 0; s < procSamples; ++s)
{ {
float sample = audio[s * chanMap.m_channelCount + c]; float sample = audio[s * chanMap.m_channelCount + c];
@@ -205,8 +209,8 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
/* All-pass filter stage */ /* All-pass filter stage */
linesAP[0].xc_inputs[linesAP[0].x0_inPoint] = linesAP[0].xc_inputs[linesAP[0].x0_inPoint] =
xf0_allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput; xf0_allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput;
float lowPass = -(xf0_allPassCoef * linesAP[0].xc_inputs[linesAP[0].x0_inPoint] - float lowPass =
linesAP[0].x10_lastInput); -(xf0_allPassCoef * linesAP[0].xc_inputs[linesAP[0].x0_inPoint] - linesAP[0].x10_lastInput);
linesAP[0].x0_inPoint += 1; linesAP[0].x0_inPoint += 1;
linesAP[0].x10_lastInput = linesAP[0].xc_inputs[linesAP[0].x4_outPoint]; linesAP[0].x10_lastInput = linesAP[0].xc_inputs[linesAP[0].x4_outPoint];
@@ -220,8 +224,8 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
lpLastOut = x11c_damping * lpLastOut + lowPass * 0.3f; lpLastOut = x11c_damping * lpLastOut + lowPass * 0.3f;
linesAP[1].xc_inputs[linesAP[1].x0_inPoint] = xf0_allPassCoef * linesAP[1].x10_lastInput + lpLastOut; linesAP[1].xc_inputs[linesAP[1].x0_inPoint] = xf0_allPassCoef * linesAP[1].x10_lastInput + lpLastOut;
float allPass = -(xf0_allPassCoef * linesAP[1].xc_inputs[linesAP[1].x0_inPoint] - float allPass =
linesAP[1].x10_lastInput); -(xf0_allPassCoef * linesAP[1].xc_inputs[linesAP[1].x0_inPoint] - linesAP[1].x10_lastInput);
linesAP[1].x0_inPoint += 1; linesAP[1].x0_inPoint += 1;
linesAP[1].x10_lastInput = linesAP[1].xc_inputs[linesAP[1].x4_outPoint]; linesAP[1].x10_lastInput = linesAP[1].xc_inputs[linesAP[1].x4_outPoint];
@@ -243,9 +247,8 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
} }
template <typename T> template <typename T>
EffectReverbHiImp<T>::EffectReverbHiImp(float coloration, float mix, float time, EffectReverbHiImp<T>::EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay,
float damping, float preDelay, float crosstalk, float crosstalk, double sampleRate)
double sampleRate)
: EffectReverbHi(coloration, mix, time, damping, preDelay, crosstalk) : EffectReverbHi(coloration, mix, time, damping, preDelay, crosstalk)
{ {
_setup(sampleRate); _setup(sampleRate);
@@ -262,27 +265,28 @@ 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;
for (int c=0 ; c<8 ; ++c) double rateRatio = m_sampleRate / NativeSampleRate;
for (int c = 0; c < 8; ++c)
{ {
for (int t=0 ; t<3 ; ++t) for (int t = 0; t < 3; ++t)
{ {
ReverbDelayLine& combLine = xb4_C[c][t]; ReverbDelayLine& combLine = xb4_C[c][t];
size_t tapDelay = CTapDelays[t] * m_sampleRate / 32000.0; size_t tapDelay = CTapDelays[t] * rateRatio;
combLine.allocate(tapDelay); combLine.allocate(tapDelay);
combLine.setdelay(tapDelay); combLine.setdelay(tapDelay);
x16c_combCoef[c][t] = std::pow(10.f, tapDelay * -3.f / timeSamples); x16c_combCoef[c][t] = std::pow(10.f, tapDelay * -3.f / timeSamples);
} }
for (int t=0 ; t<2 ; ++t) for (int t = 0; t < 2; ++t)
{ {
ReverbDelayLine& allPassLine = x0_AP[c][t]; ReverbDelayLine& allPassLine = x0_AP[c][t];
size_t tapDelay = APTapDelays[t] * m_sampleRate / 32000.0; size_t tapDelay = APTapDelays[t] * rateRatio;
allPassLine.allocate(tapDelay); allPassLine.allocate(tapDelay);
allPassLine.setdelay(tapDelay); allPassLine.setdelay(tapDelay);
} }
ReverbDelayLine& lpLine = x78_LP[c]; ReverbDelayLine& lpLine = x78_LP[c];
size_t tapDelay = LPTapDelays[c] * m_sampleRate / 32000.0; size_t tapDelay = LPTapDelays[c] * rateRatio;
lpLine.allocate(tapDelay); lpLine.allocate(tapDelay);
lpLine.setdelay(tapDelay); lpLine.setdelay(tapDelay);
} }
@@ -299,7 +303,7 @@ void EffectReverbHiImp<T>::_update()
if (x150_x1d8_preDelay != 0.f) if (x150_x1d8_preDelay != 0.f)
{ {
x1a4_preDelayTime = m_sampleRate * x150_x1d8_preDelay; x1a4_preDelayTime = m_sampleRate * x150_x1d8_preDelay;
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x1ac_preDelayLine[i].reset(new float[x1a4_preDelayTime]); x1ac_preDelayLine[i].reset(new float[x1a4_preDelayTime]);
memset(x1ac_preDelayLine[i].get(), 0, x1a4_preDelayTime * sizeof(float)); memset(x1ac_preDelayLine[i].get(), 0, x1a4_preDelayTime * sizeof(float));
@@ -309,7 +313,7 @@ void EffectReverbHiImp<T>::_update()
else else
{ {
x1a4_preDelayTime = 0; x1a4_preDelayTime = 0;
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i)
{ {
x1ac_preDelayLine[i] = nullptr; x1ac_preDelayLine[i] = nullptr;
x1b8_preDelayPtr[i] = nullptr; x1b8_preDelayPtr[i] = nullptr;
@@ -340,7 +344,7 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
float damping = x1a0_damping; float damping = x1a0_damping;
int32_t preDelayTime = x1a4_preDelayTime; int32_t preDelayTime = x1a4_preDelayTime;
for (int s=0 ; s<sampleCount ; ++s) for (int s = 0; s < sampleCount; ++s)
{ {
float sample = audio[s * chanCount + c]; float sample = audio[s * chanCount + c];
@@ -393,8 +397,8 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
linesC[2].x4_outPoint = 0; linesC[2].x4_outPoint = 0;
/* All-pass filter stage */ /* All-pass filter stage */
linesAP[0].xc_inputs[linesAP[0].x0_inPoint] = linesAP[0].xc_inputs[linesAP[0].x0_inPoint] = allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput +
allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput + linesC[2].x10_lastInput; linesC[1].x10_lastInput + linesC[2].x10_lastInput;
linesAP[1].xc_inputs[linesAP[1].x0_inPoint] = linesAP[1].xc_inputs[linesAP[1].x0_inPoint] =
allPassCoef * linesAP[1].x10_lastInput - allPassCoef * linesAP[1].x10_lastInput -
@@ -446,16 +450,16 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
template <typename T> template <typename T>
void EffectReverbHiImp<T>::_doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount) void EffectReverbHiImp<T>::_doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount)
{ {
for (int i=0 ; i<sampleCount ; ++i) for (int i = 0; i < sampleCount; ++i)
{ {
T* base = &audio[chanCount*i]; T* base = &audio[chanCount * i];
float allWet = 0; float allWet = 0;
for (int c=0 ; c<chanCount ; ++c) for (int c = 0; c < chanCount; ++c)
{ {
allWet += base[c] * wet; allWet += base[c] * wet;
base[c] *= dry; base[c] *= dry;
} }
for (int c=0 ; c<chanCount ; ++c) for (int c = 0; c < chanCount; ++c)
base[c] = ClampFull<T>(base[c] + allWet); base[c] = ClampFull<T>(base[c] + allWet);
} }
} }
@@ -466,10 +470,10 @@ void EffectReverbHiImp<T>::applyEffect(T* audio, size_t frameCount, const Channe
if (m_dirty) if (m_dirty)
_update(); _update();
for (size_t f=0 ; f<frameCount ; f+=160) for (size_t f = 0; f < frameCount; f += 160)
{ {
size_t blockSamples = std::min(size_t(160), frameCount - f); size_t blockSamples = std::min(size_t(160), frameCount - f);
for (unsigned i=0 ; i<chanMap.m_channelCount ; ++i) for (unsigned i = 0; i < chanMap.m_channelCount; ++i)
{ {
if (i == 0 && x1a8_internalCrosstalk != 0.f) if (i == 0 && x1a8_internalCrosstalk != 0.f)
{ {
@@ -489,5 +493,4 @@ template class EffectReverbStdImp<float>;
template class EffectReverbHiImp<int16_t>; template class EffectReverbHiImp<int16_t>;
template class EffectReverbHiImp<int32_t>; template class EffectReverbHiImp<int32_t>;
template class EffectReverbHiImp<float>; template class EffectReverbHiImp<float>;
} }

View File

@@ -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,28 +28,115 @@ void Emitter::_destroy()
m_vox->kill(); m_vox->kill();
} }
void Emitter::setPos(const Vector3f& pos) float Emitter::_attenuationCurve(float dist) const
{ {
if (dist > m_maxDist)
return 0.f;
float t = dist / m_maxDist;
if (m_falloff < 0.f)
{
float tmp = t * 10.f + 1.f;
tmp = 1.f / (tmp * tmp);
return (1.f + m_falloff) * (-t + 1.f) + -m_falloff * tmp;
}
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::setDir(const Vector3f& dir) 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::setMaxDist(float maxDist) void Emitter::setVectors(const float* pos, const float* dir)
{
}
void Emitter::setMaxVol(float maxVol)
{
}
void Emitter::setMinVol(float minVol)
{
}
void Emitter::setFalloff(float falloff)
{ {
for (int i=0 ; i<3 ; ++i)
{
m_pos[i] = pos[i];
m_dir[i] = dir[i];
}
m_dirty = true;
} }
} }

View File

@@ -11,13 +11,14 @@
namespace amuse namespace amuse
{ {
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();
while (m_activeSubmixes.size())
removeSubmix(&m_activeSubmixes.front());
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters) for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
emitter->_destroy(); emitter->_destroy();
for (std::shared_ptr<Voice>& vox : m_activeVoices) for (std::shared_ptr<Voice>& vox : m_activeVoices)
@@ -25,9 +26,12 @@ Engine::~Engine()
} }
Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode) Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode)
: m_backend(backend), m_ampMode(ampMode) : m_backend(backend), m_ampMode(ampMode), m_defaultStudio(_allocateStudio(true))
{ {
backend.register5MsCallback(std::bind(&Engine::_5MsCallback, this, std::placeholders::_1)); m_defaultStudio->getAuxA().makeReverbStd(0.5f, 0.8f, 3.0f, 0.5f, 0.1f);
m_defaultStudio->getAuxB().makeChorus(15, 0, 500);
m_defaultStudioReady = true;
m_backend.setCallbackInterface(this);
m_midiReader = backend.allocateMIDIReader(*this); m_midiReader = backend.allocateMIDIReader(*this);
} }
@@ -53,85 +57,72 @@ std::pair<AudioGroup*, const SFXGroupIndex*> Engine::_findSFXGroup(int groupId)
return {}; return {};
} }
std::list<std::shared_ptr<Voice>>::iterator std::list<std::shared_ptr<Voice>>::iterator Engine::_allocateVoice(const AudioGroup& group, int groupId,
Engine::_allocateVoice(const AudioGroup& group, int groupId, double sampleRate, double sampleRate, bool dynamicPitch, bool emitter,
bool dynamicPitch, bool emitter, Submix* smx) std::weak_ptr<Studio> studio)
{ {
auto it = m_activeVoices.emplace(m_activeVoices.end(), std::shared_ptr<Studio> st = studio.lock();
new Voice(*this, group, groupId, m_nextVid++, emitter, smx)); auto it =
if (smx) m_activeVoices.emplace(m_activeVoices.end(), new Voice(*this, group, groupId, m_nextVid++, emitter, studio));
m_activeVoices.back()->m_backendVoice = m_activeVoices.back()->m_backendVoice = m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
smx->m_backendSubmix->allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch); m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getMaster().m_backendSubmix.get(), FullLevels, false);
else m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getAuxA().m_backendSubmix.get(), FullLevels, false);
m_activeVoices.back()->m_backendVoice = m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getAuxB().m_backendSubmix.get(), FullLevels, false);
m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
return it; return it;
} }
std::list<std::shared_ptr<Sequencer>>::iterator std::list<std::shared_ptr<Sequencer>>::iterator Engine::_allocateSequencer(const AudioGroup& group, int groupId,
Engine::_allocateSequencer(const AudioGroup& group, int groupId, int setupId, std::weak_ptr<Studio> studio)
int setupId, Submix* smx)
{ {
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId); const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
if (songGroup) if (songGroup)
{ {
auto it = m_activeSequencers.emplace(m_activeSequencers.end(), auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
new Sequencer(*this, group, groupId, songGroup, setupId, smx)); new Sequencer(*this, group, groupId, songGroup, setupId, studio));
return it; return it;
} }
const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId); const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId);
if (sfxGroup) if (sfxGroup)
{ {
auto it = m_activeSequencers.emplace(m_activeSequencers.end(), auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
new Sequencer(*this, group, groupId, sfxGroup, smx)); new Sequencer(*this, group, groupId, sfxGroup, studio));
return it; return it;
} }
return {}; return {};
} }
std::list<Submix>::iterator Engine::_allocateSubmix(Submix* smx) std::shared_ptr<Studio> Engine::_allocateStudio(bool mainOut)
{ {
auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx); std::shared_ptr<Studio> ret = std::make_shared<Studio>(*this, mainOut);
m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back()); m_activeStudios.emplace(m_activeStudios.end(), ret);
return it; ret->m_master.m_backendSubmix = m_backend.allocateSubmix(ret->m_master, mainOut, 0);
ret->m_auxA.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxA, mainOut, 1);
ret->m_auxB.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxB, mainOut, 2);
return ret;
} }
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();
return m_activeVoices.erase(it); return m_activeVoices.erase(it);
} }
std::list<std::shared_ptr<Sequencer>>::iterator Engine::_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it) std::list<std::shared_ptr<Sequencer>>::iterator
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();
return m_activeSequencers.erase(it); return m_activeSequencers.erase(it);
} }
std::list<Submix>::iterator Engine::_destroySubmix(std::list<Submix>::iterator it)
{
#ifndef NDEBUG
assert(this == &it->getEngine());
#endif
if (it->m_destroyed)
return m_activeSubmixes.begin();
it->_destroy();
return m_activeSubmixes.erase(it);
}
void Engine::_bringOutYourDead() void Engine::_bringOutYourDead()
{ {
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;) for (auto it = m_activeEmitters.begin(); it != m_activeEmitters.end();)
{ {
Emitter* emitter = it->get(); Emitter* emitter = it->get();
if (emitter->getVoice()->_isRecursivelyDead()) if (emitter->getVoice()->_isRecursivelyDead())
@@ -143,7 +134,7 @@ void Engine::_bringOutYourDead()
++it; ++it;
} }
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;) for (auto it = m_activeVoices.begin(); it != m_activeVoices.end();)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
vox->_bringOutYourDead(); vox->_bringOutYourDead();
@@ -155,7 +146,7 @@ void Engine::_bringOutYourDead()
++it; ++it;
} }
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;) for (auto it = m_activeSequencers.begin(); it != m_activeSequencers.end();)
{ {
Sequencer* seq = it->get(); Sequencer* seq = it->get();
seq->_bringOutYourDead(); seq->_bringOutYourDead();
@@ -166,20 +157,32 @@ void Engine::_bringOutYourDead()
} }
++it; ++it;
} }
for (auto it = m_activeStudios.begin(); it != m_activeStudios.end();)
{
std::shared_ptr<Studio> st = it->lock();
if (!st)
it = m_activeStudios.erase(it);
else
++it;
}
} }
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 */
@@ -239,7 +242,7 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
AudioGroup* grp = search->second.get(); AudioGroup* grp = search->second.get();
/* Destroy runtime entities within group */ /* Destroy runtime entities within group */
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;) for (auto it = m_activeVoices.begin(); it != m_activeVoices.end();)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
if (&vox->getAudioGroup() == grp) if (&vox->getAudioGroup() == grp)
@@ -251,7 +254,7 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
++it; ++it;
} }
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;) for (auto it = m_activeEmitters.begin(); it != m_activeEmitters.end();)
{ {
Emitter* emitter = it->get(); Emitter* emitter = it->get();
if (&emitter->getAudioGroup() == grp) if (&emitter->getAudioGroup() == grp)
@@ -263,7 +266,7 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
++it; ++it;
} }
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;) for (auto it = m_activeSequencers.begin(); it != m_activeSequencers.end();)
{ {
Sequencer* seq = it->get(); Sequencer* seq = it->get();
if (&seq->getAudioGroup() == grp) if (&seq->getAudioGroup() == grp)
@@ -286,67 +289,11 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
m_audioGroups.erase(search); m_audioGroups.erase(search);
} }
/** Create new Submix (a.k.a 'Studio') within root mix engine */ /** Create new Studio within engine */
Submix* Engine::addSubmix(Submix* smx) std::shared_ptr<Studio> Engine::addStudio(bool mainOut) { return _allocateStudio(mainOut); }
{
return &*_allocateSubmix(smx);
}
std::list<Submix>::iterator Engine::_removeSubmix(std::list<Submix>::iterator smx)
{
/* Delete all voices bound to submix */
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it)
{
Voice* vox = it->get();
Submix* vsmx = vox->getSubmix();
if (vsmx == &*smx)
vox->kill();
}
/* Delete all sequencers bound to submix */
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ; ++it)
{
Sequencer* seq = it->get();
Submix* ssmx = seq->getSubmix();
if (ssmx == &*smx)
seq->kill();
}
/* Delete all submixes bound to submix */
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
{
Submix* ssmx = it->getParentSubmix();
if (ssmx == &*smx)
{
it = _removeSubmix(it);
continue;
}
++it;
}
/* Delete submix */
return _destroySubmix(smx);
}
/** Remove Submix and deallocate */
void Engine::removeSubmix(Submix* smx)
{
if (!smx)
return;
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
{
if (&*it == &*smx)
{
it = _removeSubmix(it);
break;
}
++it;
}
}
/** Start soundFX playing from loaded audio groups */ /** Start soundFX playing from loaded audio groups */
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix* smx) std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, 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())
@@ -358,8 +305,7 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
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), _allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, false, smx);
32000.0, 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))
@@ -374,8 +320,9 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
} }
/** 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, std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
float falloff, int sfxId, float minVol, float maxVol, Submix* 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())
@@ -387,33 +334,53 @@ 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), _allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, true, smx);
32000.0, 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, std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData,
const unsigned char* arrData, Submix* smx) std::weak_ptr<Studio> smx)
{ {
std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId); std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId);
if (songGrp.second) if (songGrp.second)
@@ -439,6 +406,12 @@ std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId,
return {}; return {};
} }
/** Set total volume of engine */
void Engine::setVolume(float vol)
{
m_masterVolume = vol;
}
/** Find voice from VoiceId */ /** Find voice from VoiceId */
std::shared_ptr<Voice> Engine::findVoice(int vid) std::shared_ptr<Voice> Engine::findVoice(int vid)
{ {
@@ -462,7 +435,7 @@ std::shared_ptr<Voice> Engine::findVoice(int vid)
/** Stop all voices in `kg`, stops immediately (no KeyOff) when `flag` set */ /** Stop all voices in `kg`, stops immediately (no KeyOff) when `flag` set */
void Engine::killKeygroup(uint8_t kg, bool now) void Engine::killKeygroup(uint8_t kg, bool now)
{ {
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;) for (auto it = m_activeVoices.begin(); it != m_activeVoices.end();)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
if (vox->m_keygroup == kg) if (vox->m_keygroup == kg)
@@ -484,7 +457,7 @@ void Engine::killKeygroup(uint8_t kg, bool now)
/** Send all voices using `macroId` the message `val` */ /** Send all voices using `macroId` the message `val` */
void Engine::sendMacroMessage(ObjectId macroId, int32_t val) void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
{ {
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it) for (auto it = m_activeVoices.begin(); it != m_activeVoices.end(); ++it)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
if (vox->getObjectId() == macroId) if (vox->getObjectId() == macroId)
@@ -494,5 +467,4 @@ void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers) for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
seq->sendMacroMessage(macroId, val); seq->sendMacroMessage(macroId, val);
} }
} }

View File

@@ -4,22 +4,16 @@
namespace amuse namespace amuse
{ {
static int32_t MIDItoTIME[104] = static int32_t MIDItoTIME[104] = {/* [0..103] -> milliseconds */
{ /* [0..103] -> milliseconds */ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110,
0, 10, 20, 30, 40, 50, 60, 70, 110, 120, 130, 140, 150, 160, 170, 190, 200, 220, 230, 250,
80, 90, 100, 110, 110, 120, 130, 140, 270, 290, 310, 330, 350, 380, 410, 440, 470, 500, 540, 580,
150, 160, 170, 190, 200, 220, 230, 250, 620, 660, 710, 760, 820, 880, 940, 1000, 1000, 1100, 1200, 1300,
270, 290, 310, 330, 350, 380, 410, 440, 1400, 1500, 1600, 1700, 1800, 2000, 2100, 2300, 2400, 2600, 2800, 3000,
470, 500, 540, 580, 620, 660, 710, 760, 3200, 3500, 3700, 4000, 4300, 4600, 4900, 5300, 5700, 6100, 6500, 7000,
820, 880, 940, 1000, 1000, 1100, 1200, 1300, 7500, 8100, 8600, 9300, 9900, 10000, 11000, 12000, 13000, 14000, 15000, 16000,
1400, 1500, 1600, 1700, 1800, 2000, 2100, 2300, 17000, 18000, 19000, 21000, 22000, 24000, 26000, 28000, 30000, 32000, 34000, 37000,
2400, 2600, 2800, 3000, 3200, 3500, 3700, 4000, 39000, 42000, 45000, 49000, 50000, 55000, 60000, 65000};
4300, 4600, 4900, 5300, 5700, 6100, 6500, 7000,
7500, 8100, 8600, 9300, 9900, 10000, 11000, 12000,
13000, 14000, 15000, 16000, 17000, 18000, 19000, 21000,
22000, 24000, 26000, 28000, 30000, 32000, 34000, 37000,
39000, 42000, 45000, 49000, 50000, 55000, 60000, 65000
};
void Envelope::reset(const ADSR* adsr) void Envelope::reset(const ADSR* adsr)
{ {
@@ -231,5 +225,4 @@ float Envelope::advance(double dt)
return 0.f; return 0.f;
} }
} }
} }

View File

@@ -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;
}
}

View File

@@ -9,7 +9,7 @@ namespace amuse
void Sequencer::ChannelState::_bringOutYourDead() void Sequencer::ChannelState::_bringOutYourDead()
{ {
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;) for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
{ {
Voice* vox = it->second.get(); Voice* vox = it->second.get();
vox->_bringOutYourDead(); vox->_bringOutYourDead();
@@ -21,7 +21,7 @@ void Sequencer::ChannelState::_bringOutYourDead()
++it; ++it;
} }
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;) for (auto it = m_keyoffVoxs.begin(); it != m_keyoffVoxs.end();)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
vox->_bringOutYourDead(); vox->_bringOutYourDead();
@@ -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;
@@ -47,41 +47,29 @@ void Sequencer::_bringOutYourDead()
void Sequencer::_destroy() void Sequencer::_destroy()
{ {
Entity::_destroy(); Entity::_destroy();
if (m_submix) if (m_studio)
{ m_studio.reset();
m_engine.removeSubmix(m_submix);
m_submix = nullptr;
}
} }
Sequencer::~Sequencer() Sequencer::~Sequencer()
{ {
if (m_submix) if (m_studio)
{ m_studio.reset();
m_engine.removeSubmix(m_submix);
m_submix = nullptr;
}
} }
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
const SongGroupIndex* songGroup, int setupId, Submix* smx) std::weak_ptr<Studio> studio)
: Entity(engine, group, groupId), m_songGroup(songGroup) : Entity(engine, group, groupId), m_songGroup(songGroup), m_studio(studio)
{ {
auto it = m_songGroup->m_midiSetups.find(setupId); auto it = m_songGroup->m_midiSetups.find(setupId);
if (it != m_songGroup->m_midiSetups.cend()) if (it != m_songGroup->m_midiSetups.cend())
m_midiSetup = it->second->data(); m_midiSetup = it->second->data();
m_submix = m_engine.addSubmix(smx);
m_submix->makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f);
} }
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
const SFXGroupIndex* sfxGroup, Submix* smx) std::weak_ptr<Studio> studio)
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup) : Entity(engine, group, groupId), m_sfxGroup(sfxGroup), m_studio(studio)
{ {
//m_submix = m_engine.addSubmix(smx);
//m_submix->makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f);
std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX; std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX;
for (const auto& sfx : sfxGroup->m_sfxEntries) for (const auto& sfx : sfxGroup->m_sfxEntries)
sortSFX[sfx.first] = sfx.second; sortSFX[sfx.first] = sfx.second;
@@ -91,30 +79,34 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
m_sfxMappings.push_back(sfx.second); m_sfxMappings.push_back(sfx.second);
} }
Sequencer::ChannelState::~ChannelState() Sequencer::ChannelState::~ChannelState() {}
{
}
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId) Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
: m_parent(parent), m_chanId(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;
}
} }
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_curVol = m_setup->volume / 127.f; m_curVol = m_setup->volume / 127.f;
@@ -126,14 +118,14 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
{ {
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;
} }
@@ -143,7 +135,7 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
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;
@@ -158,12 +150,45 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
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
@@ -181,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 */
@@ -214,35 +239,34 @@ 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 = std::list<std::shared_ptr<Voice>>::iterator ret = m_parent->m_engine._allocateVoice(
m_parent.m_engine._allocateVoice(m_parent.m_audioGroup, m_parent->m_audioGroup, m_parent->m_groupId, NativeSampleRate, true, false, m_parent->m_studio);
m_parent.m_groupId, 32000.0,
true, false, m_parent.m_submix);
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)->setPan(m_curPan); (*ret)->setPan(m_curPan);
(*ret)->setPitchWheel(m_curPitchWheel); (*ret)->setPitchWheel(m_curPitchWheel);
@@ -261,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)
@@ -284,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)
@@ -303,18 +327,19 @@ void Sequencer::ChannelState::setCtrlValue(uint8_t ctrl, int8_t val)
case 10: case 10:
setPan(val / 64.f - 1.f); setPan(val / 64.f - 1.f);
break; break;
default: break; default:
break;
} }
} }
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;
@@ -323,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;
@@ -366,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)
@@ -386,19 +411,16 @@ 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) void Sequencer::setTempo(double ticksPerSec) { m_ticksPerSec = ticksPerSec; }
{
m_ticksPerSec = ticksPerSec;
}
void Sequencer::ChannelState::allOff() void Sequencer::ChannelState::allOff()
{ {
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;) for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
{ {
if (it->second == m_lastVoice.lock()) if (it->second == m_lastVoice.lock())
m_lastVoice.reset(); m_lastVoice.reset();
@@ -415,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)
@@ -436,20 +458,20 @@ 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)
{ {
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;) for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
{ {
Voice* vox = it->second.get(); Voice* vox = it->second.get();
if (vox->m_keygroup == kg) if (vox->m_keygroup == kg)
@@ -471,7 +493,7 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
if (now) if (now)
{ {
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;) for (auto it = m_keyoffVoxs.begin(); it != m_keyoffVoxs.end();)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
if (vox->m_keygroup == kg) if (vox->m_keygroup == kg)
@@ -488,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)
@@ -508,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;
} }
@@ -536,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)
@@ -548,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();
@@ -586,20 +616,36 @@ 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
{ {
if (chanId > 15 || !m_chanStates[chanId]) if (chanId > 15)
return 0; return 0;
return m_chanStates[chanId]->m_curProgram; if (!m_chanStates[chanId])
{
if (!m_midiSetup)
return 0;
return m_midiSetup[chanId].programNo;
}
return m_chanStates[chanId].m_curProgram;
} }
bool Sequencer::setChanProgram(int8_t chanId, int8_t prog) bool Sequencer::setChanProgram(int8_t chanId, int8_t prog)
@@ -608,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)
@@ -619,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)
@@ -630,9 +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();
} }
} }

View File

@@ -1,13 +1,13 @@
#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
{ {
static inline uint8_t clamp7(uint8_t val) {return std::max(0, std::min(127, int(val)));} static inline uint8_t clamp7(uint8_t val) { return std::max(0, std::min(127, int(val))); }
enum class Status enum class Status
{ {
@@ -33,38 +33,51 @@ enum class Status
}; };
/* Event tags */ /* Event tags */
struct NoteEvent {}; struct NoteEvent
struct CtrlEvent {}; {
struct ProgEvent {}; };
struct PitchEvent {}; struct CtrlEvent
{
};
struct ProgEvent
{
};
struct PitchEvent
{
};
/* Intermediate event */ /* Intermediate event */
struct Event struct Event
{ {
enum class Type : uint8_t
{
Note,
Control,
Program,
Pitch
} m_type;
bool endEvent = false; bool endEvent = false;
bool isNote = false;
bool isControlChange = false;
bool isProgChange = false;
uint8_t channel; uint8_t channel;
uint8_t noteOrCtrl; uint8_t noteOrCtrl;
uint8_t velOrVal; uint8_t velOrVal;
uint8_t program; uint8_t program;
uint16_t length; uint16_t length;
bool isPitchBend = false;
int pitchBend; int pitchBend;
Event(NoteEvent, uint8_t chan, uint8_t note, uint8_t vel, uint16_t len) Event(NoteEvent, uint8_t chan, uint8_t note, uint8_t vel, uint16_t len)
: isNote(true), channel(chan), noteOrCtrl(note), velOrVal(vel), length(len) {} : m_type(Type::Note), channel(chan), noteOrCtrl(note), velOrVal(vel), length(len)
{
}
Event(CtrlEvent, uint8_t chan, uint8_t note, uint8_t vel, uint16_t len) Event(CtrlEvent, uint8_t chan, uint8_t note, uint8_t vel, uint16_t len)
: isControlChange(true), channel(chan), noteOrCtrl(note), velOrVal(vel), length(len) {} : m_type(Type::Control), channel(chan), noteOrCtrl(note), velOrVal(vel), length(len)
{
}
Event(ProgEvent, uint8_t chan, uint8_t prog) Event(ProgEvent, uint8_t chan, uint8_t prog) : m_type(Type::Program), channel(chan), program(prog) {}
: isProgChange(true), channel(chan), program(prog) {}
Event(PitchEvent, uint8_t chan, int pBend) Event(PitchEvent, uint8_t chan, int pBend) : m_type(Type::Pitch), channel(chan), pitchBend(pBend) {}
: isPitchBend(true), channel(chan), pitchBend(pBend) {}
}; };
class MIDIDecoder class MIDIDecoder
@@ -78,13 +91,12 @@ class MIDIDecoder
{ {
m_results.emplace_back(); m_results.emplace_back();
m_results.back().first = prog; m_results.back().first = prog;
for (size_t i=0 ; i<128 ; ++i) for (size_t i = 0; i < 128; ++i)
m_notes[i] = m_results.back().second.end(); m_notes[i] = m_results.back().second.end();
} }
uint8_t m_status = 0; uint8_t m_status = 0;
bool _readContinuedValue(std::vector<uint8_t>::const_iterator& it, bool _readContinuedValue(std::vector<uint8_t>::const_iterator& it, std::vector<uint8_t>::const_iterator end,
std::vector<uint8_t>::const_iterator end,
uint32_t& valOut) uint32_t& valOut)
{ {
uint8_t a = *it++; uint8_t a = *it++;
@@ -112,9 +124,8 @@ class MIDIDecoder
} }
public: public:
std::vector<uint8_t>::const_iterator std::vector<uint8_t>::const_iterator receiveBytes(std::vector<uint8_t>::const_iterator begin,
receiveBytes(std::vector<uint8_t>::const_iterator begin, std::vector<uint8_t>::const_iterator end)
std::vector<uint8_t>::const_iterator end)
{ {
std::vector<uint8_t>::const_iterator it = begin; std::vector<uint8_t>::const_iterator it = begin;
if (it == end) if (it == end)
@@ -289,19 +300,21 @@ public:
case Status::SysExTerm: case Status::SysExTerm:
case Status::TimingClock: case Status::TimingClock:
case Status::ActiveSensing: case Status::ActiveSensing:
default: break; default:
break;
} }
break; break;
} }
default: break; default:
break;
} }
} }
return it; return it;
} }
std::vector<std::pair<int, std::multimap<int, Event>>>& getResults() {return m_results;} std::vector<std::pair<int, std::multimap<int, Event>>>& getResults() { return m_results; }
std::multimap<int, int>& getTempos() {return m_tempos;} std::multimap<int, int>& getTempos() { return m_tempos; }
}; };
class MIDIEncoder class MIDIEncoder
@@ -314,22 +327,22 @@ class MIDIEncoder
{ {
if (data[0] == m_status) if (data[0] == m_status)
{ {
for (size_t i=1 ; i<len ; ++i) for (size_t i = 1; i < len; ++i)
m_result.push_back(data[i]); m_result.push_back(data[i]);
} }
else else
{ {
if (data[0] & 0x80) if (data[0] & 0x80)
m_status = data[0]; m_status = data[0];
for (size_t i=0 ; i<len ; ++i) for (size_t i = 0; i < len; ++i)
m_result.push_back(data[i]); m_result.push_back(data[i]);
} }
} }
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];
@@ -350,110 +363,98 @@ class MIDIEncoder
send[2] = val & 0x7f; send[2] = val & 0x7f;
size_t len = 3 - (ptr - send); size_t len = 3 - (ptr - send);
for (size_t i=0 ; i<len ; ++i) for (size_t i = 0; i < len; ++i)
m_result.push_back(ptr[i]); m_result.push_back(ptr[i]);
} }
public: public:
void noteOff(uint8_t chan, uint8_t key, uint8_t velocity) void noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void noteOn(uint8_t chan, uint8_t key, uint8_t velocity) void noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void notePressure(uint8_t chan, uint8_t key, uint8_t pressure) void notePressure(uint8_t chan, uint8_t key, uint8_t pressure)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t(key & 0x7f),
uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)}; uint8_t(pressure & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void controlChange(uint8_t chan, uint8_t control, uint8_t value) void controlChange(uint8_t chan, uint8_t control, uint8_t value)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(control & 0x7f),
uint8_t(control & 0x7f), uint8_t(value & 0x7f)}; uint8_t(value & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void programChange(uint8_t chan, uint8_t program) void programChange(uint8_t chan, uint8_t program)
{ {
uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t(program & 0x7f)};
uint8_t(program & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
void channelPressure(uint8_t chan, uint8_t pressure) void channelPressure(uint8_t chan, uint8_t pressure)
{ {
uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t(pressure & 0x7f)};
uint8_t(pressure & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
void pitchBend(uint8_t chan, int16_t pitch) void pitchBend(uint8_t chan, int16_t pitch)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch % 128) & 0x7f),
uint8_t((pitch % 128) & 0x7f), uint8_t((pitch / 128) & 0x7f)}; uint8_t((pitch / 128) & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void allSoundOff(uint8_t chan) void allSoundOff(uint8_t chan)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 120, 0};
120, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void resetAllControllers(uint8_t chan) void resetAllControllers(uint8_t chan)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 121, 0};
121, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void localControl(uint8_t chan, bool on) void localControl(uint8_t chan, bool on)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 122, uint8_t(on ? 127 : 0)};
122, uint8_t(on ? 127 : 0)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void allNotesOff(uint8_t chan) void allNotesOff(uint8_t chan)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 123, 0};
123, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void omniMode(uint8_t chan, bool on) void omniMode(uint8_t chan, bool on)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 125 : 124), 0};
uint8_t(on ? 125 : 124), 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void polyMode(uint8_t chan, bool on) void polyMode(uint8_t chan, bool on)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 127 : 126), 0};
uint8_t(on ? 127 : 126), 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void sysex(const void* data, size_t len) void sysex(const void* data, size_t len)
{ {
uint8_t cmd = uint8_t(Status::SysEx); uint8_t cmd = uint8_t(Status::SysEx);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
_sendContinuedValue(len); _sendContinuedValue(len);
for (size_t i=0 ; i<len ; ++i) for (size_t i = 0; i < len; ++i)
m_result.push_back(reinterpret_cast<const uint8_t*>(data)[i]); m_result.push_back(reinterpret_cast<const uint8_t*>(data)[i]);
cmd = uint8_t(Status::SysExTerm); cmd = uint8_t(Status::SysExTerm);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
@@ -461,22 +462,20 @@ public:
void timeCodeQuarterFrame(uint8_t message, uint8_t value) void timeCodeQuarterFrame(uint8_t message, uint8_t value)
{ {
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t((message & 0x7 << 4) | (value & 0xf))};
uint8_t((message & 0x7 << 4) | (value & 0xf))};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
void songPositionPointer(uint16_t pointer) void songPositionPointer(uint16_t pointer)
{ {
uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer % 128) & 0x7f),
uint8_t((pointer % 128) & 0x7f), uint8_t((pointer / 128) & 0x7f)}; uint8_t((pointer / 128) & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
void songSelect(uint8_t song) void songSelect(uint8_t song)
{ {
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t(song & 0x7f)};
uint8_t(song & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
@@ -486,7 +485,6 @@ public:
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
void startSeq() void startSeq()
{ {
uint8_t cmd = uint8_t(Status::Start); uint8_t cmd = uint8_t(Status::Start);
@@ -505,15 +503,14 @@ public:
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
void reset() void reset()
{ {
uint8_t cmd = uint8_t(Status::Reset); uint8_t cmd = uint8_t(Status::Reset);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
const std::vector<uint8_t>& getResult() const {return m_result;} const std::vector<uint8_t>& getResult() const { return m_result; }
std::vector<uint8_t>& getResult() {return m_result;} std::vector<uint8_t>& getResult() { return m_result; }
}; };
static uint32_t DecodeRLE(const unsigned char*& data) static uint32_t DecodeRLE(const unsigned char*& data)
@@ -622,7 +619,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
{ {
std::vector<uint8_t> ret = {'M', 'T', 'h', 'd'}; std::vector<uint8_t> ret = {'M', 'T', 'h', 'd'};
uint32_t six32 = SBig(uint32_t(6)); uint32_t six32 = SBig(uint32_t(6));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
ret.push_back(reinterpret_cast<uint8_t*>(&six32)[i]); ret.push_back(reinterpret_cast<uint8_t*>(&six32)[i]);
ret.push_back(0); ret.push_back(0);
@@ -635,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;
@@ -658,7 +655,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
encoder.getResult().push_back(3); encoder.getResult().push_back(3);
uint32_t tempo24 = SBig(60000000 / song.m_tempo); uint32_t tempo24 = SBig(60000000 / song.m_tempo);
for (int i=1 ; i<4 ; ++i) for (int i = 1; i < 4; ++i)
encoder.getResult().push_back(reinterpret_cast<uint8_t*>(&tempo24)[i]); encoder.getResult().push_back(reinterpret_cast<uint8_t*>(&tempo24)[i]);
/* Write out tempo changes */ /* Write out tempo changes */
@@ -675,8 +672,8 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
encoder.getResult().push_back(0x51); encoder.getResult().push_back(0x51);
encoder.getResult().push_back(3); encoder.getResult().push_back(3);
uint32_t tempo24 = SBig(60000000 / change.m_tempo); uint32_t tempo24 = SBig(60000000 / (change.m_tempo & 0x7fffffff));
for (int i=1 ; i<4 ; ++i) for (int i = 1; i < 4; ++i)
encoder.getResult().push_back(reinterpret_cast<uint8_t*>(&tempo24)[i]); encoder.getResult().push_back(reinterpret_cast<uint8_t*>(&tempo24)[i]);
++song.m_tempoPtr; ++song.m_tempoPtr;
@@ -692,13 +689,13 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
ret.push_back('r'); ret.push_back('r');
ret.push_back('k'); ret.push_back('k');
uint32_t trkSz = SBig(uint32_t(encoder.getResult().size())); uint32_t trkSz = SBig(uint32_t(encoder.getResult().size()));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
ret.push_back(reinterpret_cast<uint8_t*>(&trkSz)[i]); ret.push_back(reinterpret_cast<uint8_t*>(&trkSz)[i]);
ret.insert(ret.cend(), encoder.getResult().begin(), encoder.getResult().end()); ret.insert(ret.cend(), encoder.getResult().begin(), encoder.getResult().end());
} }
/* 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)
{ {
@@ -706,32 +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 = song.m_bigEndian ? SBig(trk->m_curRegion->m_startTick) : trk->m_curRegion->m_startTick; uint32_t regStart =
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, Event{PitchEvent{}, trk->m_midiChan, clamp(0, trk->m_lastPitchVal / 2 + 0x2000, 0x4000)}); events.emplace(regStart + nextTick,
Event{PitchEvent{}, trk.m_midiChan,
clamp(0, trk.m_lastPitchVal / 2 + 0x2000, 0x4000)});
} }
else else
break; break;
@@ -739,21 +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, Event{CtrlEvent{}, trk->m_midiChan, 1, uint8_t(clamp(0, trk->m_lastModVal * 128 / 16384, 127)), 0}); events.emplace(regStart + nextTick,
Event{CtrlEvent{}, trk.m_midiChan, 1,
uint8_t(clamp(0, trk.m_lastModVal * 128 / 16384, 127)), 0});
} }
else else
break; break;
@@ -767,40 +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, Event{CtrlEvent{}, trk->m_midiChan, ctrl, val, 0}); events.emplace(regStart + trk.m_eventWaitCountdown,
trk->m_data += 2; Event{CtrlEvent{}, trk.m_midiChan, ctrl, val, 0});
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, Event{ProgEvent{}, trk->m_midiChan, prog}); events.emplace(regStart + trk.m_eventWaitCountdown,
trk->m_data += 2; Event{ProgEvent{}, trk.m_midiChan, prog});
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 = (song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk->m_data + 2)) : uint16_t length =
*reinterpret_cast<const uint16_t*>(trk->m_data + 2)); (song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk.m_data + 2))
events.emplace(regStart + trk->m_eventWaitCountdown, Event{NoteEvent{}, trk->m_midiChan, note, vel, length}); : *reinterpret_cast<const uint16_t*>(trk.m_data + 2));
trk->m_data += 4; events.emplace(regStart + trk.m_eventWaitCountdown,
Event{NoteEvent{}, trk.m_midiChan, note, vel, length});
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
@@ -809,45 +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 = (song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk->m_data)) : uint16_t length =
*reinterpret_cast<const uint16_t*>(trk->m_data)); (song.m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(trk.m_data))
uint8_t note = trk->m_data[2] & 0x7f; : *reinterpret_cast<const uint16_t*>(trk.m_data));
uint8_t vel = trk->m_data[3] & 0x7f; uint8_t note = trk.m_data[2] & 0x7f;
events.emplace(regStart + trk->m_eventWaitCountdown, Event{NoteEvent{}, trk->m_midiChan, note, vel, length}); uint8_t vel = trk.m_data[3] & 0x7f;
events.emplace(regStart + trk.m_eventWaitCountdown,
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, Event{CtrlEvent{}, trk->m_midiChan, ctrl, val, 0}); events.emplace(regStart + trk.m_eventWaitCountdown,
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, Event{ProgEvent{}, trk->m_midiChan, prog}); events.emplace(regStart + trk.m_eventWaitCountdown,
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;
} }
} }
@@ -857,7 +867,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
/* Resolve key-off events */ /* Resolve key-off events */
for (auto& pair : events) for (auto& pair : events)
{ {
if (pair.second.isNote) if (pair.second.m_type == Event::Type::Note)
{ {
auto it = allEvents.emplace(pair.first + pair.second.length, pair.second); auto it = allEvents.emplace(pair.first + pair.second.length, pair.second);
it->second.endEvent = true; it->second.endEvent = true;
@@ -872,24 +882,23 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
encoder._sendContinuedValue(pair.first - lastTime); encoder._sendContinuedValue(pair.first - lastTime);
lastTime = pair.first; lastTime = pair.first;
if (pair.second.isControlChange) switch (pair.second.m_type)
{ {
case Event::Type::Control:
encoder.controlChange(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal); encoder.controlChange(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal);
} break;
else if (pair.second.isProgChange) case Event::Type::Program:
{ encoder.programChange(trk.m_midiChan, pair.second.program);
encoder.programChange(trk->m_midiChan, pair.second.program); break;
} case Event::Type::Pitch:
else if (pair.second.isPitchBend) encoder.pitchBend(trk.m_midiChan, pair.second.pitchBend);
{ break;
encoder.pitchBend(trk->m_midiChan, pair.second.pitchBend); case Event::Type::Note:
}
else if (pair.second.isNote)
{
if (pair.second.endEvent) if (pair.second.endEvent)
encoder.noteOff(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal); encoder.noteOff(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal);
else else
encoder.noteOn(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal); encoder.noteOn(pair.second.channel, pair.second.noteOrCtrl, pair.second.velOrVal);
break;
} }
} }
@@ -904,7 +913,7 @@ std::vector<uint8_t> SongConverter::SongToMIDI(const unsigned char* data, int& v
ret.push_back('r'); ret.push_back('r');
ret.push_back('k'); ret.push_back('k');
uint32_t trkSz = SBig(uint32_t(encoder.getResult().size())); uint32_t trkSz = SBig(uint32_t(encoder.getResult().size()));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
ret.push_back(reinterpret_cast<uint8_t*>(&trkSz)[i]); ret.push_back(reinterpret_cast<uint8_t*>(&trkSz)[i]);
ret.insert(ret.cend(), encoder.getResult().begin(), encoder.getResult().end()); ret.insert(ret.cend(), encoder.getResult().begin(), encoder.getResult().end());
} }
@@ -955,7 +964,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
std::vector<std::pair<uint32_t, uint32_t>> tempoBuf; std::vector<std::pair<uint32_t, uint32_t>> tempoBuf;
std::array<uint8_t, 64> chanMap; std::array<uint8_t, 64> chanMap;
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
chanMap[i] = 0xff; chanMap[i] = 0xff;
struct Region struct Region
@@ -987,7 +996,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
std::vector<Region> regions; std::vector<Region> regions;
int curRegionOff = 0; int curRegionOff = 0;
for (int i=0 ; i<header.count ; ++i) for (int i = 0; i < header.count; ++i)
{ {
if (memcmp(&*it, "MTrk", 4)) if (memcmp(&*it, "MTrk", 4))
return {}; return {};
@@ -1016,7 +1025,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
for (auto& pair : tempos) for (auto& pair : tempos)
{ {
if (big) if (big)
tempoBuf.emplace_back(SBig(uint32_t(pair.first * 384 / header.div)), SBig(uint32_t(pair.second))); tempoBuf.emplace_back(SBig(uint32_t(pair.first * 384 / header.div)),
SBig(uint32_t(pair.second)));
else else
tempoBuf.emplace_back(pair.first * 384 / header.div, pair.second); tempoBuf.emplace_back(pair.first * 384 / header.div, pair.second);
} }
@@ -1039,7 +1049,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
begin = dec.receiveBytes(begin, end); begin = dec.receiveBytes(begin, end);
std::vector<std::pair<int, std::multimap<int, Event>>>& results = dec.getResults(); std::vector<std::pair<int, std::multimap<int, Event>>>& results = dec.getResults();
for (int c=0 ; c<16 ; ++c) for (int c = 0; c < 16; ++c)
{ {
int lastTrackStartTick = 0; int lastTrackStartTick = 0;
bool didChanInit = false; bool didChanInit = false;
@@ -1072,7 +1082,9 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
lastModVal = 0; lastModVal = 0;
} }
if (event.second.isControlChange) switch (event.second.m_type)
{
case Event::Type::Control:
{ {
if (event.second.noteOrCtrl == 1) if (event.second.noteOrCtrl == 1)
{ {
@@ -1096,7 +1108,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
if (big) if (big)
{ {
uint32_t tickBig = SBig(uint32_t(eventTick - startTick)); uint32_t tickBig = SBig(uint32_t(eventTick - startTick));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]);
region.eventBuf.push_back(0x80 | event.second.velOrVal); region.eventBuf.push_back(0x80 | event.second.velOrVal);
region.eventBuf.push_back(0x80 | event.second.noteOrCtrl); region.eventBuf.push_back(0x80 | event.second.noteOrCtrl);
@@ -1104,15 +1116,16 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
else else
{ {
uint32_t tick = uint32_t(eventTick - startTick); uint32_t tick = uint32_t(eventTick - startTick);
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]);
region.eventBuf.push_back(0x80 | event.second.velOrVal); region.eventBuf.push_back(0x80 | event.second.velOrVal);
region.eventBuf.push_back(0x80 | event.second.noteOrCtrl); region.eventBuf.push_back(0x80 | event.second.noteOrCtrl);
} }
} }
} }
break;
} }
else if (event.second.isProgChange) case Event::Type::Program:
{ {
if (version == 1) if (version == 1)
{ {
@@ -1126,7 +1139,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
if (big) if (big)
{ {
uint32_t tickBig = SBig(uint32_t(eventTick - startTick)); uint32_t tickBig = SBig(uint32_t(eventTick - startTick));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]);
region.eventBuf.push_back(0x80 | event.second.program); region.eventBuf.push_back(0x80 | event.second.program);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
@@ -1134,22 +1147,24 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
else else
{ {
uint32_t tick = uint32_t(eventTick - startTick); uint32_t tick = uint32_t(eventTick - startTick);
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]);
region.eventBuf.push_back(0x80 | event.second.program); region.eventBuf.push_back(0x80 | event.second.program);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
} }
} }
break;
} }
else if (event.second.isPitchBend) case Event::Type::Pitch:
{ {
EncodeRLE(region.pitchBuf, uint32_t(eventTick - lastPitchTick)); EncodeRLE(region.pitchBuf, uint32_t(eventTick - lastPitchTick));
lastPitchTick = eventTick; lastPitchTick = eventTick;
int newPitch = (event.second.pitchBend - 0x2000) * 2; int newPitch = (event.second.pitchBend - 0x2000) * 2;
EncodeContinuousRLE(region.pitchBuf, newPitch - lastPitchVal); EncodeContinuousRLE(region.pitchBuf, newPitch - lastPitchVal);
lastPitchVal = newPitch; lastPitchVal = newPitch;
break;
} }
else if (event.second.isNote) case Event::Type::Note:
{ {
if (version == 1) if (version == 1)
{ {
@@ -1166,7 +1181,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
if (big) if (big)
{ {
uint32_t tickBig = SBig(uint32_t(eventTick - startTick)); uint32_t tickBig = SBig(uint32_t(eventTick - startTick));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]);
uint16_t lenBig = SBig(uint16_t(event.second.length)); uint16_t lenBig = SBig(uint16_t(event.second.length));
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&lenBig)[0]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&lenBig)[0]);
@@ -1177,7 +1192,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
else else
{ {
uint32_t tick = uint32_t(eventTick - startTick); uint32_t tick = uint32_t(eventTick - startTick);
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]);
uint16_t len = uint16_t(event.second.length); uint16_t len = uint16_t(event.second.length);
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&len)[0]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&len)[0]);
@@ -1186,6 +1201,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
region.eventBuf.push_back(event.second.velOrVal); region.eventBuf.push_back(event.second.velOrVal);
} }
} }
break;
}
} }
} }
} }
@@ -1219,11 +1236,10 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
{ {
if (big) if (big)
{ {
uint32_t selTick = std::max(std::max(lastEventTick - startTick, uint32_t selTick = std::max(std::max(lastEventTick - startTick, lastPitchTick - startTick),
lastPitchTick - startTick), lastModTick - startTick);
lastModTick - startTick);
uint32_t tickBig = SBig(uint32_t(selTick)); uint32_t tickBig = SBig(uint32_t(selTick));
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tickBig)[i]);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
@@ -1232,11 +1248,10 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
} }
else else
{ {
uint32_t selTick = std::max(std::max(lastEventTick - startTick, uint32_t selTick = std::max(std::max(lastEventTick - startTick, lastPitchTick - startTick),
lastPitchTick - startTick), lastModTick - startTick);
lastModTick - startTick);
uint32_t tick = uint32_t(selTick); uint32_t tick = uint32_t(selTick);
for (int i=0 ; i<4 ; ++i) for (int i = 0; i < 4; ++i)
region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]); region.eventBuf.push_back(reinterpret_cast<const uint8_t*>(&tick)[i]);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
region.eventBuf.push_back(0); region.eventBuf.push_back(0);
@@ -1271,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));
} }
@@ -1309,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
@@ -1318,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;
} }
} }
@@ -1340,7 +1356,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
head.swapBig(); head.swapBig();
*reinterpret_cast<SongState::Header*>(&*ret.insert(ret.cend(), 0x18, 0)) = head; *reinterpret_cast<SongState::Header*>(&*ret.insert(ret.cend(), 0x18, 0)) = head;
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
{ {
if (i >= trackRegionIdxArr.size()) if (i >= trackRegionIdxArr.size())
{ {
@@ -1349,8 +1365,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
} }
uint32_t idx = trackRegionIdxArr[i]; uint32_t idx = trackRegionIdxArr[i];
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = big ? SBig(uint32_t(0x18 + 4 * 64 + idx * 12)) : *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
uint32_t(0x18 + 4 * 64 + idx * 12); big ? SBig(uint32_t(0x18 + 4 * 64 + idx * 12)) : uint32_t(0x18 + 4 * 64 + idx * 12);
} }
for (SongState::TrackRegion& reg : regionBuf) for (SongState::TrackRegion& reg : regionBuf)
@@ -1358,8 +1374,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
uint32_t regBase = regIdxOff + 4 * regionDataIdxArr.size(); uint32_t regBase = regIdxOff + 4 * regionDataIdxArr.size();
for (uint32_t regOff : regionDataIdxArr) for (uint32_t regOff : regionDataIdxArr)
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = big ? SBig(uint32_t(regBase + regOff)) : *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
uint32_t(regBase + regOff); big ? SBig(uint32_t(regBase + regOff)) : uint32_t(regBase + regOff);
uint32_t curOffset = regBase; uint32_t curOffset = regBase;
for (Region& reg : regions) for (Region& reg : regions)
@@ -1368,15 +1384,15 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
if (reg.pitchBuf.size()) if (reg.pitchBuf.size())
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size())) : big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size()))
uint32_t(curOffset + 12 + reg.eventBuf.size()); : uint32_t(curOffset + 12 + reg.eventBuf.size());
else else
ret.insert(ret.cend(), 4, 0); ret.insert(ret.cend(), 4, 0);
if (reg.modBuf.size()) if (reg.modBuf.size())
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size())) : big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size()))
uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size()); : uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size());
else else
ret.insert(ret.cend(), 4, 0); ret.insert(ret.cend(), 4, 0);
@@ -1419,7 +1435,7 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
for (SongState::TrackRegion& reg : regionBuf) for (SongState::TrackRegion& reg : regionBuf)
*reinterpret_cast<SongState::TrackRegion*>(&*ret.insert(ret.cend(), 12, 0)) = reg; *reinterpret_cast<SongState::TrackRegion*>(&*ret.insert(ret.cend(), 12, 0)) = reg;
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
{ {
if (i >= trackRegionIdxArr.size()) if (i >= trackRegionIdxArr.size())
{ {
@@ -1428,8 +1444,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
} }
uint32_t idx = trackRegionIdxArr[i]; uint32_t idx = trackRegionIdxArr[i];
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = big ? SBig(uint32_t(0x18 + 4 * 64 + idx * 12)) : *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
uint32_t(0x18 + 4 * 64 + idx * 12); big ? SBig(uint32_t(0x18 + 4 * 64 + idx * 12)) : uint32_t(0x18 + 4 * 64 + idx * 12);
} }
memmove(&*ret.insert(ret.cend(), 64, 0), chanMap.data(), 64); memmove(&*ret.insert(ret.cend(), 64, 0), chanMap.data(), 64);
@@ -1442,15 +1458,15 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
if (reg.pitchBuf.size()) if (reg.pitchBuf.size())
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size())) : big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size()))
uint32_t(curOffset + 12 + reg.eventBuf.size()); : uint32_t(curOffset + 12 + reg.eventBuf.size());
else else
ret.insert(ret.cend(), 4, 0); ret.insert(ret.cend(), 4, 0);
if (reg.modBuf.size()) if (reg.modBuf.size())
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size())) : big ? SBig(uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size()))
uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size()); : uint32_t(curOffset + 12 + reg.eventBuf.size() + reg.pitchBuf.size());
else else
ret.insert(ret.cend(), 4, 0); ret.insert(ret.cend(), 4, 0);
@@ -1469,8 +1485,8 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
} }
for (uint32_t regOff : regionDataIdxArr) for (uint32_t regOff : regionDataIdxArr)
*reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) = big ? SBig(uint32_t(regBase + regOff)) : *reinterpret_cast<uint32_t*>(&*ret.insert(ret.cend(), 4, 0)) =
uint32_t(regBase + regOff); big ? SBig(uint32_t(regBase + regOff)) : uint32_t(regBase + regOff);
if (tempoBuf.size()) if (tempoBuf.size())
memmove(&*ret.insert(ret.cend(), tempoBuf.size() * 8, 0), tempoBuf.data(), tempoBuf.size() * 8); memmove(&*ret.insert(ret.cend(), tempoBuf.size() * 8, 0), tempoBuf.data(), tempoBuf.size() * 8);
@@ -1480,5 +1496,4 @@ std::vector<uint8_t> SongConverter::MIDIToSong(const std::vector<uint8_t>& data,
return ret; return ret;
} }
} }

View File

@@ -98,58 +98,54 @@ 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) : uint32_t regionIdx = (m_parent->m_bigEndian ? SBig(m_curRegion->m_regionIndex) : 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_parent.m_bigEndian ? SBig(m_parent.m_regionIdx[regionIdx]) : m_data = m_parent->m_songData +
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;
m_data += 4; m_data += 4;
} }
} }
void SongState::Track::advanceRegion(Sequencer* seq) void SongState::Track::advanceRegion(Sequencer* seq) { setRegion(seq, m_nextRegion); }
{
setRegion(seq, m_nextRegion);
}
int SongState::DetectVersion(const unsigned char* ptr, bool& isBig) int SongState::DetectVersion(const unsigned char* ptr, bool& isBig)
{ {
@@ -162,19 +158,19 @@ int SongState::DetectVersion(const unsigned char* ptr, bool& isBig)
/* First determine maximum index of MIDI regions across all tracks */ /* First determine maximum index of MIDI regions across all tracks */
uint32_t maxRegionIdx = 0; uint32_t maxRegionIdx = 0;
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
{ {
if (trackIdx[i]) if (trackIdx[i])
{ {
const TrackRegion* region = nullptr; const TrackRegion* region = nullptr;
const TrackRegion* nextRegion = reinterpret_cast<const TrackRegion*>(ptr + (isBig ? SBig(trackIdx[i]) : trackIdx[i])); const TrackRegion* nextRegion =
reinterpret_cast<const TrackRegion*>(ptr + (isBig ? SBig(trackIdx[i]) : trackIdx[i]));
/* Iterate all regions */ /* Iterate all regions */
while (nextRegion->indexValid(isBig)) while (nextRegion->indexValid(isBig))
{ {
region = nextRegion; region = nextRegion;
uint32_t regionIdx = (isBig ? SBig(region->m_regionIndex) : uint32_t regionIdx = (isBig ? SBig(region->m_regionIndex) : region->m_regionIndex);
region->m_regionIndex);
maxRegionIdx = std::max(maxRegionIdx, regionIdx); maxRegionIdx = std::max(maxRegionIdx, regionIdx);
nextRegion = &region[1]; nextRegion = &region[1];
} }
@@ -182,37 +178,37 @@ int SongState::DetectVersion(const unsigned char* ptr, bool& isBig)
} }
/* Perform 2 trials, first assuming revised format (more likely) */ /* Perform 2 trials, first assuming revised format (more likely) */
int v=1; int v = 1;
for (; v>=0 ; --v) for (; v >= 0; --v)
{ {
bool bad = false; bool bad = false;
/* Validate all tracks */ /* Validate all tracks */
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
{ {
if (trackIdx[i]) if (trackIdx[i])
{ {
const TrackRegion* region = nullptr; const TrackRegion* region = nullptr;
const TrackRegion* nextRegion = reinterpret_cast<const TrackRegion*>(ptr + (isBig ? SBig(trackIdx[i]) : trackIdx[i])); const TrackRegion* nextRegion =
reinterpret_cast<const TrackRegion*>(ptr + (isBig ? SBig(trackIdx[i]) : trackIdx[i]));
/* Iterate all regions */ /* Iterate all regions */
while (nextRegion->indexValid(isBig)) while (nextRegion->indexValid(isBig))
{ {
region = nextRegion; region = nextRegion;
uint32_t regionIdx = (isBig ? SBig(region->m_regionIndex) : uint32_t regionIdx = (isBig ? SBig(region->m_regionIndex) : region->m_regionIndex);
region->m_regionIndex);
nextRegion = &region[1]; nextRegion = &region[1];
const unsigned char* data = ptr + (isBig ? SBig(regionIdxTable[regionIdx]) : const unsigned char* data =
regionIdxTable[regionIdx]); ptr + (isBig ? SBig(regionIdxTable[regionIdx]) : regionIdxTable[regionIdx]);
/* Can't reliably validate final region */ /* Can't reliably validate final region */
if (regionIdx == maxRegionIdx) if (regionIdx == maxRegionIdx)
continue; continue;
/* Expected end pointer (next region) */ /* Expected end pointer (next region) */
const unsigned char* expectedEnd = ptr + (isBig ? SBig(regionIdxTable[regionIdx+1]) : const unsigned char* expectedEnd =
regionIdxTable[regionIdx+1]); ptr + (isBig ? SBig(regionIdxTable[regionIdx + 1]) : regionIdxTable[regionIdx + 1]);
Track::Header header = *reinterpret_cast<const Track::Header*>(data); Track::Header header = *reinterpret_cast<const Track::Header*>(data);
if (isBig) if (isBig)
@@ -223,7 +219,10 @@ int SongState::DetectVersion(const unsigned char* ptr, bool& isBig)
if (header.m_pitchOff) if (header.m_pitchOff)
{ {
const unsigned char* dptr = ptr + header.m_pitchOff; const unsigned char* dptr = ptr + header.m_pitchOff;
while (DecodeRLE(dptr) != 0xffffffff) {DecodeContinuousRLE(dptr);} while (DecodeRLE(dptr) != 0xffffffff)
{
DecodeContinuousRLE(dptr);
}
if (dptr >= (expectedEnd - 4) && (dptr <= expectedEnd)) if (dptr >= (expectedEnd - 4) && (dptr <= expectedEnd))
continue; continue;
} }
@@ -232,7 +231,10 @@ int SongState::DetectVersion(const unsigned char* ptr, bool& isBig)
if (header.m_modOff) if (header.m_modOff)
{ {
const unsigned char* dptr = ptr + header.m_modOff; const unsigned char* dptr = ptr + header.m_modOff;
while (DecodeRLE(dptr) != 0xffffffff) {DecodeContinuousRLE(dptr);} while (DecodeRLE(dptr) != 0xffffffff)
{
DecodeContinuousRLE(dptr);
}
if (dptr >= (expectedEnd - 4) && (dptr <= expectedEnd)) if (dptr >= (expectedEnd - 4) && (dptr <= expectedEnd))
continue; continue;
} }
@@ -337,15 +339,16 @@ bool SongState::initialize(const unsigned char* ptr)
const uint8_t* chanMap = reinterpret_cast<const uint8_t*>(ptr + m_header.m_chanMapOff); const uint8_t* chanMap = reinterpret_cast<const uint8_t*>(ptr + m_header.m_chanMapOff);
/* Initialize all tracks */ /* Initialize all tracks */
for (int i=0 ; i<64 ; ++i) for (int i = 0; i < 64; ++i)
{ {
if (trackIdx[i]) if (trackIdx[i])
{ {
const TrackRegion* region = reinterpret_cast<const TrackRegion*>(ptr + (m_bigEndian ? SBig(trackIdx[i]) : trackIdx[i])); const TrackRegion* region =
m_tracks[i].emplace(*this, chanMap[i], region); reinterpret_cast<const TrackRegion*>(ptr + (m_bigEndian ? SBig(trackIdx[i]) : trackIdx[i]));
m_tracks[i] = Track(*this, chanMap[i], region);
} }
else else
m_tracks[i] = std::experimental::nullopt; m_tracks[i] = Track();
} }
/* Initialize tempo */ /* Initialize tempo */
@@ -354,7 +357,7 @@ bool SongState::initialize(const unsigned char* ptr)
else else
m_tempoPtr = nullptr; m_tempoPtr = nullptr;
m_tempo = m_header.m_initialTempo; m_tempo = m_header.m_initialTempo & 0x7fffffff;
m_curTick = 0; m_curTick = 0;
m_songState = SongPlayState::Playing; m_songState = SongPlayState::Playing;
@@ -363,40 +366,40 @@ 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) : uint32_t nextRegTick = (m_parent->m_bigEndian ? SBig(m_nextRegion->m_startTick) : m_nextRegion->m_startTick);
m_nextRegion->m_startTick); if (uint32_t(endTick) > nextRegTick)
if (endTick > nextRegTick)
advanceRegion(&seq); advanceRegion(&seq);
else else
break; break;
} }
/* 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)
{ {
@@ -429,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)
{ {
@@ -460,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)
@@ -479,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)
{ {
@@ -501,8 +504,8 @@ 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;
m_data += 4; m_data += 4;
@@ -531,15 +534,15 @@ 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;
seq.keyOn(m_midiChan, note, vel); seq.keyOn(m_midiChan, note, vel);
@@ -562,8 +565,8 @@ 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;
m_data += 4; m_data += 4;
@@ -604,7 +607,7 @@ bool SongState::advance(Sequencer& seq, double dt)
if (remTicks <= 0) if (remTicks <= 0)
{ {
/* Turn over tempo */ /* Turn over tempo */
m_tempo = change.m_tempo; m_tempo = change.m_tempo & 0x7fffffff;
seq.setTempo(m_tempo * 384 / 60); seq.setTempo(m_tempo * 384 / 60);
++m_tempoPtr; ++m_tempoPtr;
continue; continue;
@@ -612,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;
@@ -628,5 +631,4 @@ bool SongState::advance(Sequencer& seq, double dt)
m_songState = SongPlayState::Stopped; m_songState = SongPlayState::Stopped;
return done; return done;
} }
} }

View File

@@ -4,14 +4,28 @@
#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 >.< */
#undef SendMessage #undef SendMessage
#undef GetMessage #undef GetMessage
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);
@@ -25,18 +39,17 @@ void SoundMacroState::Command::swapBig()
words[1] = SBig(words[1]); words[1] = SBig(words[1]);
} }
void SoundMacroState::Evaluator::addComponent(uint8_t midiCtrl, float scale, void SoundMacroState::Evaluator::addComponent(uint8_t midiCtrl, float scale, Combine combine, VarType varType)
Combine combine, VarType varType)
{ {
m_comps.push_back({midiCtrl, scale, combine, varType}); m_comps.push_back({midiCtrl, scale, combine, varType});
} }
float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroState& st) const float SoundMacroState::Evaluator::evaluate(double time, const Voice& vox, const SoundMacroState& st) const
{ {
float value = 0.f; float value = 0.f;
/* Iterate each component */ /* Iterate each component */
for (auto it=m_comps.cbegin() ; it != m_comps.cend() ; ++it) for (auto it = m_comps.cbegin(); it != m_comps.cend(); ++it)
{ {
const Component& comp = *it; const Component& comp = *it;
float thisValue = 0.f; float thisValue = 0.f;
@@ -57,12 +70,12 @@ float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroSta
case 130: case 130:
/* LFO1 */ /* LFO1 */
if (vox.m_lfoPeriods[0]) if (vox.m_lfoPeriods[0])
thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[0] * 2.f * M_PIF); thisValue = std::sin(time / vox.m_lfoPeriods[0] * 2.f * M_PIF);
break; break;
case 131: case 131:
/* LFO2 */ /* LFO2 */
if (vox.m_lfoPeriods[1]) if (vox.m_lfoPeriods[1])
thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[1] * 2.f * M_PIF); thisValue = std::sin(time / vox.m_lfoPeriods[1] * 2.f * M_PIF);
break; break;
case 132: case 132:
/* Surround panning */ /* Surround panning */
@@ -89,7 +102,7 @@ float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroSta
} }
} }
else if (comp.m_varType == VarType::Var) else if (comp.m_varType == VarType::Var)
thisValue = st.m_variables[std::max(0, std::min(255, int(comp.m_midiCtrl)))]; thisValue = st.m_variables[clamp(0, int(comp.m_midiCtrl), 255)];
/* Apply scale */ /* Apply scale */
thisValue *= comp.m_scale; thisValue *= comp.m_scale;
@@ -122,8 +135,8 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, bool swapDa
initialize(ptr, step, 1000.f, 0, 0, 0, swapData); initialize(ptr, step, 1000.f, 0, 0, 0, swapData);
} }
void SoundMacroState::initialize(const unsigned char* ptr, int step, double ticksPerSec, void SoundMacroState::initialize(const unsigned char* ptr, int step, double ticksPerSec, uint8_t midiKey,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool swapData) uint8_t midiVel, uint8_t midiMod, bool swapData)
{ {
m_ticksPerSec = ticksPerSec; m_ticksPerSec = ticksPerSec;
m_initKey = midiKey; m_initKey = midiKey;
@@ -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,10 +216,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
m_initKey, m_initVel, m_initMod);
} }
break; break;
@@ -219,10 +233,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
m_initKey, m_initVel, m_initMod);
} }
break; break;
@@ -289,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;
@@ -303,10 +316,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
m_initKey, m_initVel, m_initMod);
break; break;
} }
@@ -350,8 +362,8 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int8_t addNote = cmd.m_data[0]; int8_t addNote = cmd.m_data[0];
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]); ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]); int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
//int8_t priority = cmd.m_data[5]; // int8_t priority = cmd.m_data[5];
//int8_t maxVoices = cmd.m_data[6]; // int8_t maxVoices = cmd.m_data[6];
std::shared_ptr<Voice> sibVox = vox.startChildMacro(addNote, macroId, macroStep); std::shared_ptr<Voice> sibVox = vox.startChildMacro(addNote, macroId, macroStep);
if (sibVox) if (sibVox)
@@ -392,10 +404,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
m_initKey, m_initVel, m_initMod);
} }
break; break;
@@ -426,7 +437,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
bool orgVel = cmd.m_data[4]; bool orgVel = cmd.m_data[4];
int32_t eval = int32_t(orgVel ? m_initVel : m_curVel) * scale / 127 + add; int32_t eval = int32_t(orgVel ? m_initVel : m_curVel) * scale / 127 + add;
eval = std::max(0, std::min(127, eval)); eval = clamp(0, eval, 127);
if (curve != 0) if (curve != 0)
{ {
@@ -462,7 +473,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
double secTime = fadeTime / q; double secTime = fadeTime / q;
int32_t eval = int32_t(m_curVel) * scale / 127 + add; int32_t eval = int32_t(m_curVel) * scale / 127 + add;
eval = std::max(0, std::min(127, eval)); eval = clamp(0, eval, 127);
const Curve* curveData; const Curve* curveData;
if (curve != 0) if (curve != 0)
@@ -515,10 +526,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod);
m_initKey, m_initVel, m_initMod);
} }
break; break;
@@ -535,7 +545,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
float secTime = fadeTime / q; float secTime = fadeTime / q;
int32_t eval = int32_t(m_curVel) * scale / 127 + add; int32_t eval = int32_t(m_curVel) * scale / 127 + add;
eval = std::max(0, std::min(127, eval)); eval = clamp(0, eval, 127);
const Curve* curveData; const Curve* curveData;
if (curve != 0) if (curve != 0)
@@ -562,6 +572,15 @@ bool SoundMacroState::advance(Voice& vox, double dt)
m_midiDecay = cmd.m_data[1]; m_midiDecay = cmd.m_data[1];
m_midiSustain = cmd.m_data[2]; m_midiSustain = cmd.m_data[2];
m_midiRelease = cmd.m_data[3]; m_midiRelease = cmd.m_data[3];
/* Bootstrap ADSR defaults here */
if (!vox.getCtrlValue(m_midiSustain))
{
vox.setCtrlValue(m_midiAttack, 10);
vox.setCtrlValue(m_midiSustain, 127);
vox.setCtrlValue(m_midiRelease, 10);
}
break; break;
} }
case Op::RndNote: case Op::RndNote:
@@ -670,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:
@@ -772,10 +791,9 @@ 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, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, m_initKey, m_initVel, m_initMod, true);
m_initKey, m_initVel, m_initMod, true);
m_header = *reinterpret_cast<const Header*>(m_pc.back().first); m_header = *reinterpret_cast<const Header*>(m_pc.back().first);
if (vox.getAudioGroup().getDataFormat() != DataFormat::PC) if (vox.getAudioGroup().getDataFormat() != DataFormat::PC)
@@ -804,7 +822,8 @@ bool SoundMacroState::advance(Voice& vox, double dt)
vox.m_messageTrap.macroId = macroId; vox.m_messageTrap.macroId = macroId;
vox.m_messageTrap.macroStep = macroStep; vox.m_messageTrap.macroStep = macroStep;
break; break;
default: break; default:
break;
} }
break; break;
@@ -827,7 +846,8 @@ bool SoundMacroState::advance(Voice& vox, double dt)
vox.m_messageTrap.macroId = 0xffff; vox.m_messageTrap.macroId = 0xffff;
vox.m_messageTrap.macroStep = -1; vox.m_messageTrap.macroStep = -1;
break; break;
default: break; default:
break;
} }
break; break;
@@ -871,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:
@@ -1200,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;
} }
@@ -1224,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;
} }
@@ -1237,14 +1257,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
return false; return false;
} }
void SoundMacroState::keyoffNotify(Voice& vox) void SoundMacroState::keyoffNotify(Voice& vox) { m_keyoff = true; }
{
m_keyoff = true;
}
void SoundMacroState::sampleEndNotify(Voice& vox)
{
m_sampleEnd = true;
}
void SoundMacroState::sampleEndNotify(Voice& vox) { m_sampleEnd = true; }
} }

40
lib/Studio.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "amuse/Studio.hpp"
#include "amuse/Engine.hpp"
namespace amuse
{
#ifndef NDEBUG
bool Studio::_cyclicCheck(Studio* leaf)
{
for (auto it = m_studiosOut.begin(); it != m_studiosOut.end();)
{
if (leaf == it->m_targetStudio.get() || it->m_targetStudio->_cyclicCheck(leaf))
return true;
++it;
}
return false;
}
#endif
Studio::Studio(Engine& engine, bool mainOut) : m_engine(engine), m_master(engine), m_auxA(engine), m_auxB(engine)
{
if (mainOut && engine.m_defaultStudioReady)
addStudioSend(engine.getDefaultStudio(), 1.f, 1.f, 1.f);
}
void Studio::addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
{
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
/* Cyclic check */
assert(!_cyclicCheck(this));
}
void Studio::resetOutputSampleRate(double sampleRate)
{
m_master.resetOutputSampleRate(sampleRate);
m_auxA.resetOutputSampleRate(sampleRate);
m_auxB.resetOutputSampleRate(sampleRate);
}
}

View File

@@ -3,37 +3,49 @@
namespace amuse namespace amuse
{ {
void Submix::_destroy() Submix::Submix(Engine& engine) : m_root(engine) {}
{
m_destroyed = true;
}
Submix::Submix(Engine& engine, Submix* smx)
: m_root(engine), m_submix(smx)
{}
EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period) EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period)
{ {
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);
} }
EffectReverbStd& Submix::makeReverbStd(float coloration, float mix, float time, EffectDelay& Submix::makeDelay(const EffectDelayInfo& info)
float damping, float preDelay) {
return makeEffect<EffectDelay>(info);
}
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);
} }
EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, EffectReverbStd& Submix::makeReverbStd(const EffectReverbStdInfo& info)
float damping, float preDelay, float crosstalk) {
return makeEffect<EffectReverbStd>(info);
}
EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
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)
@@ -57,5 +69,4 @@ void Submix::resetOutputSampleRate(double sampleRate)
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack) for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
effect->resetOutputSampleRate(sampleRate); effect->resetOutputSampleRate(sampleRate);
} }
} }

View File

@@ -1,175 +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;
}
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More