diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d1f4f..9354698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ - added `loadMem()` to read the give audio file bytes buffer (not RAW data). Useful for the Web platform. - fixed `getFilterParamNames()`. - added `AudioData` class to manage audio samples. +- added player initialization parameters: sample rate, buffer size, number of channels (mono, stereo, quad, 5.1, 7.1). +- added voice groups. +- it's now possible to set filters not only globally, but also to single audio sources. +- fade and oscillate filter parameters. ### 2.0.2 (23 May 2024) - Fixed wrong exception raised by `setVolume()` when a handle is no more valid. diff --git a/example/lib/ui/filter_fx.dart b/example/lib/ui/filter_fx.dart index c768e18..97b9347 100644 --- a/example/lib/ui/filter_fx.dart +++ b/example/lib/ui/filter_fx.dart @@ -75,7 +75,7 @@ class _FilterFxState extends State { } for (var i = 0; i < params.length; i++) { params[i] = SoLoud.instance - .getFilterParameter(widget.filterType, i); + .getGlobalFilterParameter(widget.filterType, i); } } else { try { @@ -102,7 +102,7 @@ class _FilterFxState extends State { onChanged: (value) async { params[index] = value; SoLoud.instance - .setFilterParameter(widget.filterType, index, value); + .setGlobalFilterParameter(widget.filterType, index, value); if (mounted) setState(() {}); }, ); diff --git a/example/pubspec.lock b/example/pubspec.lock index 5ca483a..a86bf3a 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -92,7 +92,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2" + version: "2.1.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 092d222..0000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/example/tests/tests.dart b/example/tests/tests.dart index 5688e73..3a3b86a 100644 --- a/example/tests/tests.dart +++ b/example/tests/tests.dart @@ -11,12 +11,6 @@ enum TestStatus { failed, } -typedef TestFunction = ({ - String name, - Future Function() callback, - TestStatus status, -}); - /// A GUI for tests. /// /// Run this with `flutter run tests/tests.dart`. @@ -39,6 +33,18 @@ void main() { ); } +class _Test { + _Test({ + required this.name, + required this.callback, + // ignore: unused_element + this.status = TestStatus.none, + }); + final String name; + final Future Function() callback; + TestStatus status; +} + class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @@ -48,7 +54,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final output = StringBuffer(); - final List tests = []; + final List<_Test> tests = []; final textEditingController = TextEditingController(); @override @@ -57,51 +63,21 @@ class _MyHomePageState extends State { /// Add all testing functions. tests.addAll([ - ( - name: 'testProtectVoice', - status: TestStatus.none, - callback: testProtectVoice, - ), - ( + _Test(name: 'testProtectVoice', callback: testProtectVoice), + _Test( name: 'testAllInstancesFinished', - status: TestStatus.none, callback: testAllInstancesFinished, ), - ( - name: 'testCreateNotes', - status: TestStatus.none, - callback: testCreateNotes, - ), - ( - name: 'testPlaySeekPause', - status: TestStatus.none, - callback: testPlaySeekPause, - ), - ( - name: 'testPan', - status: TestStatus.none, - callback: testPan, - ), - ( - name: 'testHandles', - status: TestStatus.none, - callback: testHandles, - ), - ( - name: 'loopingTests', - status: TestStatus.none, - callback: loopingTests, - ), - ( - name: 'testSynchronousDeinit', - status: TestStatus.none, - callback: testSynchronousDeinit, - ), - ( - name: 'testAsynchronousDeinit', - status: TestStatus.none, - callback: testAsynchronousDeinit, - ), + _Test(name: 'testCreateNotes', callback: testCreateNotes), + _Test(name: 'testPlaySeekPause', callback: testPlaySeekPause), + _Test(name: 'testPan', callback: testPan), + _Test(name: 'testHandles', callback: testHandles), + _Test(name: 'loopingTests', callback: loopingTests), + _Test(name: 'testSynchronousDeinit', callback: testSynchronousDeinit), + _Test(name: 'testAsynchronousDeinit', callback: testAsynchronousDeinit), + _Test(name: 'testVoiceGroups', callback: testVoiceGroups), + _Test(name: 'testSoundFilters', callback: testSoundFilters), + _Test(name: 'testGlobalFilters', callback: testGlobalFilters), ]); } @@ -187,16 +163,13 @@ class _MyHomePageState extends State { ..write(await tests[index].callback()) ..write('===== PASSED! =====\n\n') ..writeln(); - tests[index] = ( - name: tests[index].name, - status: TestStatus.passed, - callback: tests[index].callback, - ); + tests[index].status = TestStatus.passed; textEditingController.text = output.toString(); debugPrint(output.toString()); if (context.mounted) setState(() {}); }, (error, stack) { + deinit(); // if (error is SoLoudInitializationStoppedByDeinitException) { // // This is to be expected in this test. // return; @@ -209,11 +182,7 @@ class _MyHomePageState extends State { ..writeln() ..writeln(); // ignore: parameter_assignments - tests[index] = ( - name: tests[index].name, - status: TestStatus.failed, - callback: tests[index].callback, - ); + tests[index].status = TestStatus.failed; textEditingController.text = output.toString(); debugPrint(output.toString()); if (context.mounted) setState(() {}); @@ -311,7 +280,7 @@ Future testProtectVoice() async { /// Test allInstancesFinished stream Future testAllInstancesFinished() async { - final ret = StringBuffer(); + final strBuf = StringBuffer(); await initialize(); await SoLoud.instance.disposeAllSources(); @@ -330,14 +299,14 @@ Future testAllInstancesFinished() async { var songDisposed = false; unawaited( explosion.allInstancesFinished.first.then((_) async { - ret.write('All instances of explosion finished.\n'); + strBuf.write('All instances of explosion finished.\n'); await SoLoud.instance.disposeSource(explosion); explosionDisposed = true; }), ); unawaited( song.allInstancesFinished.first.then((_) async { - ret.write('All instances of song finished.\n'); + strBuf.write('All instances of song finished.\n'); await SoLoud.instance.disposeSource(song); songDisposed = true; }), @@ -359,7 +328,7 @@ Future testAllInstancesFinished() async { deinit(); - return ret; + return strBuf; } /// Test waveform @@ -676,3 +645,186 @@ Future testSynchronousDeinit() async { return StringBuffer(); } + +/// Test voice groups. +Future testVoiceGroups() async { + await initialize(); + + final currentSound = + await SoLoud.instance.loadAsset('assets/audio/explosion.mp3'); + + /// Start playing sounds in pause state to get their handles. + final h1 = await SoLoud.instance.play(currentSound, paused: true); + final h2 = await SoLoud.instance.play(currentSound, paused: true); + final h3 = await SoLoud.instance.play(currentSound, paused: true); + final h4 = await SoLoud.instance.play(currentSound, paused: true); + + final group = SoLoud.instance.createVoiceGroup(); + assert(!group.isError, 'Failed to create voice group!'); + + var isValid = SoLoud.instance.isVoiceGroup(group); + assert(isValid, 'Voice group created but it is not valid!'); + + var isEmpty = SoLoud.instance.isVoiceGroupEmpty(group); + assert(isEmpty, 'Voice group just created but it is not empty!'); + + /// Add all voices to the group. + SoLoud.instance.addVoicesToGroup(group, [h1, h2, h3, h4]); + isEmpty = SoLoud.instance.isVoiceGroupEmpty(group); + assert(!isEmpty, 'Voices added to the group, but the group is empty!'); + + /// Start playing the voices in the group. + SoLoud.instance.setPause(group, false); + + await delay(4000); + + /// Check if group is empty after playing voices. + isEmpty = SoLoud.instance.isVoiceGroupEmpty(group); + assert( + isEmpty, + 'Voices added and finished to play, but the group is not empty!', + ); + + /// Destroy the group + SoLoud.instance.destroyVoiceGroup(group); + isValid = SoLoud.instance.isVoiceGroup(group); + assert(!isValid, 'Voice group destroy failed!'); + + deinit(); + return StringBuffer(); +} + +/// Test sound filters. +Future testSoundFilters() async { + final strBuf = StringBuffer(); + await initialize(); + + final sound = await SoLoud.instance.loadAsset( + 'assets/audio/8_bit_mentality.mp3', + // mode: LoadMode.disk, + ); + + /// Add filter to the sound. + sound.addFilter(FilterType.echoFilter); + + /// Set a handle filter. It must be set before it starts playing. + final h1 = await SoLoud.instance.play(sound); + + /// Use the `Wet` attribute index. + const attributeId = 0; + const value = 1.2; + sound.setFilterParameter( + h1, + FilterType.echoFilter, + attributeId, + value, + ); + final g = sound.getFilterParameter(h1, FilterType.echoFilter, attributeId); + assert( + closeTo(g, value, 0.001), + 'Setting attribute to $value but obtained $g', + ); + + sound.oscillateFilterParameter( + h1, + FilterType.echoFilter, + attributeId, + 0.01, + 2, + const Duration(seconds: 2), + ); + + assert( + sound.isFilterActive(FilterType.echoFilter) >= 0, + 'The filter is not active!', + ); + + await delay(6000); + + /// Remove the filter + try { + sound.removeFilter(FilterType.echoFilter); + } on Exception catch (e) { + strBuf + ..write(e) + ..writeln(); + } + assert( + sound.isFilterActive(FilterType.echoFilter) < 0, + 'The filter is still active after removing it!', + ); + + deinit(); + return strBuf; +} + +/// Test global filters. +Future testGlobalFilters() async { + final strBuf = StringBuffer(); + await initialize(); + + late final AudioSource sound; + try { + sound = await SoLoud.instance.loadAsset( + 'assets/audio/8_bit_mentality.mp3', + mode: LoadMode.disk, + ); + } on Exception catch (e) { + strBuf + ..write(e) + ..writeln(); + } + + /// Add filter to the sound. + SoLoud.instance.addGlobalFilter(FilterType.echoFilter); + + await SoLoud.instance.play(sound); + + /// Use the `Wet` attribute index. + const attributeId = 0; + const value = 1.2; + SoLoud.instance.setGlobalFilterParameter( + FilterType.echoFilter, + attributeId, + value, + ); + final g = SoLoud.instance.getGlobalFilterParameter( + FilterType.echoFilter, + attributeId, + ); + assert( + closeTo(g, value, 0.001), + 'Setting attribute to $value but optained $g', + ); + + SoLoud.instance.oscillateGlobalFilterParameter( + FilterType.echoFilter, + attributeId, + 0.01, + 2, + const Duration(seconds: 2), + ); + + assert( + SoLoud.instance.isFilterActive(FilterType.echoFilter) >= 0, + 'The filter is not active!', + ); + + await delay(6000); + + /// Remove the filter + try { + SoLoud.instance.removeGlobalFilter(FilterType.echoFilter); + } on Exception catch (e) { + strBuf + ..write(e) + ..writeln(); + } + assert( + SoLoud.instance.isFilterActive(FilterType.echoFilter) < 0, + 'The filter is still active after removing it!', + ); + + deinit(); + return strBuf; +} diff --git a/lib/src/audio_source.dart b/lib/src/audio_source.dart index 3298c24..d276815 100644 --- a/lib/src/audio_source.dart +++ b/lib/src/audio_source.dart @@ -1,8 +1,15 @@ import 'dart:async'; import 'dart:collection'; +import 'package:flutter_soloud/src/bindings/bindings_player.dart'; +import 'package:flutter_soloud/src/bindings/soloud_controller.dart'; +import 'package:flutter_soloud/src/enums.dart'; +import 'package:flutter_soloud/src/exceptions/exceptions.dart'; +import 'package:flutter_soloud/src/filter_params.dart'; +import 'package:flutter_soloud/src/soloud.dart'; import 'package:flutter_soloud/src/sound_handle.dart'; import 'package:flutter_soloud/src/sound_hash.dart'; +import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; /// the type sent back to the user when a sound event occurs @@ -37,11 +44,25 @@ enum SoundEventType { /// You can access the currently playing instances' handles via [handles]. /// /// You can listen to the broadcast stream of [soundEvents]. +/// +/// Every [AudioSource] can have their own filters. You can add, remove and +/// query wether a filter is active with `addFilter()`, +/// `removeGlobalFilter()` and `isFilterActive()`, respectively. The effect must +/// be set before playing the sound and parameters can be changed after having +/// the a voice handle: +/// ``` +/// final sound = await SoLoud.instance.loadAsset('...'); +/// sound.addFilter(FilterType.echoFilter); +/// final handle = SoLoud.instance.play(sound, paused: true); +/// sound.setFilterParameter(); +/// ``` class AudioSource { /// Constructs an instance of [AudioSource]. @internal AudioSource(this.soundHash); + static final Logger _log = Logger('flutter_soloud.AudioSource'); + /// The hash uniquely identifying this loaded sound. final SoundHash soundHash; @@ -68,8 +89,6 @@ class AudioSource { @internal final Set handlesInternal = {}; - // TODO(marco): make marker keys time able to trigger an event - /// Backing controller for [soundEvents]. @internal late final StreamController soundEventsController = @@ -103,6 +122,185 @@ class AudioSource { Stream get allInstancesFinished => allInstancesFinishedController.stream; + // /////////////////////////////////////// + // / Filters for this [soundHash] + // /////////////////////////////////////// + + /// Checks whether the given [filterType] is active. + /// + /// Returns `-1` if the filter is not active. Otherwise, returns + /// the index of the given filter. + int isFilterActive(FilterType filterType) { + final ret = SoLoudController().soLoudFFI.isFilterActive( + filterType, + soundHash: soundHash, + ); + if (ret.error != PlayerErrors.noError) { + _log.severe(() => 'isFilterActive(): ${ret.error}'); + throw SoLoudCppException.fromPlayerError(ret.error); + } + return ret.index; + } + + /// Adds a [filterType] to this sound. + /// + /// Throws [SoLoudMaxFilterNumberReachedException] when the max number of + /// concurrent filter is reached (default max filter is 8). + /// Throws [SoLoudFilterAlreadyAddedException] when trying to add a filter + /// that has already been added. + PlayerErrors addFilter(FilterType filterType) { + final error = SoLoudController().soLoudFFI.addFilter( + filterType, + soundHash: soundHash, + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'addGlobalFilter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + return error; + } + + /// Removes [filterType] from all sounds. + PlayerErrors removeFilter(FilterType filterType) { + final error = SoLoudController().soLoudFFI.removeFilter( + filterType, + soundHash: soundHash, + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'removeGlobalFilter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + return error; + } + + /// Set the effect parameter with id [attributeId] of [filterType] + /// with [value] value. + /// + /// Specify the [attributeId] of the parameter (which you can learn from + /// [SoLoud.getFilterParamNames]), and its new [value]. + /// + /// [handle] the handle to set the filter to. + /// [filterType] filter to modify a param. + /// Returns [PlayerErrors.noError] if no errors. + PlayerErrors setFilterParameter( + SoundHandle handle, + FilterType filterType, + int attributeId, + double value, + ) { + final error = SoLoudController().soLoudFFI.setFilterParams( + filterType, + attributeId, + value, + handle: handle, + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'setFxParams(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + return error; + } + + /// Get the effect parameter value with id [attributeId] of [filterType]. + /// + /// Specify the [attributeId] of the parameter (which you can learn from + /// [SoLoud.getFilterParamNames]). + /// + /// [handle] the handle to get the attribute value from. If equal to 0, + /// it gets the global filter value. + /// [filterType] the filter to modify a parameter. + /// Returns the value of the parameter. + double getFilterParameter( + SoundHandle handle, + FilterType filterType, + int attributeId, + ) { + final ret = SoLoudController().soLoudFFI.getFilterParams( + filterType, + attributeId, + handle: handle, + ); + if (ret.error == PlayerErrors.filterNotFound) { + throw const SoLoudFilterNotFoundException(); + } + if (ret.error == PlayerErrors.soundHandleNotFound) { + throw const SoLoudSoundHandleNotFoundCppException(); + } + if (ret.error != PlayerErrors.noError) { + throw SoLoudCppException.fromPlayerError(ret.error); + } + return ret.value; + } + + /// Fade a parameter of a filter. + /// + /// [handle] the handle of the voice to apply the fade. If equal to 0, + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [to] value the attribute should go in [time] duration. + /// [time] the fade slope duration. + /// + /// Throws [SoLoudNotInitializedException] if the engine is not initialized. + void fadeFilterParameter( + SoundHandle handle, + FilterType filterType, + int attributeId, + double to, + Duration time, + ) { + if (!SoLoud.instance.isInitialized) { + throw const SoLoudNotInitializedException(); + } + final error = SoLoudController().soLoudFFI.fadeFilterParameter( + filterType, + attributeId, + to, + time.toDouble(), + handle: handle, + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'fadeFilterParameter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + } + + /// Oscillate a parameter of a filter. + /// + /// [handle] the handle of the voice to apply the fade. If equal to 0, + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [from] the starting value the attribute sould start to oscillate. + /// [to] the ending value the attribute sould end to oscillate. + /// [time] the fade slope duration. + /// + /// Throws [SoLoudNotInitializedException] if the engine is not initialized. + void oscillateFilterParameter( + SoundHandle handle, + FilterType filterType, + int attributeId, + double from, + double to, + Duration time, + ) { + if (!SoLoud.instance.isInitialized) { + throw const SoLoudNotInitializedException(); + } + final error = SoLoudController().soLoudFFI.oscillateFilterParameter( + filterType, + attributeId, + from, + to, + time.toDouble(), + handle: handle, + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'oscillateFilterParameter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + } + @override String toString() { return 'soundHash: $soundHash has ${handles.length} active handles'; diff --git a/lib/src/bindings/bindings_player.dart b/lib/src/bindings/bindings_player.dart index 79e8b9a..8a7867d 100644 --- a/lib/src/bindings/bindings_player.dart +++ b/lib/src/bindings/bindings_player.dart @@ -52,9 +52,19 @@ abstract class FlutterSoLoud { /// Initialize the player. Must be called before any other player functions. /// + /// [sampleRate] the sample rate. Usually is 22050, 44100 (CD quality) + /// or 48000. + /// [bufferSize] the audio buffer size. Usually is 2048, but can be also be + /// lowered if less latency is needed. + /// [channels] mono, stereo, quad, 5.1, 7.1. + /// /// Returns [PlayerErrors.noError] if success. @mustBeOverridden - PlayerErrors initEngine(); + PlayerErrors initEngine( + int sampleRate, + int bufferSize, + Channels channels, + ); /// Must be called when the player is no more needed or when closing the app. @mustBeOverridden @@ -483,37 +493,78 @@ abstract class FlutterSoLoud { @mustBeOverridden void setMaxActiveVoiceCount(int maxVoiceCount); + ///////////////////////////////////////// + /// voice groups + ///////////////////////////////////////// + + /// Used to create a new voice group. Returns 0 if not successful. + SoundHandle createVoiceGroup(); + + /// Deallocates the voice group. Does not stop the voices attached to the + /// voice group. + /// + /// [handle] the group handle to destroy. + void destroyVoiceGroup(SoundHandle handle); + + /// Adds voice handle to the voice group. The voice handles can still be + /// used separate from the group. + /// [voiceGroupHandle] the group handle to add the new [voiceHandles]. + /// [voiceHandles] voice handles list to add to the [voiceGroupHandle]. + void addVoicesToGroup( + SoundHandle voiceGroupHandle, + List voiceHandles, + ); + + /// Checks if the handle is a valid voice group. Does not care if the + /// voice group is empty. + /// + /// [handle] the group handle to check. + /// Return true if [handle] is a group handle. + bool isVoiceGroup(SoundHandle handle); + + /// Checks whether a voice group is empty. SoLoud automatically trims + /// the voice groups of voices that have ended, so the group may be + /// empty even though you've added valid voice handles to it. + /// + /// [handle] group handle to check. + /// Return true if the group handle doesn't have any voices. + bool isVoiceGroupEmpty(SoundHandle handle); + // /////////////////////////////////////// // faders // /////////////////////////////////////// /// Smoothly change the global volume over specified [duration]. @mustBeOverridden - int fadeGlobalVolume(double to, Duration duration); + PlayerErrors fadeGlobalVolume(double to, Duration duration); /// Smoothly change a channel's volume over specified [duration]. @mustBeOverridden - int fadeVolume(SoundHandle handle, double to, Duration duration); + PlayerErrors fadeVolume(SoundHandle handle, double to, Duration duration); /// Smoothly change a channel's pan setting over specified [duration]. @mustBeOverridden - int fadePan(SoundHandle handle, double to, Duration duration); + PlayerErrors fadePan(SoundHandle handle, double to, Duration duration); /// Smoothly change a channel's relative play speed over specified time. @mustBeOverridden - int fadeRelativePlaySpeed(SoundHandle handle, double to, Duration time); + PlayerErrors fadeRelativePlaySpeed( + SoundHandle handle, + double to, + Duration time, + ); /// After specified [duration], pause the channel. @mustBeOverridden - int schedulePause(SoundHandle handle, Duration duration); + PlayerErrors schedulePause(SoundHandle handle, Duration duration); /// After specified time, stop the channel. @mustBeOverridden - int scheduleStop(SoundHandle handle, Duration duration); + PlayerErrors scheduleStop(SoundHandle handle, Duration duration); /// Set fader to oscillate the volume at specified frequency. @mustBeOverridden - int oscillateVolume( + PlayerErrors oscillateVolume( SoundHandle handle, double from, double to, @@ -522,11 +573,16 @@ abstract class FlutterSoLoud { /// Set fader to oscillate the panning at specified frequency. @mustBeOverridden - int oscillatePan(SoundHandle handle, double from, double to, Duration time); + PlayerErrors oscillatePan( + SoundHandle handle, + double from, + double to, + Duration time, + ); /// Set fader to oscillate the relative play speed at specified frequency. @mustBeOverridden - int oscillateRelativePlaySpeed( + PlayerErrors oscillateRelativePlaySpeed( SoundHandle handle, double from, double to, @@ -535,7 +591,45 @@ abstract class FlutterSoLoud { /// Set fader to oscillate the global volume at specified frequency. @mustBeOverridden - int oscillateGlobalVolume(double from, double to, Duration time); + PlayerErrors oscillateGlobalVolume(double from, double to, Duration time); + + /// Fade a parameter of a filter. + /// + /// [handle] the handle of the voice to apply the fade. If equal to 0, + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [to] value the attribute should go in [time] duration. + /// [time] the fade slope duration. + /// Returns [PlayerErrors.noError] if no errors. + @mustBeOverridden + PlayerErrors fadeFilterParameter( + FilterType filterType, + int attributeId, + double to, + double time, { + SoundHandle handle = const SoundHandle(0), + }); + + /// Oscillate a parameter of a filter. + /// + /// [handle] the handle of the voice to apply the fade. If equal to 0, + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [from] the starting value the attribute sould start to oscillate. + /// [to] the ending value the attribute sould end to oscillate. + /// [time] the fade slope duration. + /// Returns [PlayerErrors.noError] if no errors. + @mustBeOverridden + PlayerErrors oscillateFilterParameter( + FilterType filterType, + int attributeId, + double from, + double to, + double time, { + SoundHandle handle = const SoundHandle(0), + }); // /////////////////////////////////////// // Filters @@ -547,7 +641,10 @@ abstract class FlutterSoLoud { /// Returns [PlayerErrors.noError] if no errors and the index of /// the active filter (-1 if the filter is not active). @mustBeOverridden - ({PlayerErrors error, int index}) isFilterActive(FilterType filterType); + ({PlayerErrors error, int index}) isFilterActive( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }); /// Get parameters names of the given filter. /// @@ -569,29 +666,48 @@ abstract class FlutterSoLoud { /// [PlayerErrors.maxNumberOfFiltersReached] when the maximum number of /// filters has been reached (default is 8). @mustBeOverridden - PlayerErrors addGlobalFilter(FilterType filterType); + PlayerErrors addFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }); /// Remove the filter [filterType]. /// /// [filterType] filter to remove. /// Returns [PlayerErrors.noError] if no errors. @mustBeOverridden - int removeGlobalFilter(FilterType filterType); + PlayerErrors removeFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }); /// Set the effect parameter with id [attributeId] of [filterType] /// with [value] value. /// + /// [handle] the handle to set the filter to. If equal to 0, the filter is + /// applyed to the global filter. /// [filterType] filter to modify a param. /// Returns [PlayerErrors.noError] if no errors. @mustBeOverridden - int setFilterParams(FilterType filterType, int attributeId, double value); + PlayerErrors setFilterParams( + FilterType filterType, + int attributeId, + double value, { + SoundHandle handle = const SoundHandle.error(), + }); - /// Get the effect parameter with id [attributeId] of [filterType]. + /// Get the effect parameter value with id [attributeId] of [filterType]. /// + /// [handle] the handle to get the attribute value from. If equal to 0, + /// it gets the global filter. /// [filterType] the filter to modify a parameter. /// Returns the value of the parameter. @mustBeOverridden - double getFilterParams(FilterType filterType, int attributeId); + ({PlayerErrors error, double value}) getFilterParams( + FilterType filterType, + int attributeId, { + SoundHandle handle = const SoundHandle.error(), + }); // /////////////////////////////////////// // 3D audio methods diff --git a/lib/src/bindings/bindings_player_ffi.dart b/lib/src/bindings/bindings_player_ffi.dart index 2a8dd3b..9cc28b8 100644 --- a/lib/src/bindings/bindings_player_ffi.dart +++ b/lib/src/bindings/bindings_player_ffi.dart @@ -163,13 +163,21 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _nativeFreePtr.asFunction)>(); @override - PlayerErrors initEngine() { - return PlayerErrors.values[_initEngine()]; + PlayerErrors initEngine(int sampleRate, int bufferSize, Channels channels) { + final ret = _initEngine( + sampleRate, + bufferSize, + channels.count, + ); + return PlayerErrors.values[ret]; } - late final _initEnginePtr = - _lookup>('initEngine'); - late final _initEngine = _initEnginePtr.asFunction(); + late final _initEnginePtr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function(ffi.UnsignedInt, ffi.UnsignedInt, + ffi.UnsignedInt)>>('initEngine'); + late final _initEngine = + _initEnginePtr.asFunction(); @override void deinit() { @@ -837,13 +845,79 @@ class FlutterSoLoudFfi extends FlutterSoLoud { late final _setMaxActiveVoiceCount = _setMaxActiveVoiceCountPtr.asFunction(); + ///////////////////////////////////////// + /// voice groups + ///////////////////////////////////////// + + @override + SoundHandle createVoiceGroup() { + final ret = _createVoiceGroup(); + return SoundHandle(ret > 0 ? ret : -1); + } + + late final _createVoiceGroupPtr = + _lookup>( + 'createVoiceGroup'); + late final _createVoiceGroup = + _createVoiceGroupPtr.asFunction(); + + @override + void destroyVoiceGroup(SoundHandle handle) { + return _destroyVoiceGroup(handle.id); + } + + late final _destroyVoiceGroupPtr = + _lookup>( + 'destroyVoiceGroup'); + late final _destroyVoiceGroup = + _destroyVoiceGroupPtr.asFunction(); + + @override + void addVoicesToGroup( + SoundHandle voiceGroupHandle, + List voiceHandles, + ) { + for (final handle in voiceHandles) { + _addVoiceToGroup(voiceGroupHandle.id, handle.id); + } + } + + late final _addVoiceToGroupPtr = _lookup< + ffi + .NativeFunction>( + 'addVoiceToGroup'); + late final _addVoiceToGroup = + _addVoiceToGroupPtr.asFunction(); + + @override + bool isVoiceGroup(SoundHandle handle) { + return _isVoiceGroup(handle.id) == 1; + } + + late final _isVoiceGroupPtr = + _lookup>( + 'isVoiceGroup'); + late final _isVoiceGroup = _isVoiceGroupPtr.asFunction(); + + @override + bool isVoiceGroupEmpty(SoundHandle handle) { + return _isVoiceGroupEmpty(handle.id) == 1; + } + + late final _isVoiceGroupEmptyPtr = + _lookup>( + 'isVoiceGroupEmpty'); + late final _isVoiceGroupEmpty = + _isVoiceGroupEmptyPtr.asFunction(); + ///////////////////////////////////////// /// faders ///////////////////////////////////////// @override - int fadeGlobalVolume(double to, Duration duration) { - return _fadeGlobalVolume(to, duration.toDouble()); + PlayerErrors fadeGlobalVolume(double to, Duration duration) { + final e = _fadeGlobalVolume(to, duration.toDouble()); + return PlayerErrors.values[e]; } late final _fadeGlobalVolumePtr = @@ -853,8 +927,9 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _fadeGlobalVolumePtr.asFunction(); @override - int fadeVolume(SoundHandle handle, double to, Duration duration) { - return _fadeVolume(handle.id, to, duration.toDouble()); + PlayerErrors fadeVolume(SoundHandle handle, double to, Duration duration) { + final e = _fadeVolume(handle.id, to, duration.toDouble()); + return PlayerErrors.values[e]; } late final _fadeVolumePtr = _lookup< @@ -865,8 +940,9 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _fadeVolumePtr.asFunction(); @override - int fadePan(SoundHandle handle, double to, Duration duration) { - return _fadePan(handle.id, to, duration.toDouble()); + PlayerErrors fadePan(SoundHandle handle, double to, Duration duration) { + final e = _fadePan(handle.id, to, duration.toDouble()); + return PlayerErrors.values[e]; } late final _fadePanPtr = _lookup< @@ -877,8 +953,13 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _fadePanPtr.asFunction(); @override - int fadeRelativePlaySpeed(SoundHandle handle, double to, Duration time) { - return _fadeRelativePlaySpeed(handle.id, to, time.toDouble()); + PlayerErrors fadeRelativePlaySpeed( + SoundHandle handle, + double to, + Duration time, + ) { + final e = _fadeRelativePlaySpeed(handle.id, to, time.toDouble()); + return PlayerErrors.values[e]; } late final _fadeRelativePlaySpeedPtr = _lookup< @@ -889,8 +970,9 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _fadeRelativePlaySpeedPtr.asFunction(); @override - int schedulePause(SoundHandle handle, Duration duration) { - return _schedulePause(handle.id, duration.toDouble()); + PlayerErrors schedulePause(SoundHandle handle, Duration duration) { + final e = _schedulePause(handle.id, duration.toDouble()); + return PlayerErrors.values[e]; } late final _schedulePausePtr = _lookup< @@ -900,8 +982,9 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _schedulePausePtr.asFunction(); @override - int scheduleStop(SoundHandle handle, Duration duration) { - return _scheduleStop(handle.id, duration.toDouble()); + PlayerErrors scheduleStop(SoundHandle handle, Duration duration) { + final e = _scheduleStop(handle.id, duration.toDouble()); + return PlayerErrors.values[e]; } late final _scheduleStopPtr = _lookup< @@ -911,9 +994,10 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _scheduleStopPtr.asFunction(); @override - int oscillateVolume( + PlayerErrors oscillateVolume( SoundHandle handle, double from, double to, Duration time) { - return _oscillateVolume(handle.id, from, to, time.toDouble()); + final e = _oscillateVolume(handle.id, from, to, time.toDouble()); + return PlayerErrors.values[e]; } late final _oscillateVolumePtr = _lookup< @@ -924,8 +1008,14 @@ class FlutterSoLoudFfi extends FlutterSoLoud { .asFunction(); @override - int oscillatePan(SoundHandle handle, double from, double to, Duration time) { - return _oscillatePan(handle.id, from, to, time.toDouble()); + PlayerErrors oscillatePan( + SoundHandle handle, + double from, + double to, + Duration time, + ) { + final e = _oscillatePan(handle.id, from, to, time.toDouble()); + return PlayerErrors.values[e]; } late final _oscillatePanPtr = _lookup< @@ -936,9 +1026,10 @@ class FlutterSoLoudFfi extends FlutterSoLoud { _oscillatePanPtr.asFunction(); @override - int oscillateRelativePlaySpeed( + PlayerErrors oscillateRelativePlaySpeed( SoundHandle handle, double from, double to, Duration time) { - return _oscillateRelativePlaySpeed(handle.id, from, to, time.toDouble()); + final e = _oscillateRelativePlaySpeed(handle.id, from, to, time.toDouble()); + return PlayerErrors.values[e]; } late final _oscillateRelativePlaySpeedPtr = _lookup< @@ -949,8 +1040,9 @@ class FlutterSoLoudFfi extends FlutterSoLoud { .asFunction(); @override - int oscillateGlobalVolume(double from, double to, Duration time) { - return _oscillateGlobalVolume(from, to, time.toDouble()); + PlayerErrors oscillateGlobalVolume(double from, double to, Duration time) { + final e = _oscillateGlobalVolume(from, to, time.toDouble()); + return PlayerErrors.values[e]; } late final _oscillateGlobalVolumePtr = _lookup< @@ -960,26 +1052,81 @@ class FlutterSoLoudFfi extends FlutterSoLoud { late final _oscillateGlobalVolume = _oscillateGlobalVolumePtr .asFunction(); + @override + PlayerErrors fadeFilterParameter( + FilterType filterType, + int attributeId, + double to, + double time, { + SoundHandle handle = const SoundHandle(0), + }) { + final e = _fadeFilterParameter( + handle.id, + filterType.index, + attributeId, + to, + time, + ); + return PlayerErrors.values[e]; + } + + late final _fadeFilterParameterPtr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function(ffi.UnsignedInt, ffi.Int32, ffi.Int, ffi.Float, + ffi.Float)>>('fadeFilterParameter'); + late final _fadeFilterParameter = _fadeFilterParameterPtr + .asFunction(); + + @override + PlayerErrors oscillateFilterParameter( + FilterType filterType, + int attributeId, + double from, + double to, + double time, { + SoundHandle handle = const SoundHandle(0), + }) { + final e = _oscillateFilterParameter( + handle.id, + filterType.index, + attributeId, + from, + to, + time, + ); + return PlayerErrors.values[e]; + } + + late final _oscillateFilterParameterPtr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function(ffi.UnsignedInt, ffi.Int32, ffi.Int, ffi.Float, + ffi.Float, ffi.Float)>>('oscillateFilterParameter'); + late final _oscillateFilterParameter = _oscillateFilterParameterPtr + .asFunction(); + // /////////////////////////////////////// // Filters // /////////////////////////////////////// @override - ({PlayerErrors error, int index}) isFilterActive(FilterType filterType) { + ({PlayerErrors error, int index}) isFilterActive( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { // ignore: omit_local_variable_types final ffi.Pointer id = calloc(ffi.sizeOf()); - final e = _isFilterActive(filterType.index, id); + final e = _isFilterActive(soundHash.hash, filterType.index, id); final ret = (error: PlayerErrors.values[e], index: id.value); calloc.free(id); return ret; } late final _isFilterActivePtr = _lookup< - ffi - .NativeFunction)>>( - 'isFilterActive'); - late final _isFilterActive = - _isFilterActivePtr.asFunction)>(); + ffi.NativeFunction< + ffi.Int32 Function(ffi.UnsignedInt, ffi.Int32, + ffi.Pointer)>>('isFilterActive'); + late final _isFilterActive = _isFilterActivePtr + .asFunction)>(); @override ({PlayerErrors error, List names}) getFilterParamNames( @@ -1023,49 +1170,82 @@ class FlutterSoLoudFfi extends FlutterSoLoud { int, ffi.Pointer, ffi.Pointer>)>(); @override - PlayerErrors addGlobalFilter(FilterType filterType) { - final e = _addGlobalFilter(filterType.index); + PlayerErrors addFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { + final e = _addFilter(soundHash.hash, filterType.index); return PlayerErrors.values[e]; } - late final _addGlobalFilterPtr = - _lookup>( - 'addGlobalFilter'); - late final _addGlobalFilter = - _addGlobalFilterPtr.asFunction(); + late final _addFilterPtr = _lookup< + ffi.NativeFunction>( + 'addFilter'); + late final _addFilter = _addFilterPtr.asFunction(); @override - int removeGlobalFilter(FilterType filterType) { - return _removeGlobalFilter(filterType.index); + PlayerErrors removeFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { + final e = _removeFilter(soundHash.hash, filterType.index); + return PlayerErrors.values[e]; } - late final _removeGlobalFilterPtr = - _lookup>( - 'removeGlobalFilter'); - late final _removeGlobalFilter = - _removeGlobalFilterPtr.asFunction(); + late final _removeFilterPtr = _lookup< + ffi.NativeFunction>( + 'removeFilter'); + late final _removeFilter = + _removeFilterPtr.asFunction(); @override - int setFilterParams(FilterType filterType, int attributeId, double value) { - return _setFxParams(filterType.index, attributeId, value); + PlayerErrors setFilterParams( + FilterType filterType, + int attributeId, + double value, { + SoundHandle handle = const SoundHandle.error(), + }) { + final e = _setFilterParams( + handle.isError ? 0 : handle.id, + filterType.index, + attributeId, + value, + ); + return PlayerErrors.values[e]; } - late final _setFxParamsPtr = _lookup< + late final _setFilterParamsPtr = _lookup< ffi.NativeFunction< - ffi.Int32 Function(ffi.Int32, ffi.Int, ffi.Float)>>('setFxParams'); - late final _setFxParams = - _setFxParamsPtr.asFunction(); + ffi.Int32 Function(ffi.UnsignedInt, ffi.Int32, ffi.Int, + ffi.Float)>>('setFilterParams'); + late final _setFilterParams = + _setFilterParamsPtr.asFunction(); @override - double getFilterParams(FilterType filterType, int attributeId) { - return _getFxParams(filterType.index, attributeId); + ({PlayerErrors error, double value}) getFilterParams( + FilterType filterType, + int attributeId, { + SoundHandle handle = const SoundHandle.error(), + }) { + // ignore: omit_local_variable_types + final ffi.Pointer paramValue = calloc(); + final error = _getFilterParams( + handle.isError ? 0 : handle.id, + filterType.index, + attributeId, + paramValue, + ); + final ret = paramValue.value; + calloc.free(paramValue); + return (error: PlayerErrors.values[error], value: ret); } - late final _getFxParamsPtr = - _lookup>( - 'getFxParams'); - late final _getFxParams = - _getFxParamsPtr.asFunction(); + late final _getFilterParamsPtr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function(ffi.UnsignedInt, ffi.Int32, ffi.Int, + ffi.Pointer)>>('getFilterParams'); + late final _getFilterParams = _getFilterParamsPtr + .asFunction)>(); ///////////////////////////////////////// /// 3D audio methods diff --git a/lib/src/bindings/bindings_player_web.dart b/lib/src/bindings/bindings_player_web.dart index 1bfffa2..681d088 100644 --- a/lib/src/bindings/bindings_player_web.dart +++ b/lib/src/bindings/bindings_player_web.dart @@ -72,8 +72,9 @@ class FlutterSoLoudWeb extends FlutterSoLoud { } @override - PlayerErrors initEngine() { - return PlayerErrors.values[wasmInitEngine()]; + PlayerErrors initEngine(int sampleRate, int bufferSize, Channels channels) { + final ret = wasmInitEngine(sampleRate, bufferSize, channels.count); + return PlayerErrors.values[ret]; } @override @@ -420,68 +421,168 @@ class FlutterSoLoudWeb extends FlutterSoLoud { return wasmSetMaxActiveVoiceCount(maxVoiceCount); } + ///////////////////////////////////////// + /// voice groups + ///////////////////////////////////////// + + @override + SoundHandle createVoiceGroup() { + /// The group handle returned has the sign bit flagged. Since on the web + /// the int is a signed 32 bit, a negative number will be returned. + /// Fixing by ORing the result. + final ret = wasmCreateVoiceGroup() | 0xfffff000; + return SoundHandle(ret > 0 ? ret : -1); + } + + @override + void destroyVoiceGroup(SoundHandle handle) { + return wasmDestroyVoiceGroup(handle.id); + } + + @override + void addVoicesToGroup( + SoundHandle voiceGroupHandle, + List voiceHandles, + ) { + for (final handle in voiceHandles) { + wasmAddVoiceToGroup(voiceGroupHandle.id, handle.id); + } + } + + @override + bool isVoiceGroup(SoundHandle handle) { + return wasmIsVoiceGroup(handle.id) == 1; + } + + @override + bool isVoiceGroupEmpty(SoundHandle handle) { + return wasmIsVoiceGroupEmpty(handle.id) == 1; + } + // /////////////////////////////////////// // faders // /////////////////////////////////////// @override - int fadeGlobalVolume(double to, Duration duration) { - return wasmFadeGlobalVolume(to, duration.toDouble()); + PlayerErrors fadeGlobalVolume(double to, Duration duration) { + final e = wasmFadeGlobalVolume(to, duration.toDouble()); + return PlayerErrors.values[e]; } @override - int fadeVolume(SoundHandle handle, double to, Duration duration) { - return wasmFadeVolume(handle.id, to, duration.toDouble()); + PlayerErrors fadeVolume(SoundHandle handle, double to, Duration duration) { + final e = wasmFadeVolume(handle.id, to, duration.toDouble()); + return PlayerErrors.values[e]; } @override - int fadePan(SoundHandle handle, double to, Duration duration) { - return wasmFadePan(handle.id, to, duration.toDouble()); + PlayerErrors fadePan(SoundHandle handle, double to, Duration duration) { + final e = wasmFadePan(handle.id, to, duration.toDouble()); + return PlayerErrors.values[e]; } @override - int fadeRelativePlaySpeed(SoundHandle handle, double to, Duration time) { - return wasmFadeRelativePlaySpeed(handle.id, to, time.toDouble()); + PlayerErrors fadeRelativePlaySpeed( + SoundHandle handle, + double to, + Duration time, + ) { + final e = wasmFadeRelativePlaySpeed(handle.id, to, time.toDouble()); + return PlayerErrors.values[e]; } @override - int schedulePause(SoundHandle handle, Duration duration) { - return wasmSchedulePause(handle.id, duration.toDouble()); + PlayerErrors schedulePause(SoundHandle handle, Duration duration) { + final e = wasmSchedulePause(handle.id, duration.toDouble()); + return PlayerErrors.values[e]; } @override - int scheduleStop(SoundHandle handle, Duration duration) { - return wasmScheduleStop(handle.id, duration.toDouble()); + PlayerErrors scheduleStop(SoundHandle handle, Duration duration) { + final e = wasmScheduleStop(handle.id, duration.toDouble()); + return PlayerErrors.values[e]; } @override - int oscillateVolume( + PlayerErrors oscillateVolume( SoundHandle handle, double from, double to, Duration time, ) { - return wasmOscillateVolume(handle.id, from, to, time.toDouble()); + final e = wasmOscillateVolume(handle.id, from, to, time.toDouble()); + return PlayerErrors.values[e]; } @override - int oscillatePan(SoundHandle handle, double from, double to, Duration time) { - return wasmOscillatePan(handle.id, from, to, time.toDouble()); + PlayerErrors oscillatePan( + SoundHandle handle, + double from, + double to, + Duration time, + ) { + final e = wasmOscillatePan(handle.id, from, to, time.toDouble()); + return PlayerErrors.values[e]; } @override - int oscillateRelativePlaySpeed( + PlayerErrors oscillateRelativePlaySpeed( SoundHandle handle, double from, double to, Duration time, ) { - return wasmOscillateRelativePlaySpeed(handle.id, from, to, time.toDouble()); + final e = wasmOscillateRelativePlaySpeed( + handle.id, + from, + to, + time.toDouble(), + ); + return PlayerErrors.values[e]; } @override - int oscillateGlobalVolume(double from, double to, Duration time) { - return wasmOscillateGlobalVolume(from, to, time.toDouble()); + PlayerErrors oscillateGlobalVolume(double from, double to, Duration time) { + final e = wasmOscillateGlobalVolume(from, to, time.toDouble()); + return PlayerErrors.values[e]; + } + + @override + PlayerErrors fadeFilterParameter( + FilterType filterType, + int attributeId, + double to, + double time, { + SoundHandle handle = const SoundHandle.error(), + }) { + final e = wasmFadeFilterParameter( + handle.isError ? 0 : handle.id, + filterType.index, + attributeId, + to, + time, + ); + return PlayerErrors.values[e]; + } + + @override + PlayerErrors oscillateFilterParameter( + FilterType filterType, + int attributeId, + double from, + double to, + double time, { + SoundHandle handle = const SoundHandle.error(), + }) { + final e = wasmOscillateFilterParameter( + handle.isError ? 0 : handle.id, + filterType.index, + attributeId, + from, + to, + time, + ); + return PlayerErrors.values[e]; } // /////////////////////////////////////// @@ -489,10 +590,13 @@ class FlutterSoLoudWeb extends FlutterSoLoud { // /////////////////////////////////////// @override - ({PlayerErrors error, int index}) isFilterActive(FilterType filterType) { + ({PlayerErrors error, int index}) isFilterActive( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { // ignore: omit_local_variable_types final idPtr = wasmMalloc(4); // 4 bytes for an int - final e = wasmIsFilterActive(filterType.index, idPtr); + final e = wasmIsFilterActive(soundHash.hash, filterType.index, idPtr); final index = wasmGetI32Value(idPtr, 'i32'); final ret = (error: PlayerErrors.values[e], index: index); wasmFree(idPtr); @@ -526,24 +630,55 @@ class FlutterSoLoudWeb extends FlutterSoLoud { } @override - PlayerErrors addGlobalFilter(FilterType filterType) { - final e = wasmAddGlobalFilter(filterType.index); + PlayerErrors addFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { + final e = wasmAddFilter(soundHash.hash, filterType.index); return PlayerErrors.values[e]; } @override - int removeGlobalFilter(FilterType filterType) { - return wasmRemoveGlobalFilter(filterType.index); + PlayerErrors removeFilter( + FilterType filterType, { + SoundHash soundHash = const SoundHash.invalid(), + }) { + final e = wasmRemoveFilter(soundHash.hash, filterType.index); + return PlayerErrors.values[e]; } @override - int setFilterParams(FilterType filterType, int attributeId, double value) { - return wasmSetFxParams(filterType.index, attributeId, value); + PlayerErrors setFilterParams( + FilterType filterType, + int attributeId, + double value, { + SoundHandle handle = const SoundHandle(0), + }) { + final e = wasmSetFilterParams( + handle.id, + filterType.index, + attributeId, + value, + ); + return PlayerErrors.values[e]; } @override - double getFilterParams(FilterType filterType, int attributeId) { - return wasmGetFxParams(filterType.index, attributeId); + ({PlayerErrors error, double value}) getFilterParams( + FilterType filterType, + int attributeId, { + SoundHandle handle = const SoundHandle(0), + }) { + final paramValuePtr = wasmMalloc(4); + final error = wasmGetFilterParams( + handle.id, + filterType.index, + attributeId, + paramValuePtr, + ); + final ret = wasmGetF32Value(paramValuePtr, 'float'); + wasmFree(paramValuePtr); + return (error: PlayerErrors.values[error], value: ret); } // ////////////////////////////////////// diff --git a/lib/src/bindings/js_extension.dart b/lib/src/bindings/js_extension.dart index 0306049..245414d 100644 --- a/lib/src/bindings/js_extension.dart +++ b/lib/src/bindings/js_extension.dart @@ -46,7 +46,7 @@ external void wasmSendToWorker(int message, int value); external web.Worker wasmWorker; @JS('Module._initEngine') -external int wasmInitEngine(); +external int wasmInitEngine(int sampleRate, int bufferSize, int channels); @JS('Module._dispose') external void wasmDeinit(); @@ -242,6 +242,29 @@ external int wasmGetMaxActiveVoiceCount(); @JS('Module._setMaxActiveVoiceCount') external void wasmSetMaxActiveVoiceCount(int maxVoiceCount); +///////////////////////////////////////// +/// voice groups +///////////////////////////////////////// + +@JS('Module._createVoiceGroup') +external int wasmCreateVoiceGroup(); + +@JS('Module._destroyVoiceGroup') +external void wasmDestroyVoiceGroup(int handle); + +@JS('Module._addVoiceToGroup') +external void wasmAddVoiceToGroup(int voiceGroupHandle, int voiceHandle); + +@JS('Module._isVoiceGroup') +external int wasmIsVoiceGroup(int handle); + +@JS('Module._isVoiceGroupEmpty') +external int wasmIsVoiceGroupEmpty(int handle); + +// /////////////////////////////////////// +// faders +// /////////////////////////////////////// + @JS('Module._fadeGlobalVolume') external int wasmFadeGlobalVolume(double to, double duration); @@ -282,8 +305,31 @@ external int wasmOscillateRelativePlaySpeed( @JS('Module._oscillateGlobalVolume') external int wasmOscillateGlobalVolume(double from, double to, double time); +@JS('Module._fadeFilterParameter') +external int wasmFadeFilterParameter( + int handle, + int filterType, + int attributeId, + double to, + double time, +); + +@JS('Module._oscillateFilterParameter') +external int wasmOscillateFilterParameter( + int handle, + int filterType, + int attributeId, + double from, + double to, + double time, +); + +// /////////////////////////////////////// +// Filters +// /////////////////////////////////////// + @JS('Module._isFilterActive') -external int wasmIsFilterActive(int filterType, int idPtr); +external int wasmIsFilterActive(int soundHash, int filterType, int idPtr); @JS('Module._getFilterParamNames') external int wasmGetFilterParamNames( @@ -292,17 +338,27 @@ external int wasmGetFilterParamNames( int namesPtr, ); -@JS('Module._addGlobalFilter') -external int wasmAddGlobalFilter(int filterType); +@JS('Module._addFilter') +external int wasmAddFilter(int soundHash, int filterType); -@JS('Module._removeGlobalFilter') -external int wasmRemoveGlobalFilter(int filterType); +@JS('Module._removeFilter') +external int wasmRemoveFilter(int soundHash, int filterType); -@JS('Module._setFxParams') -external int wasmSetFxParams(int filterType, int attributeId, double value); +@JS('Module._setFilterParams') +external int wasmSetFilterParams( + int handle, + int filterType, + int attributeId, + double value, +); -@JS('Module._getFxParams') -external double wasmGetFxParams(int filterType, int attributeId); +@JS('Module._getFilterParams') +external int wasmGetFilterParams( + int handle, + int filterType, + int attributeId, + int paramValuePtr, +); @JS('Module._play3d') external int wasmPlay3d( diff --git a/lib/src/enums.dart b/lib/src/enums.dart index e433c9a..9389212 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -233,3 +233,26 @@ enum PlayerStateNotification { /// unlocked, } + +/// The channels to be used while initializing the player. +enum Channels { + /// One channel. + mono(1), + + /// Two channels. + stereo(2), + + /// Four channels. + quad(4), + + /// Six channels. + surround51(6), + + /// Eight channels. + dolby71(8); + + const Channels(this.count); + + /// The channels count. + final int count; +} diff --git a/lib/src/exceptions/exceptions_from_dart.dart b/lib/src/exceptions/exceptions_from_dart.dart index 884c91f..cb2b30f 100644 --- a/lib/src/exceptions/exceptions_from_dart.dart +++ b/lib/src/exceptions/exceptions_from_dart.dart @@ -87,3 +87,14 @@ class SoLoudSoundHashNotFoundDartException extends SoLoudDartException { String get description => 'The sound with specified hash is not found ' '(on the Dart side).'; } + +/// An exception that is thrown when SoLoud (Dart) tries to create a voice +/// group but something goes wrong. +class SoLoudCreateVoiceGroupDartException extends SoLoudDartException { + /// Creates a new [SoLoudCreateVoiceGroupDartException]. + const SoLoudCreateVoiceGroupDartException([super.message]); + + @override + String get description => 'SoLoud.createVoiceGroup() was not able to create ' + ' a new voice group.'; +} diff --git a/lib/src/soloud.dart b/lib/src/soloud.dart index 50ccdf5..24162c5 100644 --- a/lib/src/soloud.dart +++ b/lib/src/soloud.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_soloud/src/audio_source.dart'; import 'package:flutter_soloud/src/bindings/audio_data.dart'; +import 'package:flutter_soloud/src/bindings/bindings_player.dart'; import 'package:flutter_soloud/src/bindings/soloud_controller.dart'; import 'package:flutter_soloud/src/enums.dart'; import 'package:flutter_soloud/src/exceptions/exceptions.dart'; @@ -202,17 +203,29 @@ interface class SoLoud { /// that play sounds from assets or from the file system, this is probably /// unnecessary, as the amount of data will be finite. /// The default is `false`. + /// [sampleRate] The sample rate represents the number of samples used, per + /// second. Typical sample rates are 8000Hz, 22050Hz, 44100Hz and 48000Hz. + /// Higher the sample rates mean clearer sound, but also bigger files, more + /// memory and higher processing power requirements. + /// [bufferSize] Audio latency generally means the time it takes from + /// triggering a sound to the sound actually coming out of the speakers. + /// The smaller the latency, the better. + /// Unfortunately, there's always some latency. The primary source of + /// latency (that a programmer can have any control over) is the size of + /// audio buffer. Generally speaking, the smaller the buffer, the lower the + /// latency, but at the same time, the smaller the buffer, the more likely the + /// system hits buffer underruns (ie, the play head marches on but there's no + /// data ready to be played) and the sound breaks down horribly. + /// [channels] mono, stereo, quad, 5.1, 7.1. Future init({ // TODO(filip): remove deprecation? @Deprecated('timeout is not used anymore.') Duration timeout = const Duration(seconds: 10), bool automaticCleanup = false, + int sampleRate = 44100, + int bufferSize = 2048, + Channels channels = Channels.stereo, }) async { - /// Defaults are: - /// Miniaudio audio backend - /// sample rate 44100 - /// buffer 2048 - // TODO(marco): add engine initialization parameters _log.finest('init() called'); // if `!isInitialized` but the engine is initialized in native, therefore @@ -233,7 +246,11 @@ interface class SoLoud { // Initialize native callbacks _initializeNativeCallbacks(); - final error = _controller.soLoudFFI.initEngine(); + final error = _controller.soLoudFFI.initEngine( + sampleRate, + bufferSize, + channels, + ); _logPlayerError(error, from: 'initialize() result'); if (error == PlayerErrors.noError) { _isInitialized = true; @@ -842,7 +859,7 @@ interface class SoLoud { source.soundEventsController.add(( event: SoundEventType.soundDisposed, sound: source, - handle: SoundHandle.error(), + handle: const SoundHandle.error(), )); } await source.soundEventsController.close(); @@ -871,7 +888,7 @@ interface class SoLoud { sound.soundEventsController.add(( event: SoundEventType.soundDisposed, sound: sound, - handle: SoundHandle.error(), + handle: const SoundHandle.error(), )); // TODO(filiph): Close these in parallel using `Future.wait()` await sound.soundEventsController.close(); @@ -1333,6 +1350,58 @@ interface class SoLoud { _controller.soLoudFFI.setFftSmoothing(smooth); } + ///////////////////////////////////////// + /// voice groups + ///////////////////////////////////////// + + /// Used to create a new voice group. Returns 0 if not successful. + SoundHandle createVoiceGroup() { + final ret = _controller.soLoudFFI.createVoiceGroup(); + if (ret.isError) throw const SoLoudCreateVoiceGroupDartException(); + return ret; + } + + /// Deallocates the voice group. Does not stop the voices attached to the + /// voice group. + /// + /// [handle] the group handle to destroy. + void destroyVoiceGroup(SoundHandle handle) { + return _controller.soLoudFFI.destroyVoiceGroup(handle); + } + + /// Adds voice handle to the voice group. The voice handles can still be + /// used separate from the group. + /// [voiceGroupHandle] the group handle to add the new [voiceHandles]. + /// [voiceHandles] voice handle to add to the [voiceGroupHandle]. + void addVoicesToGroup( + SoundHandle voiceGroupHandle, + List voiceHandles, + ) { + return _controller.soLoudFFI.addVoicesToGroup( + voiceGroupHandle, + voiceHandles, + ); + } + + /// Checks if the handle is a valid voice group. Does not care if the + /// voice group is empty. + /// + /// [handle] the group handle to check. + /// Return true if [handle] is a group handle. + bool isVoiceGroup(SoundHandle handle) { + return _controller.soLoudFFI.isVoiceGroup(handle); + } + + /// Checks whether a voice group is empty. SoLoud automatically trims + /// the voice groups of voices that have ended, so the group may be + /// empty even though you've added valid voice handles to it. + /// + /// [handle] group handle to check. + /// Return true if the group handle doesn't have any voices. + bool isVoiceGroupEmpty(SoundHandle handle) { + return _controller.soLoudFFI.isVoiceGroupEmpty(handle); + } + // /////////////////////////////////////// // faders // ////////////////////////////////////// @@ -1345,8 +1414,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.fadeGlobalVolume(to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.fadeGlobalVolume(to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'fadeGlobalVolume(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1363,8 +1431,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.fadeVolume(handle, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.fadeVolume(handle, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'fadeVolume(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1381,8 +1448,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.fadePan(handle, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.fadePan(handle, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'fadePan(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1399,8 +1465,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.fadeRelativePlaySpeed(handle, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.fadeRelativePlaySpeed(handle, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'fadeRelativePlaySpeed(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1416,8 +1481,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.schedulePause(handle, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.schedulePause(handle, time); if (error != PlayerErrors.noError) { _log.severe(() => 'schedulePause(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1433,8 +1497,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.scheduleStop(handle, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.scheduleStop(handle, time); if (error != PlayerErrors.noError) { _log.severe(() => 'scheduleStop(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1455,8 +1518,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.oscillateVolume(handle, from, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.oscillateVolume(handle, from, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'oscillateVolume(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1476,8 +1538,7 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.oscillatePan(handle, from, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.oscillatePan(handle, from, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'oscillatePan(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1498,9 +1559,8 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI + final error = _controller.soLoudFFI .oscillateRelativePlaySpeed(handle, from, to, time); - final error = PlayerErrors.values[ret]; if (error != PlayerErrors.noError) { _log.severe(() => 'oscillateRelativePlaySpeed(): $error'); throw SoLoudCppException.fromPlayerError(error); @@ -1518,16 +1578,78 @@ interface class SoLoud { if (!isInitialized) { throw const SoLoudNotInitializedException(); } - final ret = _controller.soLoudFFI.oscillateGlobalVolume(from, to, time); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.oscillateGlobalVolume(from, to, time); if (error != PlayerErrors.noError) { _log.severe(() => 'oscillateGlobalVolume(): $error'); throw SoLoudCppException.fromPlayerError(error); } } + /// Fade a parameter of a filter. + /// + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [to] value the attribute should go in [time] duration. + /// [time] the fade slope duration. + /// + /// Throws [SoLoudNotInitializedException] if the engine is not initialized. + void fadeGlobalFilterParameter( + FilterType filterType, + int attributeId, + double to, + Duration time, + ) { + if (!isInitialized) { + throw const SoLoudNotInitializedException(); + } + final error = _controller.soLoudFFI.fadeFilterParameter( + filterType, + attributeId, + to, + time.toDouble(), + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'fadeFilterParameter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + } + + /// Oscillate a parameter of a filter. + /// + /// it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [from] the starting value the attribute sould start to oscillate. + /// [to] the ending value the attribute sould end to oscillate. + /// [time] the fade slope duration. + /// + /// Throws [SoLoudNotInitializedException] if the engine is not initialized. + void oscillateGlobalFilterParameter( + FilterType filterType, + int attributeId, + double from, + double to, + Duration time, + ) { + if (!isInitialized) { + throw const SoLoudNotInitializedException(); + } + final error = _controller.soLoudFFI.oscillateFilterParameter( + filterType, + attributeId, + from, + to, + time.toDouble(), + ); + if (error != PlayerErrors.noError) { + _log.severe(() => 'oscillateFilterParameter(): $error'); + throw SoLoudCppException.fromPlayerError(error); + } + } + // /////////////////////////////////////// - // / Filters + // / Global filters // /////////////////////////////////////// /// Checks whether the given [filterType] is active. @@ -1543,8 +1665,6 @@ interface class SoLoud { return ret.index; } - // TODO(marco): add a method to rearrange filters order? - /// Gets parameters of the given [filterType]. /// /// Returns the list of param names. @@ -1564,48 +1684,90 @@ interface class SoLoud { /// Throws [SoLoudFilterAlreadyAddedException] when trying to add a filter /// that has already been added. void addGlobalFilter(FilterType filterType) { - final e = _controller.soLoudFFI.addGlobalFilter(filterType); - if (e != PlayerErrors.noError) { - _log.severe(() => 'addGlobalFilter(): $e'); - throw SoLoudCppException.fromPlayerError(e); + final error = _controller.soLoudFFI.addFilter(filterType); + if (error != PlayerErrors.noError) { + _log.severe(() => 'addGlobalFilter(): $error'); + throw SoLoudCppException.fromPlayerError(error); } } /// Removes [filterType] from all sounds. void removeGlobalFilter(FilterType filterType) { - final ret = _controller.soLoudFFI.removeGlobalFilter(filterType); - final error = PlayerErrors.values[ret]; + final error = _controller.soLoudFFI.removeFilter(filterType); if (error != PlayerErrors.noError) { _log.severe(() => 'removeGlobalFilter(): $error'); throw SoLoudCppException.fromPlayerError(error); } } - /// Sets a parameter of the given [filterType]. + /// Set the effect parameter with id [attributeId] of [filterType] + /// with [value] value. /// /// Specify the [attributeId] of the parameter (which you can learn from /// [getFilterParamNames]), and its new [value]. - void setFilterParameter( - FilterType filterType, int attributeId, double value) { - final ret = - _controller.soLoudFFI.setFilterParams(filterType, attributeId, value); - final error = PlayerErrors.values[ret]; + /// + /// applyed to the global filter. + /// [filterType] filter to modify a param. + /// Returns [PlayerErrors.noError] if no errors. + void setGlobalFilterParameter( + FilterType filterType, + int attributeId, + double value, + ) { + final error = _controller.soLoudFFI.setFilterParams( + filterType, + attributeId, + value, + ); if (error != PlayerErrors.noError) { _log.severe(() => 'setFxParams(): $error'); throw SoLoudCppException.fromPlayerError(error); } } - /// Gets the value of a parameter of the given [filterType]. + /// Set the effect parameter with id [attributeId] of [filterType] + /// with [value] value. + @Deprecated('Please use setGlobalFilterParameter class instead.') + void setFilterParameter( + FilterType filterType, + int attributeId, + double value, + ) => + setGlobalFilterParameter(filterType, attributeId, value); + + /// Get the effect parameter value with id [attributeId] of [filterType]. /// /// Specify the [attributeId] of the parameter (which you can learn from /// [getFilterParamNames]). /// - /// Returns the value as [double]. - double getFilterParameter(FilterType filterType, int attributeId) { - return _controller.soLoudFFI.getFilterParams(filterType, attributeId); + /// it gets the global filter value. + /// [filterType] the filter to modify a parameter. + /// Returns the value of the parameter. + double getGlobalFilterParameter( + FilterType filterType, + int attributeId, + ) { + final ret = _controller.soLoudFFI.getFilterParams( + filterType, + attributeId, + ); + + _logPlayerError(ret.error, from: 'getGlobalFilterParameter()'); + if (ret.error != PlayerErrors.noError) { + throw SoLoudCppException.fromPlayerError(ret.error); + } + return ret.value; } + /// Get the effect parameter value with id [attributeId] of [filterType]. + @Deprecated('Please use getGlobalFilterParameter class instead.') + double getFilterParameter( + FilterType filterType, + int attributeId, { + SoundHandle handle = const SoundHandle(0), + }) => + getGlobalFilterParameter(filterType, attributeId); + // //////////////////////////////////////////////// // Below all the methods implemented with FFI for the 3D audio // more info: https://solhsa.com/soloud/core3d.html diff --git a/lib/src/sound_handle.dart b/lib/src/sound_handle.dart index 3df886f..c524484 100644 --- a/lib/src/sound_handle.dart +++ b/lib/src/sound_handle.dart @@ -16,10 +16,10 @@ import 'package:meta/meta.dart'; /// /// Constructors are marked [internal] because it should not be possible /// for users to create a handle from Dart. -extension type SoundHandle._(int id) { +extension type const SoundHandle._(int id) { /// Constructs a valid handle with [id]. @internal - SoundHandle(this.id) + const SoundHandle(this.id) : assert( id >= 0, 'Handle with id<0 is being constructed. ' @@ -28,7 +28,7 @@ extension type SoundHandle._(int id) { /// Constructs an invalid handle (for APIs that need to return _some_ handle /// even during errors). @internal - SoundHandle.error() : this._(-1); + const SoundHandle.error() : this._(-1); /// Checks if the handle represents an error (it was constructed /// with [SoundHandle.error]). diff --git a/lib/src/sound_hash.dart b/lib/src/sound_hash.dart index de3b5d2..3a34741 100644 --- a/lib/src/sound_hash.dart +++ b/lib/src/sound_hash.dart @@ -17,10 +17,10 @@ import 'package:meta/meta.dart'; /// /// Constructors are marked [internal] because it should not be possible /// for users to create a sound hash from Dart. -extension type SoundHash._(int hash) { +extension type const SoundHash._(int hash) { /// Constructs a valid sound hash with [hash]. @internal - SoundHash(this.hash) + const SoundHash(this.hash) : assert( hash > 0, 'Trying to create a valid sound hash with the value 0', @@ -29,7 +29,7 @@ extension type SoundHash._(int hash) { /// Constructs an invalid sound hash /// (for APIs that need to return _some_ hash even during errors). @internal - SoundHash.invalid() : this._(0); + const SoundHash.invalid() : this._(0); /// Generate a "fake" [SoundHash] for generated (i.e. non-loaded) sounds. /// diff --git a/pubspec.yaml b/pubspec.yaml index 4dc57d1..5254cda 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: >- A low-level audio plugin for Flutter, mainly meant for games and immersive apps. Based on the SoLoud (C++) audio engine. -version: 2.0.2 +version: 2.1.0 issue_tracker: https://github.com/alnitak/flutter_soloud/issues homepage: https://github.com/alnitak/flutter_soloud maintainer: Marco Bavagnoli (@lildeimos) @@ -62,7 +62,7 @@ flutter: assets: # These assets are only needed for the web platform. # Waiting for https://github.com/flutter/flutter/issues/65065 and - # https://github.com/flutter/flutter/issues/8230 to be addressed + # https://github.com/flutter/flutter/issues/8230 to be addressed. # to make a conditional build. - web/worker.dart.js - web/libflutter_soloud_plugin.js diff --git a/src/active_sound.h b/src/active_sound.h new file mode 100644 index 0000000..ce70879 --- /dev/null +++ b/src/active_sound.h @@ -0,0 +1,27 @@ +#ifndef ACTIVE_SOUND_H +#define ACTIVE_SOUND_H + +#include "enums.h" +#include "filters/filters.h" +#include "soloud.h" + +#include +#include +#include + +class Filters; + +/// The default number of concurrent voices - maximum number of "streams" - is 16, +/// but this can be adjusted at runtime +typedef struct ActiveSound +{ + std::shared_ptr sound; + SoundType soundType; + std::vector handle; + std::unique_ptr filters; + // unique identifier of this sound based on the file name + unsigned int soundHash; + std::string completeFileName; +} ActiveSound; + +#endif // ACTIVE_SOUND_H \ No newline at end of file diff --git a/src/bindings.cpp b/src/bindings.cpp index 7618abb..e1733cd 100644 --- a/src/bindings.cpp +++ b/src/bindings.cpp @@ -43,9 +43,9 @@ extern "C" FFI_PLUGIN_EXPORT void createWorkerInWasm() { printf("CPP void createWorkerInWasm()\n"); - + EM_ASM({ - if (!Module.wasmWorker) + if (!Module.wasmWorker) { // Create a new Worker from the URI var workerUri = "assets/packages/flutter_soloud/web/worker.dart.js"; @@ -149,16 +149,24 @@ extern "C" ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// - /// Initialize the player.get()-> Must be called before any other player functions + /// Initialize the player. Must be called before any other player functions. /// - /// Returns [PlayerErrors.noError] if success - FFI_PLUGIN_EXPORT enum PlayerErrors initEngine() + /// [sampleRate] the sample rate. Usually is 22050, 44100 (CD quality) or 48000. + /// [bufferSize] the audio buffer size. Usually is 2048, but can be also 512 when + /// low latency is needed for example in games. + /// [channels] 1=mono, 2=stereo, 4=quad, 6=5.1, 8=7.1. + /// + /// Returns [PlayerErrors.noError] if success. + FFI_PLUGIN_EXPORT enum PlayerErrors initEngine( + unsigned int sampleRate, + unsigned int bufferSize, + unsigned int channels) { if (player.get() == nullptr) player = std::make_unique(); player.get()->setStateChangedCallback(stateChangedCallback); - PlayerErrors res = (PlayerErrors)player.get()->init(); + PlayerErrors res = (PlayerErrors)player.get()->init(sampleRate, bufferSize, channels); if (res != noError) return res; @@ -374,7 +382,7 @@ extern "C" FFI_PLUGIN_EXPORT void pauseSwitch(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->pauseSwitch(handle); } @@ -386,7 +394,7 @@ extern "C" FFI_PLUGIN_EXPORT void setPause(unsigned int handle, bool pause) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->setPause(handle, pause); } @@ -398,7 +406,7 @@ extern "C" FFI_PLUGIN_EXPORT int getPause(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return false; return player.get()->getPause(handle) ? 1 : 0; } @@ -418,7 +426,7 @@ extern "C" FFI_PLUGIN_EXPORT void setRelativePlaySpeed(unsigned int handle, float speed) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->setRelativePlaySpeed(handle, speed); } @@ -431,7 +439,7 @@ extern "C" FFI_PLUGIN_EXPORT float getRelativePlaySpeed(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return 1; return player.get()->getRelativePlaySpeed(handle); } @@ -471,7 +479,7 @@ extern "C" FFI_PLUGIN_EXPORT void stop(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->stop(handle); } @@ -502,7 +510,7 @@ extern "C" FFI_PLUGIN_EXPORT int getLooping(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return 0; return player.get()->getLooping(handle) == 1; } @@ -515,7 +523,7 @@ extern "C" FFI_PLUGIN_EXPORT void setLooping(unsigned int handle, bool enable) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->setLooping(handle, enable); } @@ -527,7 +535,7 @@ extern "C" FFI_PLUGIN_EXPORT double getLoopPoint(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return 0; return player.get()->getLoopPoint(handle); } @@ -539,7 +547,7 @@ extern "C" FFI_PLUGIN_EXPORT void setLoopPoint(unsigned int handle, double time) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->setLoopPoint(handle, time); } @@ -646,7 +654,8 @@ extern "C" return noError; } - FFI_PLUGIN_EXPORT float getTextureValue(int row, int column) { + FFI_PLUGIN_EXPORT float getTextureValue(int row, int column) + { return texture2D[row][column]; } @@ -692,7 +701,7 @@ extern "C" FFI_PLUGIN_EXPORT double getPosition(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return 0.0; return player.get()->getPosition(handle); } @@ -724,7 +733,7 @@ extern "C" FFI_PLUGIN_EXPORT double getVolume(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return 0.0; return player.get()->getVolume(handle); } @@ -735,7 +744,7 @@ extern "C" { if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - if (!player.get()->isValidVoiceHandle(handle)) + if (!player.get()->isValidHandle(handle)) return soundHandleNotFound; player.get()->setVolume(handle, volume); return noError; @@ -787,7 +796,7 @@ extern "C" if (player.get() == nullptr || !player.get()->isInited() || player.get()->getSoundsCount() == 0) return false; - return player.get()->isValidVoiceHandle(handle) ? 1 : 0; + return player.get()->isValidHandle(handle) ? 1 : 0; } /// Returns the number of concurrent sounds that are playing at the moment. @@ -818,7 +827,7 @@ extern "C" FFI_PLUGIN_EXPORT bool getProtectVoice(unsigned int handle) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return false; return player.get()->getProtectVoice(handle); } @@ -836,7 +845,7 @@ extern "C" FFI_PLUGIN_EXPORT void setProtectVoice(unsigned int handle, bool protect) { if (player.get() == nullptr || !player.get()->isInited() || - !player.get()->isValidVoiceHandle(handle)) + !player.get()->isValidHandle(handle)) return; player.get()->setProtectVoice(handle, protect); } @@ -868,11 +877,70 @@ extern "C" } ///////////////////////////////////////// - /// faders + /// voice groups ///////////////////////////////////////// - /// Smoothly change the global volume over specified time. + /// Used to create a new voice group. Returns 0 if not successful. + FFI_PLUGIN_EXPORT unsigned int createVoiceGroup() + { + if (player.get() == nullptr || !player.get()->isInited()) + return -1; + auto ret = player.get()->createVoiceGroup(); + return ret; + } + + /// Deallocates the voice group. Does not stop the voices attached to the + /// voice group. /// + /// [handle] the group handle to destroy. + FFI_PLUGIN_EXPORT void destroyVoiceGroup(unsigned int handle) + { + if (player.get() == nullptr || !player.get()->isInited()) + return; + player.get()->destroyVoiceGroup(handle); + } + + /// Adds voice handle to the voice group. The voice handles can still be + /// used separate from the group. + /// [voiceGroupHandle] the group handle to add the new [voiceHandle]. + /// [voiceHandle] voice handle to add to the [voiceGroupHandle]. + FFI_PLUGIN_EXPORT void addVoiceToGroup(unsigned int voiceGroupHandle, unsigned int voiceHandle) + { + if (player.get() == nullptr || !player.get()->isInited()) + return; + player.get()->addVoiceToGroup(voiceGroupHandle, voiceHandle); + } + + /// Checks if the handle is a valid voice group. Does not care if the + /// voice group is empty. + /// + /// [handle] the group handle to check. + /// Return true if [handle] is a group handle. + FFI_PLUGIN_EXPORT bool isVoiceGroup(unsigned int handle) + { + if (player.get() == nullptr || !player.get()->isInited()) + return false; + return player.get()->isVoiceGroup(handle); + } + + /// Checks whether a voice group is empty. SoLoud automatically trims + /// the voice groups of voices that have ended, so the group may be + /// empty even though you've added valid voice handles to it. + /// + /// [handle] group handle to check. + /// Return true if the group handle doesn't have any voices. + FFI_PLUGIN_EXPORT bool isVoiceGroupEmpty(unsigned int handle) + { + if (player.get() == nullptr || !player.get()->isInited()) + return false; + return player.get()->isVoiceGroupEmpty(handle); + } + + ///////////////////////////////////////// + /// faders & oscillators + ///////////////////////////////////////// + + /// Smoothly change the global volume over specified time. FFI_PLUGIN_EXPORT enum PlayerErrors fadeGlobalVolume(float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -882,7 +950,6 @@ extern "C" } /// Smoothly change a channel's volume over specified time. - /// FFI_PLUGIN_EXPORT enum PlayerErrors fadeVolume(unsigned int handle, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -892,7 +959,6 @@ extern "C" } /// Smoothly change a channel's pan setting over specified time. - /// FFI_PLUGIN_EXPORT enum PlayerErrors fadePan(unsigned int handle, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -902,7 +968,6 @@ extern "C" } /// Smoothly change a channel's relative play speed over specified time. - /// FFI_PLUGIN_EXPORT enum PlayerErrors fadeRelativePlaySpeed(unsigned int handle, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -912,7 +977,6 @@ extern "C" } /// After specified time, pause the channel. - /// FFI_PLUGIN_EXPORT enum PlayerErrors schedulePause(unsigned int handle, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -922,7 +986,6 @@ extern "C" } /// After specified time, stop the channel. - /// FFI_PLUGIN_EXPORT enum PlayerErrors scheduleStop(unsigned int handle, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -932,7 +995,6 @@ extern "C" } /// Set fader to oscillate the volume at specified frequency. - /// FFI_PLUGIN_EXPORT enum PlayerErrors oscillateVolume(unsigned int handle, float from, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -942,7 +1004,6 @@ extern "C" } /// Set fader to oscillate the panning at specified frequency. - /// FFI_PLUGIN_EXPORT enum PlayerErrors oscillatePan(unsigned int handle, float from, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -952,7 +1013,6 @@ extern "C" } /// Set fader to oscillate the relative play speed at specified frequency. - /// FFI_PLUGIN_EXPORT enum PlayerErrors oscillateRelativePlaySpeed(unsigned int handle, float from, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -962,7 +1022,6 @@ extern "C" } /// Set fader to oscillate the global volume at specified frequency. - /// FFI_PLUGIN_EXPORT enum PlayerErrors oscillateGlobalVolume(float from, float to, float time) { if (player.get() == nullptr || !player.get()->isInited()) @@ -977,24 +1036,34 @@ extern "C" /// Check if the given filter is active or not. /// - /// [filterType] filter to check + /// [soundHash] the sound to check the filter. If this is =0 this function + /// searches in the global filters. + /// [filterType] filter to check. /// Returns [PlayerErrors.noError] if no errors and the index of - /// the given filter (-1 if the filter is not active) - /// - FFI_PLUGIN_EXPORT enum PlayerErrors isFilterActive(enum FilterType filterType, int *index) + /// the given filter (-1 if the filter is not active). + FFI_PLUGIN_EXPORT enum PlayerErrors isFilterActive(unsigned int soundHash, enum FilterType filterType, int *index) { *index = -1; if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - *index = player.get()->mFilters.isFilterActive(filterType); + + if (soundHash == 0) + *index = player.get()->mFilters.isFilterActive(filterType); + else + { + auto const s = player.get()->findByHash(soundHash); + if (s == nullptr) + return soundHashNotFound; + *index = s->filters->isFilterActive(filterType); + } + return noError; } /// Get parameters names of the given filter. /// - /// [filterType] filter to get param names - /// Returns [PlayerErrors.noError] if no errors and the list of param names - /// + /// [filterType] filter to get param names. + /// Returns [PlayerErrors.noError] if no errors and the list of param names. FFI_PLUGIN_EXPORT enum PlayerErrors getFilterParamNames( enum FilterType filterType, int *paramsCount, char **names) { @@ -1013,56 +1082,186 @@ extern "C" return noError; } - /// Add the filter [filterType] to all sounds. + /// Add the filter [filterType] to [soundHash]. If [soundHash]==0 the + /// filter is added to global filters. /// - /// [filterType] filter to add - /// Returns [PlayerErrors.noError] if no errors - /// - FFI_PLUGIN_EXPORT enum PlayerErrors addGlobalFilter(enum FilterType filterType) + /// [soundHash] the sound to add the filter to. + /// [filterType] filter to add. + /// Returns [PlayerErrors.noError] if no errors. + FFI_PLUGIN_EXPORT enum PlayerErrors addFilter(unsigned int soundHash, enum FilterType filterType) { if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - return player.get()->mFilters.addGlobalFilter(filterType); + if (soundHash == 0) + return player.get()->mFilters.addFilter(filterType); + + auto const s = player.get()->findByHash(soundHash); + if (s == nullptr) + return soundHashNotFound; + + return s->filters->addFilter(filterType); } - /// Remove the filter [filterType]. + /// Remove the filter [filterType] from [soundHash]. If [soundHash]==0 the + /// filter is removed from the global filters. /// - /// [filterType] filter to remove - /// Returns [PlayerErrors.noError] if no errors - /// - FFI_PLUGIN_EXPORT enum PlayerErrors removeGlobalFilter(enum FilterType filterType) + /// [filterType] filter to remove. + /// Returns [PlayerErrors.noError] if no errors. + FFI_PLUGIN_EXPORT enum PlayerErrors removeFilter(unsigned int soundHash, enum FilterType filterType) { if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - if (!player.get()->mFilters.removeGlobalFilter(filterType)) - return filterNotFound; + if (soundHash == 0) + { + if (!player.get()->mFilters.removeFilter(filterType)) + return filterNotFound; + } + else + { + auto const s = player.get()->findByHash(soundHash); + if (s == nullptr) + return soundHashNotFound; + if (!s->filters->removeFilter(filterType)) + return filterNotFound; + } + return noError; } /// Set the effect parameter with id [attributeId] /// of [filterType] with [value] value. /// - /// [filterType] filter to modify a param - /// Returns [PlayerErrors.noError] if no errors - /// - FFI_PLUGIN_EXPORT enum PlayerErrors setFxParams(enum FilterType filterType, int attributeId, float value) + /// [handle] the handle to set the filter to. If equal to 0, the filter is applyed globally. + /// [filterType] filter to modify a param. + /// Returns [PlayerErrors.noError] if no errors. + FFI_PLUGIN_EXPORT enum PlayerErrors setFilterParams(unsigned int handle, enum FilterType filterType, int attributeId, float value) { if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - player.get()->mFilters.setFxParams(filterType, attributeId, value); + /// Not important to call the [SoLoud::AudioSource].setFilterParams() here, SoLoud + /// will set the param globally or by [handle] if [handle] is not ==0. + if (handle == 0) + player.get()->mFilters.setFilterParams(handle, filterType, attributeId, value); + else + { + auto const &s = player.get()->findByHandle(handle); + if (s == nullptr) + { + return soundHandleNotFound; + } + else + { + s->filters.get()->setFilterParams(handle, filterType, attributeId, value); + } + } return noError; } /// Get the effect parameter with id [attributeId] of [filterType]. /// - /// [filterType] filter to modify a param - /// Returns the value of param + /// [handle] the handle to get the filter to. If equal to 0, it gets the global filter. + /// [filterType] filter to modify a param. + /// Returns the value of param or 9999.0 if the filter is not found. + FFI_PLUGIN_EXPORT enum PlayerErrors getFilterParams( + unsigned int handle, + enum FilterType filterType, + int attributeId, + float *filterValue) + { + *filterValue = 9999.0f; + if (player.get() == nullptr || !player.get()->isInited()) + return backendNotInited; + /// If [handle] == 0 get the parameter from global filters else from + /// the sound which owns [handle]. + if (handle == 0) + { + *filterValue = player.get()->mFilters.getFilterParams(handle, filterType, attributeId); + return noError; + } + else + { + auto const &s = player.get()->findByHandle(handle); + if (s == nullptr) + return soundHandleNotFound; + else + { + *filterValue = s->filters.get()->getFilterParams(handle, filterType, attributeId); + if (*filterValue == 9999.0f) + return filterNotFound; + return noError; + } + } + return noError; + } + + /// Fades a parameter of a filter. + /// + /// [handle] the handle of the voice to apply the fade. If equal to 0, it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [to] value the attribute should go in [time] duration. + /// [time] the fade slope duration. + /// Returns [PlayerErrors.noError] if no errors. + FFI_PLUGIN_EXPORT enum PlayerErrors fadeFilterParameter( + unsigned int handle, + enum FilterType filterType, + int attributeId, + float to, + float time) + { + if (player.get() == nullptr || !player.get()->isInited()) + return backendNotInited; + if (handle == 0) + player.get()->mFilters.fadeFilterParameter(handle, filterType, attributeId, to, time); + else + { + auto const &s = player.get()->findByHandle(handle); + if (s == nullptr) + { + return soundHandleNotFound; + } + else + { + s->filters.get()->fadeFilterParameter(handle, filterType, attributeId, to, time); + } + } + return noError; + } + + /// Oscillate a parameter of a filter. /// - FFI_PLUGIN_EXPORT float getFxParams(enum FilterType filterType, int attributeId) + /// [handle] the handle of the voice to apply the fade. If equal to 0, it fades the global filter. + /// [filterType] filter to modify a param. + /// [attributeId] the attribute index to fade. + /// [from] the starting value the attribute sould start to oscillate. + /// [to] the ending value the attribute sould end to oscillate. + /// [time] the fade slope duration. + /// Returns [PlayerErrors.noError] if no errors. + FFI_PLUGIN_EXPORT enum PlayerErrors oscillateFilterParameter( + unsigned int handle, + enum FilterType filterType, + int attributeId, + float from, + float to, + float time) { if (player.get() == nullptr || !player.get()->isInited()) return backendNotInited; - return player.get()->mFilters.getFxParams(filterType, attributeId); + if (handle == 0) + player.get()->mFilters.oscillateFilterParameter(handle, filterType, attributeId, from, to, time); + else + { + auto const &s = player.get()->findByHandle(handle); + if (s == nullptr) + { + return soundHandleNotFound; + } + else + { + s->filters.get()->oscillateFilterParameter(handle, filterType, attributeId, from, to, time); + } + } + return noError; } ///////////////////////////////////////// diff --git a/src/enums.h b/src/enums.h index 96beb7c..200a0c8 100644 --- a/src/enums.h +++ b/src/enums.h @@ -69,4 +69,27 @@ typedef enum PlayerStateEvents event_unlocked, } PlayerEvents_t; +typedef enum SoundType +{ + // using Soloud::wav + TYPE_WAV, + // using Soloud::wavStream + TYPE_WAVSTREAM, + // this sound is a waveform + TYPE_SYNTH +} SoundType_t; + +typedef enum FilterType +{ + BiquadResonantFilter, + EqFilter, + EchoFilter, + LofiFilter, + FlangerFilter, + BassboostFilter, + WaveShaperFilter, + RobotizeFilter, + FreeverbFilter +} FilterType_t; + #endif // ENUMS_H \ No newline at end of file diff --git a/src/ffi_gen_tmp.h b/src/ffi_gen_tmp.h index fbda9cc..219c217 100644 --- a/src/ffi_gen_tmp.h +++ b/src/ffi_gen_tmp.h @@ -23,9 +23,8 @@ struct CaptureDevice //--------------------- copy here the new functions to generate -FFI_PLUGIN_EXPORT enum PlayerErrors loadMem( - char *uniqueName, - unsigned char *buffer, - int length, - int loadIntoMem, - unsigned int *hash); +FFI_PLUGIN_EXPORT enum PlayerErrors getFilterParams( + unsigned int handle, + enum FilterType filterType, + int attributeId, + float *filterValue); diff --git a/src/filters/filters.cpp b/src/filters/filters.cpp index b69a564..2de459b 100644 --- a/src/filters/filters.cpp +++ b/src/filters/filters.cpp @@ -4,13 +4,10 @@ #include #include -Filters::Filters(SoLoud::Soloud *soloud) : mSoloud(soloud) -{ -} +Filters::Filters(SoLoud::Soloud *soloud, ActiveSound *sound) + : mSoloud(soloud), mSound(sound), filters({}) {} -Filters::~Filters() -{ -} +Filters::~Filters() {} int Filters::isFilterActive(FilterType filter) { @@ -127,9 +124,9 @@ std::vector Filters::getFilterParamNames(FilterType filterType) return ret; } -PlayerErrors Filters::addGlobalFilter(FilterType filterType) +PlayerErrors Filters::addFilter(FilterType filterType) { - if (filters.size() >= FILTERS_PER_STREAM) + if ((int)filters.size() >= FILTERS_PER_STREAM) return maxNumberOfFiltersReached; // Check if the new filter is already here. @@ -143,55 +140,82 @@ PlayerErrors Filters::addGlobalFilter(FilterType filterType) case BiquadResonantFilter: if (!mBiquadResonantFilter) mBiquadResonantFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mBiquadResonantFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mBiquadResonantFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mBiquadResonantFilter.get()); filters.push_back({filterType, static_cast(mBiquadResonantFilter.get())}); break; case EqFilter: if (!mEqFilter) mEqFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mEqFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mEqFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mEqFilter.get()); filters.push_back({filterType, static_cast(mEqFilter.get())}); break; case EchoFilter: if (!mEchoFilter) mEchoFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mEchoFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mEchoFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mEchoFilter.get()); filters.push_back({filterType, static_cast(mEchoFilter.get())}); break; case LofiFilter: if (!mLofiFilter) mLofiFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mLofiFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mLofiFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mLofiFilter.get()); filters.push_back({filterType, static_cast(mLofiFilter.get())}); break; case FlangerFilter: if (!mFlangerFilter) mFlangerFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mFlangerFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mFlangerFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mFlangerFilter.get()); filters.push_back({filterType, static_cast(mFlangerFilter.get())}); break; case BassboostFilter: if (!mBassboostFilter) mBassboostFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mBassboostFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mBassboostFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mBassboostFilter.get()); filters.push_back({filterType, static_cast(mBassboostFilter.get())}); break; case WaveShaperFilter: if (!mWaveShaperFilter) mWaveShaperFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mWaveShaperFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mWaveShaperFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mWaveShaperFilter.get()); filters.push_back({filterType, static_cast(mWaveShaperFilter.get())}); break; case RobotizeFilter: if (!mRobotizeFilter) mRobotizeFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mRobotizeFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mRobotizeFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mRobotizeFilter.get()); filters.push_back({filterType, static_cast(mRobotizeFilter.get())}); break; case FreeverbFilter: if (!mFreeverbFilter) mFreeverbFilter = std::make_unique(); - mSoloud->setGlobalFilter(filtersSize, mFreeverbFilter.get()); + if (mSound == nullptr) + mSoloud->setGlobalFilter(filtersSize, mFreeverbFilter.get()); + else + mSound->sound.get()->setFilter(filtersSize, mFreeverbFilter.get()); filters.push_back({filterType, static_cast(mFreeverbFilter.get())}); break; default: @@ -199,8 +223,9 @@ PlayerErrors Filters::addGlobalFilter(FilterType filterType) } return noError; } + /// TODO remove all filters FilterType.none -bool Filters::removeGlobalFilter(FilterType filterType) +bool Filters::removeFilter(FilterType filterType) { int index = isFilterActive(filterType); if (index < 0) @@ -239,11 +264,17 @@ bool Filters::removeGlobalFilter(FilterType filterType) break; } - /// shift filters down by 1 fron [index] + /// shift filters down by 1 from [index] for (int i = index; i < filters.size() - 1; i++) { - mSoloud->setGlobalFilter(i + 1, 0); - mSoloud->setGlobalFilter(i, filters[i+1].filter); + if (mSound == nullptr) + mSoloud->setGlobalFilter(i + 1, 0); + else + mSound->sound.get()->setFilter(i + 1, 0); + if (mSound == nullptr) + mSoloud->setGlobalFilter(i, filters[i + 1].filter); + else + mSound->sound.get()->setFilter(i, filters[i + 1].filter); } /// remove the filter from the list filters.erase(filters.begin() + index); @@ -251,21 +282,45 @@ bool Filters::removeGlobalFilter(FilterType filterType) return true; } -void Filters::setFxParams(FilterType filterType, int attributeId, float value) +void Filters::setFilterParams(SoLoud::handle handle, FilterType filterType, int attributeId, float value) { int index = isFilterActive(filterType); if (index < 0) return; - mSoloud->setFilterParameter(0, index, attributeId, value); + mSoloud->setFilterParameter(handle, index, attributeId, value); } -float Filters::getFxParams(FilterType filterType, int attributeId) +float Filters::getFilterParams(SoLoud::handle handle, FilterType filterType, int attributeId) { int index = isFilterActive(filterType); if (index < 0) - return 0.0f; + return 9999.0f; - float ret = mSoloud->getFilterParameter(0, index, attributeId); + float ret = mSoloud->getFilterParameter(handle, index, attributeId); return ret; } + +void Filters::fadeFilterParameter(SoLoud::handle handle, FilterType filterType, int attributeId, float to, float time) +{ + int index = isFilterActive(filterType); + if (index < 0) + return; + + mSoloud->fadeFilterParameter(handle, index, attributeId, to, time); +} + +void Filters::oscillateFilterParameter( + SoLoud::handle handle, + FilterType filterType, + int attributeId, + float from, + float to, + float time) +{ + int index = isFilterActive(filterType); + if (index < 0) + return; + + mSoloud->oscillateFilterParameter(handle, index, attributeId, from, to, time); +} diff --git a/src/filters/filters.h b/src/filters/filters.h index 4183e5f..cf6b798 100644 --- a/src/filters/filters.h +++ b/src/filters/filters.h @@ -1,6 +1,8 @@ #ifndef FILTERS_H #define FILTERS_H +#include "../active_sound.h" + #include "soloud.h" #include "soloud_filter.h" #include "soloud_biquadresonantfilter.h" @@ -16,55 +18,66 @@ #include "soloud_robotizefilter.h" #include "soloud_freeverbfilter.h" -#include "../enums.h" - #include #include #include -typedef enum FilterType +struct FilterObject { - BiquadResonantFilter, - EqFilter, - EchoFilter, - LofiFilter, - FlangerFilter, - BassboostFilter, - WaveShaperFilter, - RobotizeFilter, - FreeverbFilter -} FilterType_t; - -struct FilterObject { FilterType type; SoLoud::Filter *filter; - bool operator==(FilterType const &i) { + bool operator==(FilterType const &i) + { return (i == type); } }; -class Filters { +/// Class to manage global filters. +class Filters +{ /// TODO(marco): Soloud.setGlobalFilter() /// Sets, or clears, the global filter. /// - /// Setting the global filter to NULL will clear the global filter. - /// The default maximum number of global filters active is 4, but this + /// Setting the global filter to NULL will clear the global filter. + /// The default maximum number of global filters active is 4, but this /// can be changed in a global constant in soloud.h (and rebuilding SoLoud). public: - Filters(SoLoud::Soloud *soloud); + Filters(SoLoud::Soloud *soloud, ActiveSound *sound); ~Filters(); int isFilterActive(FilterType filter); - PlayerErrors addGlobalFilter(FilterType filterType); - bool removeGlobalFilter(FilterType filterType); + + PlayerErrors addFilter(FilterType filterType); + + bool removeFilter(FilterType filterType); + std::vector getFilterParamNames(FilterType filterType); - void setFxParams(FilterType filterType, int attributeId, float value); - float getFxParams(FilterType filterType, int attributeId); + + /// If [handle]==0 the operation is done to global filters. + void setFilterParams(SoLoud::handle handle, FilterType filterType, int attributeId, float value); + + /// If [handle]==0 the operation is done to global filters. + float getFilterParams(SoLoud::handle handle, FilterType filterType, int attributeId); + + /// If [handle]==0 the operation is done to global filters. + void fadeFilterParameter(SoLoud::handle handle, FilterType filterType, int attributeId, float to, float time); + + /// If [handle]==0 the operation is done to global filters. + void oscillateFilterParameter( + SoLoud::handle handle, + FilterType filterType, + int attributeId, + float from, + float to, + float time); private: /// main SoLoud engine, the one used by player.cpp SoLoud::Soloud *mSoloud; + /// The sound to manage filters for. If null the filters are managed globally. + ActiveSound *mSound; + std::vector filters; std::unique_ptr mBiquadResonantFilter; diff --git a/src/player.cpp b/src/player.cpp index c46fee8..4cc6d1b 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -15,7 +15,7 @@ #include #endif -Player::Player() : mInited(false), mFilters(&soloud) {} +Player::Player() : mInited(false), mFilters(&soloud, nullptr) {} Player::~Player() { @@ -32,7 +32,7 @@ void Player::setStateChangedCallback(void (*stateChangedCallback)(unsigned int)) soloud.setStateChangedCallback(stateChangedCallback); } -PlayerErrors Player::init() +PlayerErrors Player::init(unsigned int sampleRate, unsigned int bufferSize, unsigned int channels) { if (mInited) return playerAlreadyInited; @@ -42,9 +42,7 @@ PlayerErrors Player::init() // initialize SoLoud. SoLoud::result result = soloud.init( SoLoud::Soloud::CLIP_ROUNDOFF, - SoLoud::Soloud::MINIAUDIO, 44100, 2048, 2U); - // soloud.init(1U, 0U, 44100, 2048, 2U); - // SoLoud::Thread::sleep(1000); + SoLoud::Soloud::MINIAUDIO, sampleRate, bufferSize, channels); if (result == SoLoud::SO_NO_ERROR) mInited = true; else @@ -128,12 +126,9 @@ PlayerErrors Player::loadFile( unsigned int newHash = (unsigned int)std::hash{}(completeFileName); /// check if the sound has been already loaded - auto const &s = std::find_if( - sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == newHash; }); + auto const s = findByHash(newHash); - if (s != sounds.end()) + if (s != nullptr) { *hash = newHash; return fileAlreadyLoaded; @@ -160,6 +155,8 @@ PlayerErrors Player::loadFile( if (result != SoLoud::SO_NO_ERROR) { sounds.pop_back(); + } else { + sounds.back().get()->filters = std::make_unique(&soloud, sounds.back().get()); } *hash = newHash; @@ -180,12 +177,9 @@ PlayerErrors Player::loadMem( unsigned int newHash = (unsigned int)std::hash{}(uniqueName); /// check if the sound has been already loaded - auto const &s = std::find_if( - sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == newHash; }); + auto const s = findByHash(newHash); - if (s != sounds.end()) + if (s != nullptr) { hash = newHash; return fileAlreadyLoaded; @@ -212,6 +206,8 @@ PlayerErrors Player::loadMem( if (result != SoLoud::SO_NO_ERROR) { sounds.pop_back(); + } else { + sounds.back().get()->filters = std::make_unique(&soloud, sounds.back().get()); } return (PlayerErrors)result; @@ -240,68 +236,59 @@ PlayerErrors Player::loadWaveform( sounds.back().get()->soundHash = hash; sounds.back().get()->sound = std::make_shared((SoLoud::Soloud::WAVEFORM)waveform, superWave, detune, scale); sounds.back().get()->soundType = TYPE_SYNTH; + sounds.back().get()->filters = std::make_unique(&soloud, sounds.back().get()); return noError; } void Player::setWaveformScale(unsigned int soundHash, float newScale) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + auto const s = findByHash(soundHash); - if (s == sounds.end() || s->get()->soundType != TYPE_SYNTH) + if (s == nullptr || s->soundType != TYPE_SYNTH) return; - static_cast(s->get()->sound.get())->setScale(newScale); + static_cast(s->sound.get())->setScale(newScale); } void Player::setWaveformDetune(unsigned int soundHash, float newDetune) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + auto const s = findByHash(soundHash); - if (s == sounds.end() || s->get()->soundType != TYPE_SYNTH) + if (s == nullptr || s->soundType != TYPE_SYNTH) return; - static_cast(s->get()->sound.get())->setDetune(newDetune); + static_cast(s->sound.get())->setDetune(newDetune); } void Player::setWaveform(unsigned int soundHash, int newWaveform) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + auto const s = findByHash(soundHash); - if (s == sounds.end() || s->get()->soundType != TYPE_SYNTH) + if (s == nullptr || s->soundType != TYPE_SYNTH) return; - static_cast(s->get()->sound.get())->setWaveform((SoLoud::Soloud::WAVEFORM)newWaveform); + static_cast(s->sound.get())->setWaveform((SoLoud::Soloud::WAVEFORM)newWaveform); } void Player::setWaveformFreq(unsigned int soundHash, float newFreq) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + auto const s = findByHash(soundHash); - if (s == sounds.end() || s->get()->soundType != TYPE_SYNTH) + if (s == nullptr || s->soundType != TYPE_SYNTH) return; - static_cast(s->get()->sound.get())->setFreq(newFreq); + static_cast(s->sound.get())->setFreq(newFreq); } void Player::setWaveformSuperwave(unsigned int soundHash, bool superwave) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + auto const s = findByHash(soundHash); - if (s == sounds.end() || s->get()->soundType != TYPE_SYNTH) + if (s == nullptr || s->soundType != TYPE_SYNTH) return; - static_cast(s->get()->sound.get())->setSuperWave(superwave); + static_cast(s->sound.get())->setSuperWave(superwave); } void Player::pauseSwitch(unsigned int handle) @@ -339,15 +326,10 @@ unsigned int Player::play( bool looping, double loopingStartAt) { - auto const &s = std::find_if( - sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); - - if (s == sounds.end()) - return 0; + ActiveSound *sound = findByHash(soundHash); - ActiveSound *sound = s->get(); + if (sound == nullptr) + return soundHashNotFound; SoLoud::handle newHandle = soloud.play( *sound->sound.get(), volume, pan, paused, 0); @@ -393,14 +375,12 @@ void Player::removeHandle(unsigned int handle) void Player::disposeSound(unsigned int soundHash) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); + ActiveSound *sound = findByHash(soundHash); - if (s == sounds.end()) + if (sound == nullptr) return; - s->get()->sound.get()->stop(); + sound->sound.get()->stop(); // remove the sound from the list sounds.erase(std::remove_if(sounds.begin(), sounds.end(), [soundHash](std::shared_ptr &f) @@ -444,6 +424,7 @@ PlayerErrors Player::textToSpeech(const std::string &textToSpeech, unsigned int if (result == SoLoud::SO_NO_ERROR) { handle = soloud.play(speech); + sounds.back().get()->filters = std::make_unique(&soloud, sounds.back().get()); sounds.back().get()->handle.push_back(handle); } else @@ -476,16 +457,15 @@ float *Player::getWave() // The length in seconds double Player::getLength(unsigned int soundHash) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); - if (s == sounds.end() || s->get()->soundType == TYPE_SYNTH) + auto const &s = findByHash(soundHash); + + if (s == nullptr || s->soundType == TYPE_SYNTH) return 0.0; - if (s->get()->soundType == TYPE_WAV) - return static_cast(s->get()->sound.get())->getLength(); + if (s->soundType == TYPE_WAV) + return static_cast(s->sound.get())->getLength(); - // if (s->get()->soundType == TYPE_WAVSTREAM) - return static_cast(s->get()->sound.get())->getLength(); + // if (s->soundType == TYPE_WAVSTREAM) + return static_cast(s->sound.get())->getLength(); } // time in seconds @@ -551,9 +531,9 @@ void Player::setPanAbsolute(SoLoud::handle handle, float panLeft, float panRight soloud.setPanAbsolute(handle, panLeft, panRight); } -bool Player::isValidVoiceHandle(SoLoud::handle handle) +bool Player::isValidHandle(SoLoud::handle handle) { - return soloud.isValidVoiceHandle(handle); + return soloud.isValidVoiceHandle(handle) || soloud.isVoiceGroup(handle); } unsigned int Player::getActiveVoiceCount() @@ -563,19 +543,18 @@ unsigned int Player::getActiveVoiceCount() int Player::countAudioSource(unsigned int soundHash) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); - if (s == sounds.end() || s->get()->soundType == TYPE_SYNTH) + auto const &s = findByHash(soundHash); + + if (s == nullptr || s->soundType == TYPE_SYNTH) return 0; - if (s->get()->soundType == TYPE_WAV) + if (s->soundType == TYPE_WAV) { - SoLoud::AudioSource *as = static_cast(s->get()->sound.get()); + SoLoud::AudioSource *as = static_cast(s->sound.get()); return soloud.countAudioSource(*as); } - // if (s->get()->soundType == TYPE_WAVSTREAM) - SoLoud::AudioSource *as = static_cast(s->get()->sound.get()); + // if (s->soundType == TYPE_WAVSTREAM) + SoLoud::AudioSource *as = static_cast(s->sound.get()); return soloud.countAudioSource(*as); } @@ -625,6 +604,17 @@ ActiveSound *Player::findByHandle(SoLoud::handle handle) return nullptr; } +ActiveSound *Player::findByHash(unsigned int soundHash) +{ + auto const &s = std::find_if(sounds.begin(), sounds.end(), + [&](std::shared_ptr const &f) + { return f->soundHash == soundHash; }); + if (s == sounds.end()) + return nullptr; + + return s->get(); +} + void Player::debug() { int n = 0; @@ -639,6 +629,31 @@ void Player::debug() } } +///////////////////////////////////////// +/// voice groups +///////////////////////////////////////// + +unsigned int Player::createVoiceGroup() { + auto ret = soloud.createVoiceGroup(); + return ret; +} + +void Player::destroyVoiceGroup(SoLoud::handle handle) { + soloud.destroyVoiceGroup(handle); +} + +void Player::addVoiceToGroup(SoLoud::handle voiceGroupHandle, SoLoud::handle voiceHandle) { + soloud.addVoiceToGroup(voiceGroupHandle, voiceHandle); +} + +bool Player::isVoiceGroup(SoLoud::handle handle) { + return soloud.isVoiceGroup(handle); +} + +bool Player::isVoiceGroupEmpty(SoLoud::handle handle) { + return soloud.isVoiceGroupEmpty(handle); +} + ///////////////////////////////////////// /// faders ///////////////////////////////////////// @@ -716,13 +731,10 @@ unsigned int Player::play3d( bool looping, double loopingStartAt) { - auto const &s = std::find_if(sounds.begin(), sounds.end(), - [&](std::shared_ptr const &f) - { return f->soundHash == soundHash; }); - if (s == sounds.end()) - return 0; + ActiveSound *sound = findByHash(soundHash); + if (sound == 0) + return soundHashNotFound; - ActiveSound *sound = s->get(); SoLoud::handle newHandle = soloud.play3d( *sound->sound.get(), posX, posY, posZ, diff --git a/src/player.h b/src/player.h index 0dcf786..3a01576 100644 --- a/src/player.h +++ b/src/player.h @@ -4,9 +4,10 @@ #define PLAYER_H #include "enums.h" +#include "filters/filters.h" +#include "active_sound.h" #include "soloud.h" #include "soloud_speech.h" -#include "filters/filters.h" #include #include @@ -16,27 +17,6 @@ #include #include -typedef enum SoundType -{ - // using Soloud::wav - TYPE_WAV, - // using Soloud::wavStream - TYPE_WAVSTREAM, - // this sound is a waveform - TYPE_SYNTH -} SoundType_t; - -/// The default number of concurrent voices - maximum number of "streams" - is 16, -/// but this can be adjusted at runtime -struct ActiveSound -{ - std::shared_ptr sound; - SoundType soundType; - std::vector handle; - // unique identifier of this sound based on the file name - unsigned int soundHash; - std::string completeFileName; -}; class Player { @@ -45,8 +25,12 @@ class Player ~Player(); /// @brief Initialize the player. Must be called before any other player functions. + /// @param sampleRate sample rate. Usually is 22050, 44100 (CD quality) or 48000. + /// @param bufferSize the audio buffer size. Usually is 2048, but can be also 512 when + /// low latency is needed for example in games. + /// @param channels 1)mono, 2)stereo 4)quad 6)5.1 8)7.1 /// @return Returns [PlayerErrors.SO_NO_ERROR] if success. - PlayerErrors init(); + PlayerErrors init(unsigned int sampleRate, unsigned int bufferSize, unsigned int channels); /// @brief Set a function callback triggered when a voice is stopped/ended. void setVoiceEndedCallback(void (*voiceEndedCallback)(unsigned int*)); @@ -307,7 +291,7 @@ class Player /// @brief Check if a handle is still valid. /// @param handle handle to check. /// @return true if it still exists. - bool isValidVoiceHandle(SoLoud::handle handle); + bool isValidHandle(SoLoud::handle handle); /// @brief Returns the number of concurrent sounds that are playing at the moment. unsigned int getActiveVoiceCount(); @@ -355,8 +339,40 @@ class Player /// @return If not found, return nullptr. ActiveSound *findByHandle(SoLoud::handle handle); + /// @brief Find a sound by its handle. + /// @param handle the handle to search. + /// @return If not found, return nullptr. + ActiveSound *findByHash(unsigned int hash); + void debug(); + ///////////////////////////////////////// + /// voice groups + ///////////////////////////////////////// + + /// @brief Used to create a new voice group. Returns 0 if not successful. + unsigned int createVoiceGroup(); + + /// @brief Deallocates the voice group. Does not stop the voices attached to the voice group. + /// @param handle the group handle to destroy. + void destroyVoiceGroup(SoLoud::handle handle); + + /// @brief Adds voice handle to the voice group. The voice handles can still be used separate from the group. + /// @param voiceGroupHandle the group handle to add the new [handle]. + /// @param voiceHandle voice handle to add to the [voiceGroupHandle]. + void addVoiceToGroup(SoLoud::handle voiceGroupHandle, SoLoud::handle voiceHandle); + + /// @brief Checks if the handle is a valid voice group. Does not care if the voice group is empty. + /// @param handle the group handle to check. + /// @return true if [handle] is a group handle. + bool isVoiceGroup(SoLoud::handle handle); + + /// @brief Checks whether a voice group is empty. SoLoud automatically trims the voice groups of + /// voices that have ended, so the group may be empty even though you've added valid voice handles to it. + /// @param handle group handle to check. + /// @return true if the group handle doesn't have any voices. + bool isVoiceGroupEmpty(SoLoud::handle handle); + ///////////////////////////////////////// /// faders & oscillators ///////////////////////////////////////// @@ -518,7 +534,7 @@ class Player /// speech object SoLoud::Speech speech; - /// Filters + /// Global filters Filters mFilters; private: diff --git a/web/libflutter_soloud_plugin.js b/web/libflutter_soloud_plugin.js index 6a76334..8a2fee3 100644 --- a/web/libflutter_soloud_plugin.js +++ b/web/libflutter_soloud_plugin.js @@ -1 +1 @@ -var Module=typeof Module!="undefined"?Module:{};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);if(typeof module!="undefined"){module["exports"]=Module}process.on("uncaughtException",ex=>{if(ex!=="unwind"&&!(ex instanceof ExitStatus)&&!(ex.context instanceof ExitStatus)){throw ex}});quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{if(isFileURI(url)){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null);return}fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))}).then(onload,onerror)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];function getSafeHeapType(bytes,isFloat){switch(bytes){case 1:return"i8";case 2:return"i16";case 4:return isFloat?"float":"i32";case 8:return isFloat?"double":"i64";default:abort(`getSafeHeapType() invalid bytes=${bytes}`)}}function SAFE_HEAP_STORE(dest,value,bytes,isFloat){if(dest<=0)abort(`segmentation fault storing ${bytes} bytes to address ${dest}`);if(dest%bytes!==0)abort(`alignment error storing to address ${dest}, which was expected to be aligned to a multiple of ${bytes}`);if(runtimeInitialized){var brk=_sbrk(0);if(dest+bytes>brk)abort(`segmentation fault, exceeded the top of the available dynamic heap when storing ${bytes} bytes to address ${dest}. DYNAMICTOP=${brk}`);if(brk<_emscripten_stack_get_base())abort(`brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`);if(brk>wasmMemory.buffer.byteLength)abort(`brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`)}setValue_safe(dest,value,getSafeHeapType(bytes,isFloat));return value}function SAFE_HEAP_STORE_D(dest,value,bytes){return SAFE_HEAP_STORE(dest,value,bytes,true)}function SAFE_HEAP_LOAD(dest,bytes,unsigned,isFloat){if(dest<=0)abort(`segmentation fault loading ${bytes} bytes from address ${dest}`);if(dest%bytes!==0)abort(`alignment error loading from address ${dest}, which was expected to be aligned to a multiple of ${bytes}`);if(runtimeInitialized){var brk=_sbrk(0);if(dest+bytes>brk)abort(`segmentation fault, exceeded the top of the available dynamic heap when loading ${bytes} bytes from address ${dest}. DYNAMICTOP=${brk}`);if(brk<_emscripten_stack_get_base())abort(`brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`);if(brk>wasmMemory.buffer.byteLength)abort(`brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`)}var type=getSafeHeapType(bytes,isFloat);var ret=getValue_safe(dest,type);if(unsigned)ret=unSign(ret,parseInt(type.substr(1),10));return ret}function SAFE_HEAP_LOAD_D(dest,bytes,unsigned){return SAFE_HEAP_LOAD(dest,bytes,unsigned,true)}function segfault(){abort("segmentation fault")}function alignfault(){abort("alignment fault")}var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="libflutter_soloud_plugin.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),error=>{try{resolve(getBinarySync(binaryFile))}catch(e){reject(e)}})})}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["q"];updateMemoryViews();addOnInit(wasmExports["r"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);return false}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult);return{}}var tempDouble;var tempI64;var ASM_CONSTS={67376:($0,$1,$2,$3,$4)=>{if(typeof window==="undefined"||(window.AudioContext||window.webkitAudioContext)===undefined){return 0}if(typeof window.miniaudio==="undefined"){window.miniaudio={referenceCount:0};window.miniaudio.device_type={};window.miniaudio.device_type.playback=$0;window.miniaudio.device_type.capture=$1;window.miniaudio.device_type.duplex=$2;window.miniaudio.device_state={};window.miniaudio.device_state.stopped=$3;window.miniaudio.device_state.started=$4;let miniaudio=window.miniaudio;miniaudio.devices=[];miniaudio.track_device=function(device){for(var iDevice=0;iDevice0){if(miniaudio.devices[miniaudio.devices.length-1]==null){miniaudio.devices.pop()}else{break}}};miniaudio.untrack_device=function(device){for(var iDevice=0;iDevice{_ma_device__on_notification_unlocked(device.pDevice)},error=>{console.error("Failed to resume audiocontext",error)})}}miniaudio.unlock_event_types.map(function(event_type){document.removeEventListener(event_type,miniaudio.unlock,true)})};miniaudio.unlock_event_types.map(function(event_type){document.addEventListener(event_type,miniaudio.unlock,true)})}window.miniaudio.referenceCount+=1;return 1},69554:()=>{if(typeof window.miniaudio!=="undefined"){miniaudio.unlock_event_types.map(function(event_type){document.removeEventListener(event_type,miniaudio.unlock,true)});window.miniaudio.referenceCount-=1;if(window.miniaudio.referenceCount===0){delete window.miniaudio}}},69844:()=>navigator.mediaDevices!==undefined&&navigator.mediaDevices.getUserMedia!==undefined,69948:()=>{try{var temp=new(window.AudioContext||window.webkitAudioContext);var sampleRate=temp.sampleRate;temp.close();return sampleRate}catch(e){return 0}},70119:($0,$1,$2,$3,$4,$5)=>{var deviceType=$0;var channels=$1;var sampleRate=$2;var bufferSize=$3;var pIntermediaryBuffer=$4;var pDevice=$5;if(typeof window.miniaudio==="undefined"){return-1}var device={};var audioContextOptions={};if(deviceType==window.miniaudio.device_type.playback&&sampleRate!=0){audioContextOptions.sampleRate=sampleRate}device.webaudio=new(window.AudioContext||window.webkitAudioContext)(audioContextOptions);device.webaudio.suspend();device.state=window.miniaudio.device_state.stopped;var channelCountIn=0;var channelCountOut=channels;if(deviceType!=window.miniaudio.device_type.playback){channelCountIn=channels}device.scriptNode=device.webaudio.createScriptProcessor(bufferSize,channelCountIn,channelCountOut);device.scriptNode.onaudioprocess=function(e){if(device.intermediaryBufferView==null||device.intermediaryBufferView.length==0){device.intermediaryBufferView=new Float32Array(HEAPF32.buffer,pIntermediaryBuffer,bufferSize*channels)}if(deviceType==window.miniaudio.device_type.capture||deviceType==window.miniaudio.device_type.duplex){for(var iChannel=0;iChannelwindow.miniaudio.get_device_by_index($0).webaudio.sampleRate,73069:$0=>{var device=window.miniaudio.get_device_by_index($0);if(device.scriptNode!==undefined){device.scriptNode.onaudioprocess=function(e){};device.scriptNode.disconnect();device.scriptNode=undefined}if(device.streamNode!==undefined){device.streamNode.disconnect();device.streamNode=undefined}device.webaudio.close();device.webaudio=undefined;device.pDevice=undefined},73469:$0=>{window.miniaudio.untrack_device_by_index($0)},73519:$0=>{var device=window.miniaudio.get_device_by_index($0);device.webaudio.resume();device.state=window.miniaudio.device_state.started},73658:$0=>{var device=window.miniaudio.get_device_by_index($0);device.webaudio.suspend();device.state=window.miniaudio.device_state.stopped},73798:()=>{if(!Module.wasmWorker){var workerUri="assets/packages/flutter_soloud/web/worker.dart.js";console.log("EM_ASM creating web worker!");Module.wasmWorker=new Worker(workerUri)}else{console.log("EM_ASM web worker already created!")}},74046:($0,$1)=>{if(Module.wasmWorker){console.log("EM_ASM posting message "+UTF8ToString($0)+" with value "+$1);Module.wasmWorker.postMessage(JSON.stringify({message:UTF8ToString($0),value:$1}))}else{console.error("Worker not found.")}}};function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}Module["ExitStatus"]=ExitStatus;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};Module["callRuntimeCallbacks"]=callRuntimeCallbacks;function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return SAFE_HEAP_LOAD(ptr,1,0);case"i8":return SAFE_HEAP_LOAD(ptr,1,0);case"i16":return SAFE_HEAP_LOAD((ptr>>1)*2,2,0);case"i32":return SAFE_HEAP_LOAD((ptr>>2)*4,4,0);case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return SAFE_HEAP_LOAD_D((ptr>>2)*4,4,0);case"double":return SAFE_HEAP_LOAD_D((ptr>>3)*8,8,0);case"*":return SAFE_HEAP_LOAD((ptr>>2)*4,4,1);default:abort(`invalid type for getValue: ${type}`)}}Module["getValue"]=getValue;function getValue_safe(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}Module["getValue_safe"]=getValue_safe;var noExitRuntime=Module["noExitRuntime"]||true;Module["noExitRuntime"]=noExitRuntime;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":SAFE_HEAP_STORE(ptr,value,1);break;case"i8":SAFE_HEAP_STORE(ptr,value,1);break;case"i16":SAFE_HEAP_STORE((ptr>>1)*2,value,2);break;case"i32":SAFE_HEAP_STORE((ptr>>2)*4,value,4);break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":SAFE_HEAP_STORE_D((ptr>>2)*4,value,4);break;case"double":SAFE_HEAP_STORE_D((ptr>>3)*8,value,8);break;case"*":SAFE_HEAP_STORE((ptr>>2)*4,value,4);break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue"]=setValue;function setValue_safe(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue_safe"]=setValue_safe;var stackRestore=val=>__emscripten_stack_restore(val);Module["stackRestore"]=stackRestore;var stackSave=()=>_emscripten_stack_get_current();Module["stackSave"]=stackSave;var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};Module["UTF8ArrayToString"]=UTF8ArrayToString;var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";Module["UTF8ToString"]=UTF8ToString;var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])};Module["___assert_fail"]=___assert_fail;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){SAFE_HEAP_STORE((this.ptr+4>>2)*4,type,4)}get_type(){return SAFE_HEAP_LOAD((this.ptr+4>>2)*4,4,1)}set_destructor(destructor){SAFE_HEAP_STORE((this.ptr+8>>2)*4,destructor,4)}get_destructor(){return SAFE_HEAP_LOAD((this.ptr+8>>2)*4,4,1)}set_caught(caught){caught=caught?1:0;SAFE_HEAP_STORE(this.ptr+12,caught,1)}get_caught(){return SAFE_HEAP_LOAD(this.ptr+12,1,0)!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;SAFE_HEAP_STORE(this.ptr+13,rethrown,1)}get_rethrown(){return SAFE_HEAP_LOAD(this.ptr+13,1,0)!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){SAFE_HEAP_STORE((this.ptr+16>>2)*4,adjustedPtr,4)}get_adjusted_ptr(){return SAFE_HEAP_LOAD((this.ptr+16>>2)*4,4,1)}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return SAFE_HEAP_LOAD((this.excPtr>>2)*4,4,1)}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}Module["ExceptionInfo"]=ExceptionInfo;var exceptionLast=0;Module["exceptionLast"]=exceptionLast;var uncaughtExceptionCount=0;Module["uncaughtExceptionCount"]=uncaughtExceptionCount;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};Module["___cxa_throw"]=___cxa_throw;function syscallGetVarargI(){var ret=SAFE_HEAP_LOAD((+SYSCALLS.varargs>>2)*4,4,0);SYSCALLS.varargs+=4;return ret}Module["syscallGetVarargI"]=syscallGetVarargI;var syscallGetVarargP=syscallGetVarargI;Module["syscallGetVarargP"]=syscallGetVarargP;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};Module["PATH"]=PATH;var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};Module["initRandomFill"]=initRandomFill;var randomFill=view=>(randomFill=initRandomFill())(view);Module["randomFill"]=randomFill;var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};Module["stringToUTF8Array"]=stringToUTF8Array;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};Module["FS_stdin_getChar"]=FS_stdin_getChar;var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};Module["TTY"]=TTY;var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};Module["zeroMemory"]=zeroMemory;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;Module["alignMemory"]=alignMemory;var mmapAlloc=size=>{abort()};Module["mmapAlloc"]=mmapAlloc;var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};Module["asyncLoad"]=asyncLoad;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};Module["FS_createDataFile"]=FS_createDataFile;var preloadPlugins=Module["preloadPlugins"]||[];Module["preloadPlugins"]=preloadPlugins;var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};Module["FS_createPreloadedFile"]=FS_createPreloadedFile;var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};Module["FS_modeStringToFlags"]=FS_modeStringToFlags;var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};Module["FS_getMode"]=FS_getMode;var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS:MEMFS}},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);SAFE_HEAP_STORE((buf>>2)*4,stat.dev,4);SAFE_HEAP_STORE((buf+4>>2)*4,stat.mode,4);SAFE_HEAP_STORE((buf+8>>2)*4,stat.nlink,4);SAFE_HEAP_STORE((buf+12>>2)*4,stat.uid,4);SAFE_HEAP_STORE((buf+16>>2)*4,stat.gid,4);SAFE_HEAP_STORE((buf+20>>2)*4,stat.rdev,4);tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+24>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+28>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+32>>2)*4,4096,4);SAFE_HEAP_STORE((buf+36>>2)*4,stat.blocks,4);var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+40>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+44>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+48>>2)*4,atime%1e3*1e3,4);tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+56>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+60>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+64>>2)*4,mtime%1e3*1e3,4);tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+72>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+76>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+80>>2)*4,ctime%1e3*1e3,4);tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+88>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+92>>2)*4,tempI64[1],4);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};Module["SYSCALLS"]=SYSCALLS;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;SAFE_HEAP_STORE((arg+offset>>1)*2,2,2);return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fcntl64"]=___syscall_fcntl64;function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>2)*4,termios.c_iflag||0,4);SAFE_HEAP_STORE((argp+4>>2)*4,termios.c_oflag||0,4);SAFE_HEAP_STORE((argp+8>>2)*4,termios.c_cflag||0,4);SAFE_HEAP_STORE((argp+12>>2)*4,termios.c_lflag||0,4);for(var i=0;i<32;i++){SAFE_HEAP_STORE(argp+i+17,termios.c_cc[i]||0,1)}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=SAFE_HEAP_LOAD((argp>>2)*4,4,0);var c_oflag=SAFE_HEAP_LOAD((argp+4>>2)*4,4,0);var c_cflag=SAFE_HEAP_LOAD((argp+8>>2)*4,4,0);var c_lflag=SAFE_HEAP_LOAD((argp+12>>2)*4,4,0);var c_cc=[];for(var i=0;i<32;i++){c_cc.push(SAFE_HEAP_LOAD(argp+i+17,1,0))}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>2)*4,0,4);return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>1)*2,winsize[0],2);SAFE_HEAP_STORE((argp+2>>1)*2,winsize[1],2)}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ioctl"]=___syscall_ioctl;function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_openat"]=___syscall_openat;var __abort_js=()=>{abort("")};Module["__abort_js"]=__abort_js;var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);Module["__emscripten_memcpy_js"]=__emscripten_memcpy_js;var readEmAsmArgsArray=[];Module["readEmAsmArgsArray"]=readEmAsmArgsArray;var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=SAFE_HEAP_LOAD(sigPtr++,1,1)){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?SAFE_HEAP_LOAD((buf>>2)*4,4,1):ch==105?SAFE_HEAP_LOAD((buf>>2)*4,4,0):SAFE_HEAP_LOAD_D((buf>>3)*8,8,0));buf+=wide?8:4}return readEmAsmArgsArray};Module["readEmAsmArgs"]=readEmAsmArgs;var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};Module["runEmAsmFunction"]=runEmAsmFunction;var _emscripten_asm_const_int=(code,sigPtr,argbuf)=>runEmAsmFunction(code,sigPtr,argbuf);Module["_emscripten_asm_const_int"]=_emscripten_asm_const_int;var getHeapMax=()=>2147483648;Module["getHeapMax"]=getHeapMax;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};Module["growMemory"]=growMemory;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};Module["_emscripten_resize_heap"]=_emscripten_resize_heap;function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_close"]=_fd_close;var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2)*4,4,1);var len=SAFE_HEAP_LOAD((iov+4>>2)*4,4,1);iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2)*4,num,4);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_read"]=_fd_read;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((newOffset>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((newOffset+4>>2)*4,tempI64[1],4);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_seek"]=_fd_seek;var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2)*4,4,1);var len=SAFE_HEAP_LOAD((iov+4>>2)*4,4,1);iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!="undefined"){offset+=curr}}return ret};Module["doWritev"]=doWritev;function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);SAFE_HEAP_STORE((pnum>>2)*4,num,4);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_write"]=_fd_write;var _getentropy=(buffer,size)=>{randomFill(HEAPU8.subarray(buffer,buffer+size));return 0};Module["_getentropy"]=_getentropy;var getCFunc=ident=>{var func=Module["_"+ident];return func};Module["getCFunc"]=getCFunc;var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};Module["writeArrayToMemory"]=writeArrayToMemory;var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;var stackAlloc=sz=>__emscripten_stack_alloc(sz);Module["stackAlloc"]=stackAlloc;var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};Module["stringToUTF8OnStack"]=stringToUTF8OnStack;var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};Module["cwrap"]=cwrap;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();var wasmImports={a:___assert_fail,h:___cxa_throw,g:___syscall_fcntl64,j:___syscall_ioctl,k:___syscall_openat,o:__abort_js,l:__emscripten_memcpy_js,c:alignfault,d:_emscripten_asm_const_int,p:_emscripten_resize_heap,e:_fd_close,i:_fd_read,m:_fd_seek,f:_fd_write,n:_getentropy,b:segfault};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["r"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["t"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["u"])(a0);var _ma_device__on_notification_unlocked=Module["_ma_device__on_notification_unlocked"]=a0=>(_ma_device__on_notification_unlocked=Module["_ma_device__on_notification_unlocked"]=wasmExports["v"])(a0);var _ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=(a0,a1)=>(_ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=wasmExports["w"])(a0,a1);var _ma_free_emscripten=Module["_ma_free_emscripten"]=(a0,a1)=>(_ma_free_emscripten=Module["_ma_free_emscripten"]=wasmExports["x"])(a0,a1);var _ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=wasmExports["y"])(a0,a1,a2);var _ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=wasmExports["z"])(a0,a1,a2);var _createWorkerInWasm=Module["_createWorkerInWasm"]=()=>(_createWorkerInWasm=Module["_createWorkerInWasm"]=wasmExports["A"])();var _sendToWorker=Module["_sendToWorker"]=(a0,a1)=>(_sendToWorker=Module["_sendToWorker"]=wasmExports["B"])(a0,a1);var _nativeFree=Module["_nativeFree"]=a0=>(_nativeFree=Module["_nativeFree"]=wasmExports["C"])(a0);var _voiceEndedCallback=Module["_voiceEndedCallback"]=a0=>(_voiceEndedCallback=Module["_voiceEndedCallback"]=wasmExports["D"])(a0);var _setDartEventCallback=Module["_setDartEventCallback"]=(a0,a1,a2)=>(_setDartEventCallback=Module["_setDartEventCallback"]=wasmExports["E"])(a0,a1,a2);var _initEngine=Module["_initEngine"]=()=>(_initEngine=Module["_initEngine"]=wasmExports["F"])();var _dispose=Module["_dispose"]=()=>(_dispose=Module["_dispose"]=wasmExports["G"])();var _isInited=Module["_isInited"]=()=>(_isInited=Module["_isInited"]=wasmExports["H"])();var _loadFile=Module["_loadFile"]=(a0,a1)=>(_loadFile=Module["_loadFile"]=wasmExports["I"])(a0,a1);var _loadMem=Module["_loadMem"]=(a0,a1,a2,a3,a4)=>(_loadMem=Module["_loadMem"]=wasmExports["J"])(a0,a1,a2,a3,a4);var _loadWaveform=Module["_loadWaveform"]=(a0,a1,a2,a3,a4)=>(_loadWaveform=Module["_loadWaveform"]=wasmExports["K"])(a0,a1,a2,a3,a4);var _setWaveformScale=Module["_setWaveformScale"]=(a0,a1)=>(_setWaveformScale=Module["_setWaveformScale"]=wasmExports["L"])(a0,a1);var _setWaveformDetune=Module["_setWaveformDetune"]=(a0,a1)=>(_setWaveformDetune=Module["_setWaveformDetune"]=wasmExports["M"])(a0,a1);var _setWaveformFreq=Module["_setWaveformFreq"]=(a0,a1)=>(_setWaveformFreq=Module["_setWaveformFreq"]=wasmExports["N"])(a0,a1);var _setSuperWave=Module["_setSuperWave"]=(a0,a1)=>(_setSuperWave=Module["_setSuperWave"]=wasmExports["O"])(a0,a1);var _setWaveform=Module["_setWaveform"]=(a0,a1)=>(_setWaveform=Module["_setWaveform"]=wasmExports["P"])(a0,a1);var _speechText=Module["_speechText"]=(a0,a1)=>(_speechText=Module["_speechText"]=wasmExports["Q"])(a0,a1);var _pauseSwitch=Module["_pauseSwitch"]=a0=>(_pauseSwitch=Module["_pauseSwitch"]=wasmExports["R"])(a0);var _setPause=Module["_setPause"]=(a0,a1)=>(_setPause=Module["_setPause"]=wasmExports["S"])(a0,a1);var _getPause=Module["_getPause"]=a0=>(_getPause=Module["_getPause"]=wasmExports["T"])(a0);var _setRelativePlaySpeed=Module["_setRelativePlaySpeed"]=(a0,a1)=>(_setRelativePlaySpeed=Module["_setRelativePlaySpeed"]=wasmExports["U"])(a0,a1);var _getRelativePlaySpeed=Module["_getRelativePlaySpeed"]=a0=>(_getRelativePlaySpeed=Module["_getRelativePlaySpeed"]=wasmExports["V"])(a0);var _play=Module["_play"]=(a0,a1,a2,a3,a4,a5,a6)=>(_play=Module["_play"]=wasmExports["W"])(a0,a1,a2,a3,a4,a5,a6);var _stop=Module["_stop"]=a0=>(_stop=Module["_stop"]=wasmExports["X"])(a0);var _disposeSound=Module["_disposeSound"]=a0=>(_disposeSound=Module["_disposeSound"]=wasmExports["Y"])(a0);var _disposeAllSound=Module["_disposeAllSound"]=()=>(_disposeAllSound=Module["_disposeAllSound"]=wasmExports["Z"])();var _getLooping=Module["_getLooping"]=a0=>(_getLooping=Module["_getLooping"]=wasmExports["_"])(a0);var _setLooping=Module["_setLooping"]=(a0,a1)=>(_setLooping=Module["_setLooping"]=wasmExports["$"])(a0,a1);var _getLoopPoint=Module["_getLoopPoint"]=a0=>(_getLoopPoint=Module["_getLoopPoint"]=wasmExports["aa"])(a0);var _setLoopPoint=Module["_setLoopPoint"]=(a0,a1)=>(_setLoopPoint=Module["_setLoopPoint"]=wasmExports["ba"])(a0,a1);var _setVisualizationEnabled=Module["_setVisualizationEnabled"]=a0=>(_setVisualizationEnabled=Module["_setVisualizationEnabled"]=wasmExports["ca"])(a0);var _getVisualizationEnabled=Module["_getVisualizationEnabled"]=()=>(_getVisualizationEnabled=Module["_getVisualizationEnabled"]=wasmExports["da"])();var _getFft=Module["_getFft"]=a0=>(_getFft=Module["_getFft"]=wasmExports["ea"])(a0);var _getWave=Module["_getWave"]=a0=>(_getWave=Module["_getWave"]=wasmExports["fa"])(a0);var _setFftSmoothing=Module["_setFftSmoothing"]=a0=>(_setFftSmoothing=Module["_setFftSmoothing"]=wasmExports["ga"])(a0);var _getAudioTexture=Module["_getAudioTexture"]=a0=>(_getAudioTexture=Module["_getAudioTexture"]=wasmExports["ha"])(a0);var _getAudioTexture2D=Module["_getAudioTexture2D"]=a0=>(_getAudioTexture2D=Module["_getAudioTexture2D"]=wasmExports["ia"])(a0);var _getTextureValue=Module["_getTextureValue"]=(a0,a1)=>(_getTextureValue=Module["_getTextureValue"]=wasmExports["ja"])(a0,a1);var _getLength=Module["_getLength"]=a0=>(_getLength=Module["_getLength"]=wasmExports["ka"])(a0);var _seek=Module["_seek"]=(a0,a1)=>(_seek=Module["_seek"]=wasmExports["la"])(a0,a1);var _getPosition=Module["_getPosition"]=a0=>(_getPosition=Module["_getPosition"]=wasmExports["ma"])(a0);var _getGlobalVolume=Module["_getGlobalVolume"]=()=>(_getGlobalVolume=Module["_getGlobalVolume"]=wasmExports["na"])();var _setGlobalVolume=Module["_setGlobalVolume"]=a0=>(_setGlobalVolume=Module["_setGlobalVolume"]=wasmExports["oa"])(a0);var _getVolume=Module["_getVolume"]=a0=>(_getVolume=Module["_getVolume"]=wasmExports["pa"])(a0);var _setVolume=Module["_setVolume"]=(a0,a1)=>(_setVolume=Module["_setVolume"]=wasmExports["qa"])(a0,a1);var _getPan=Module["_getPan"]=a0=>(_getPan=Module["_getPan"]=wasmExports["ra"])(a0);var _setPan=Module["_setPan"]=(a0,a1)=>(_setPan=Module["_setPan"]=wasmExports["sa"])(a0,a1);var _setPanAbsolute=Module["_setPanAbsolute"]=(a0,a1,a2)=>(_setPanAbsolute=Module["_setPanAbsolute"]=wasmExports["ta"])(a0,a1,a2);var _getIsValidVoiceHandle=Module["_getIsValidVoiceHandle"]=a0=>(_getIsValidVoiceHandle=Module["_getIsValidVoiceHandle"]=wasmExports["ua"])(a0);var _getActiveVoiceCount=Module["_getActiveVoiceCount"]=()=>(_getActiveVoiceCount=Module["_getActiveVoiceCount"]=wasmExports["va"])();var _countAudioSource=Module["_countAudioSource"]=a0=>(_countAudioSource=Module["_countAudioSource"]=wasmExports["wa"])(a0);var _getVoiceCount=Module["_getVoiceCount"]=()=>(_getVoiceCount=Module["_getVoiceCount"]=wasmExports["xa"])();var _getProtectVoice=Module["_getProtectVoice"]=a0=>(_getProtectVoice=Module["_getProtectVoice"]=wasmExports["ya"])(a0);var _setProtectVoice=Module["_setProtectVoice"]=(a0,a1)=>(_setProtectVoice=Module["_setProtectVoice"]=wasmExports["za"])(a0,a1);var _getMaxActiveVoiceCount=Module["_getMaxActiveVoiceCount"]=()=>(_getMaxActiveVoiceCount=Module["_getMaxActiveVoiceCount"]=wasmExports["Aa"])();var _setMaxActiveVoiceCount=Module["_setMaxActiveVoiceCount"]=a0=>(_setMaxActiveVoiceCount=Module["_setMaxActiveVoiceCount"]=wasmExports["Ba"])(a0);var _fadeGlobalVolume=Module["_fadeGlobalVolume"]=(a0,a1)=>(_fadeGlobalVolume=Module["_fadeGlobalVolume"]=wasmExports["Ca"])(a0,a1);var _fadeVolume=Module["_fadeVolume"]=(a0,a1,a2)=>(_fadeVolume=Module["_fadeVolume"]=wasmExports["Da"])(a0,a1,a2);var _fadePan=Module["_fadePan"]=(a0,a1,a2)=>(_fadePan=Module["_fadePan"]=wasmExports["Ea"])(a0,a1,a2);var _fadeRelativePlaySpeed=Module["_fadeRelativePlaySpeed"]=(a0,a1,a2)=>(_fadeRelativePlaySpeed=Module["_fadeRelativePlaySpeed"]=wasmExports["Fa"])(a0,a1,a2);var _schedulePause=Module["_schedulePause"]=(a0,a1)=>(_schedulePause=Module["_schedulePause"]=wasmExports["Ga"])(a0,a1);var _scheduleStop=Module["_scheduleStop"]=(a0,a1)=>(_scheduleStop=Module["_scheduleStop"]=wasmExports["Ha"])(a0,a1);var _oscillateVolume=Module["_oscillateVolume"]=(a0,a1,a2,a3)=>(_oscillateVolume=Module["_oscillateVolume"]=wasmExports["Ia"])(a0,a1,a2,a3);var _oscillatePan=Module["_oscillatePan"]=(a0,a1,a2,a3)=>(_oscillatePan=Module["_oscillatePan"]=wasmExports["Ja"])(a0,a1,a2,a3);var _oscillateRelativePlaySpeed=Module["_oscillateRelativePlaySpeed"]=(a0,a1,a2,a3)=>(_oscillateRelativePlaySpeed=Module["_oscillateRelativePlaySpeed"]=wasmExports["Ka"])(a0,a1,a2,a3);var _oscillateGlobalVolume=Module["_oscillateGlobalVolume"]=(a0,a1,a2)=>(_oscillateGlobalVolume=Module["_oscillateGlobalVolume"]=wasmExports["La"])(a0,a1,a2);var _isFilterActive=Module["_isFilterActive"]=(a0,a1)=>(_isFilterActive=Module["_isFilterActive"]=wasmExports["Ma"])(a0,a1);var _getFilterParamNames=Module["_getFilterParamNames"]=(a0,a1,a2)=>(_getFilterParamNames=Module["_getFilterParamNames"]=wasmExports["Na"])(a0,a1,a2);var _addGlobalFilter=Module["_addGlobalFilter"]=a0=>(_addGlobalFilter=Module["_addGlobalFilter"]=wasmExports["Oa"])(a0);var _removeGlobalFilter=Module["_removeGlobalFilter"]=a0=>(_removeGlobalFilter=Module["_removeGlobalFilter"]=wasmExports["Pa"])(a0);var _setFxParams=Module["_setFxParams"]=(a0,a1,a2)=>(_setFxParams=Module["_setFxParams"]=wasmExports["Qa"])(a0,a1,a2);var _getFxParams=Module["_getFxParams"]=(a0,a1)=>(_getFxParams=Module["_getFxParams"]=wasmExports["Ra"])(a0,a1);var _play3d=Module["_play3d"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=>(_play3d=Module["_play3d"]=wasmExports["Sa"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11);var _set3dSoundSpeed=Module["_set3dSoundSpeed"]=a0=>(_set3dSoundSpeed=Module["_set3dSoundSpeed"]=wasmExports["Ta"])(a0);var _get3dSoundSpeed=Module["_get3dSoundSpeed"]=()=>(_get3dSoundSpeed=Module["_get3dSoundSpeed"]=wasmExports["Ua"])();var _set3dListenerParameters=Module["_set3dListenerParameters"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=>(_set3dListenerParameters=Module["_set3dListenerParameters"]=wasmExports["Va"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11);var _set3dListenerPosition=Module["_set3dListenerPosition"]=(a0,a1,a2)=>(_set3dListenerPosition=Module["_set3dListenerPosition"]=wasmExports["Wa"])(a0,a1,a2);var _set3dListenerAt=Module["_set3dListenerAt"]=(a0,a1,a2)=>(_set3dListenerAt=Module["_set3dListenerAt"]=wasmExports["Xa"])(a0,a1,a2);var _set3dListenerUp=Module["_set3dListenerUp"]=(a0,a1,a2)=>(_set3dListenerUp=Module["_set3dListenerUp"]=wasmExports["Ya"])(a0,a1,a2);var _set3dListenerVelocity=Module["_set3dListenerVelocity"]=(a0,a1,a2)=>(_set3dListenerVelocity=Module["_set3dListenerVelocity"]=wasmExports["Za"])(a0,a1,a2);var _set3dSourceParameters=Module["_set3dSourceParameters"]=(a0,a1,a2,a3,a4,a5,a6)=>(_set3dSourceParameters=Module["_set3dSourceParameters"]=wasmExports["_a"])(a0,a1,a2,a3,a4,a5,a6);var _set3dSourcePosition=Module["_set3dSourcePosition"]=(a0,a1,a2,a3)=>(_set3dSourcePosition=Module["_set3dSourcePosition"]=wasmExports["$a"])(a0,a1,a2,a3);var _set3dSourceVelocity=Module["_set3dSourceVelocity"]=(a0,a1,a2,a3)=>(_set3dSourceVelocity=Module["_set3dSourceVelocity"]=wasmExports["ab"])(a0,a1,a2,a3);var _set3dSourceMinMaxDistance=Module["_set3dSourceMinMaxDistance"]=(a0,a1,a2)=>(_set3dSourceMinMaxDistance=Module["_set3dSourceMinMaxDistance"]=wasmExports["bb"])(a0,a1,a2);var _set3dSourceAttenuation=Module["_set3dSourceAttenuation"]=(a0,a1,a2)=>(_set3dSourceAttenuation=Module["_set3dSourceAttenuation"]=wasmExports["cb"])(a0,a1,a2);var _set3dSourceDopplerFactor=Module["_set3dSourceDopplerFactor"]=(a0,a1)=>(_set3dSourceDopplerFactor=Module["_set3dSourceDopplerFactor"]=wasmExports["db"])(a0,a1);var _js_init=Module["_js_init"]=a0=>(_js_init=Module["_js_init"]=wasmExports["eb"])(a0);var _js_load=Module["_js_load"]=()=>(_js_load=Module["_js_load"]=wasmExports["fb"])();var _js_play=Module["_js_play"]=a0=>(_js_play=Module["_js_play"]=wasmExports["gb"])(a0);var _js_dispose=Module["_js_dispose"]=()=>(_js_dispose=Module["_js_dispose"]=wasmExports["hb"])();var _listCaptureDevices=Module["_listCaptureDevices"]=(a0,a1,a2)=>(_listCaptureDevices=Module["_listCaptureDevices"]=wasmExports["ib"])(a0,a1,a2);var _freeListCaptureDevices=Module["_freeListCaptureDevices"]=(a0,a1,a2)=>(_freeListCaptureDevices=Module["_freeListCaptureDevices"]=wasmExports["jb"])(a0,a1,a2);var _initCapture=Module["_initCapture"]=a0=>(_initCapture=Module["_initCapture"]=wasmExports["kb"])(a0);var _disposeCapture=Module["_disposeCapture"]=()=>(_disposeCapture=Module["_disposeCapture"]=wasmExports["lb"])();var _isCaptureInited=Module["_isCaptureInited"]=()=>(_isCaptureInited=Module["_isCaptureInited"]=wasmExports["mb"])();var _isCaptureStarted=Module["_isCaptureStarted"]=()=>(_isCaptureStarted=Module["_isCaptureStarted"]=wasmExports["nb"])();var _startCapture=Module["_startCapture"]=()=>(_startCapture=Module["_startCapture"]=wasmExports["ob"])();var _stopCapture=Module["_stopCapture"]=()=>(_stopCapture=Module["_stopCapture"]=wasmExports["pb"])();var _getCaptureFft=Module["_getCaptureFft"]=a0=>(_getCaptureFft=Module["_getCaptureFft"]=wasmExports["qb"])(a0);var _getCaptureWave=Module["_getCaptureWave"]=a0=>(_getCaptureWave=Module["_getCaptureWave"]=wasmExports["rb"])(a0);var _getCaptureTexture=Module["_getCaptureTexture"]=a0=>(_getCaptureTexture=Module["_getCaptureTexture"]=wasmExports["sb"])(a0);var _getCaptureAudioTexture2D=Module["_getCaptureAudioTexture2D"]=a0=>(_getCaptureAudioTexture2D=Module["_getCaptureAudioTexture2D"]=wasmExports["tb"])(a0);var _getCaptureTextureValue=Module["_getCaptureTextureValue"]=(a0,a1)=>(_getCaptureTextureValue=Module["_getCaptureTextureValue"]=wasmExports["ub"])(a0,a1);var _setCaptureFftSmoothing=Module["_setCaptureFftSmoothing"]=a0=>(_setCaptureFftSmoothing=Module["_setCaptureFftSmoothing"]=wasmExports["vb"])(a0);var _emscripten_get_sbrk_ptr=()=>(_emscripten_get_sbrk_ptr=wasmExports["wb"])();var _sbrk=a0=>(_sbrk=wasmExports["xb"])(a0);var _emscripten_stack_get_base=()=>(_emscripten_stack_get_base=wasmExports["yb"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["zb"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["Ab"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["Bb"])();var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["Cb"])(a0);var dynCall_iiiji=Module["dynCall_iiiji"]=(a0,a1,a2,a3,a4,a5)=>(dynCall_iiiji=Module["dynCall_iiiji"]=wasmExports["Db"])(a0,a1,a2,a3,a4,a5);var dynCall_jii=Module["dynCall_jii"]=(a0,a1,a2)=>(dynCall_jii=Module["dynCall_jii"]=wasmExports["Eb"])(a0,a1,a2);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["Fb"])(a0,a1,a2,a3,a4);Module["ccall"]=ccall;Module["cwrap"]=cwrap;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); +var Module=typeof Module!="undefined"?Module:{};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);if(typeof module!="undefined"){module["exports"]=Module}process.on("uncaughtException",ex=>{if(ex!=="unwind"&&!(ex instanceof ExitStatus)&&!(ex.context instanceof ExitStatus)){throw ex}});quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{if(isFileURI(url)){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null);return}fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))}).then(onload,onerror)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];function getSafeHeapType(bytes,isFloat){switch(bytes){case 1:return"i8";case 2:return"i16";case 4:return isFloat?"float":"i32";case 8:return isFloat?"double":"i64";default:abort(`getSafeHeapType() invalid bytes=${bytes}`)}}function SAFE_HEAP_STORE(dest,value,bytes,isFloat){if(dest<=0)abort(`segmentation fault storing ${bytes} bytes to address ${dest}`);if(dest%bytes!==0)abort(`alignment error storing to address ${dest}, which was expected to be aligned to a multiple of ${bytes}`);if(runtimeInitialized){var brk=_sbrk(0);if(dest+bytes>brk)abort(`segmentation fault, exceeded the top of the available dynamic heap when storing ${bytes} bytes to address ${dest}. DYNAMICTOP=${brk}`);if(brk<_emscripten_stack_get_base())abort(`brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`);if(brk>wasmMemory.buffer.byteLength)abort(`brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`)}setValue_safe(dest,value,getSafeHeapType(bytes,isFloat));return value}function SAFE_HEAP_STORE_D(dest,value,bytes){return SAFE_HEAP_STORE(dest,value,bytes,true)}function SAFE_HEAP_LOAD(dest,bytes,unsigned,isFloat){if(dest<=0)abort(`segmentation fault loading ${bytes} bytes from address ${dest}`);if(dest%bytes!==0)abort(`alignment error loading from address ${dest}, which was expected to be aligned to a multiple of ${bytes}`);if(runtimeInitialized){var brk=_sbrk(0);if(dest+bytes>brk)abort(`segmentation fault, exceeded the top of the available dynamic heap when loading ${bytes} bytes from address ${dest}. DYNAMICTOP=${brk}`);if(brk<_emscripten_stack_get_base())abort(`brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`);if(brk>wasmMemory.buffer.byteLength)abort(`brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`)}var type=getSafeHeapType(bytes,isFloat);var ret=getValue_safe(dest,type);if(unsigned)ret=unSign(ret,parseInt(type.substr(1),10));return ret}function SAFE_HEAP_LOAD_D(dest,bytes,unsigned){return SAFE_HEAP_LOAD(dest,bytes,unsigned,true)}function segfault(){abort("segmentation fault")}function alignfault(){abort("alignment fault")}var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="libflutter_soloud_plugin.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),error=>{try{resolve(getBinarySync(binaryFile))}catch(e){reject(e)}})})}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["q"];updateMemoryViews();addOnInit(wasmExports["r"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);return false}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult);return{}}var tempDouble;var tempI64;var ASM_CONSTS={67296:($0,$1,$2,$3,$4)=>{if(typeof window==="undefined"||(window.AudioContext||window.webkitAudioContext)===undefined){return 0}if(typeof window.miniaudio==="undefined"){window.miniaudio={referenceCount:0};window.miniaudio.device_type={};window.miniaudio.device_type.playback=$0;window.miniaudio.device_type.capture=$1;window.miniaudio.device_type.duplex=$2;window.miniaudio.device_state={};window.miniaudio.device_state.stopped=$3;window.miniaudio.device_state.started=$4;let miniaudio=window.miniaudio;miniaudio.devices=[];miniaudio.track_device=function(device){for(var iDevice=0;iDevice0){if(miniaudio.devices[miniaudio.devices.length-1]==null){miniaudio.devices.pop()}else{break}}};miniaudio.untrack_device=function(device){for(var iDevice=0;iDevice{_ma_device__on_notification_unlocked(device.pDevice)},error=>{console.error("Failed to resume audiocontext",error)})}}miniaudio.unlock_event_types.map(function(event_type){document.removeEventListener(event_type,miniaudio.unlock,true)})};miniaudio.unlock_event_types.map(function(event_type){document.addEventListener(event_type,miniaudio.unlock,true)})}window.miniaudio.referenceCount+=1;return 1},69474:()=>{if(typeof window.miniaudio!=="undefined"){miniaudio.unlock_event_types.map(function(event_type){document.removeEventListener(event_type,miniaudio.unlock,true)});window.miniaudio.referenceCount-=1;if(window.miniaudio.referenceCount===0){delete window.miniaudio}}},69764:()=>navigator.mediaDevices!==undefined&&navigator.mediaDevices.getUserMedia!==undefined,69868:()=>{try{var temp=new(window.AudioContext||window.webkitAudioContext);var sampleRate=temp.sampleRate;temp.close();return sampleRate}catch(e){return 0}},70039:($0,$1,$2,$3,$4,$5)=>{var deviceType=$0;var channels=$1;var sampleRate=$2;var bufferSize=$3;var pIntermediaryBuffer=$4;var pDevice=$5;if(typeof window.miniaudio==="undefined"){return-1}var device={};var audioContextOptions={};if(deviceType==window.miniaudio.device_type.playback&&sampleRate!=0){audioContextOptions.sampleRate=sampleRate}device.webaudio=new(window.AudioContext||window.webkitAudioContext)(audioContextOptions);device.webaudio.suspend();device.state=window.miniaudio.device_state.stopped;var channelCountIn=0;var channelCountOut=channels;if(deviceType!=window.miniaudio.device_type.playback){channelCountIn=channels}device.scriptNode=device.webaudio.createScriptProcessor(bufferSize,channelCountIn,channelCountOut);device.scriptNode.onaudioprocess=function(e){if(device.intermediaryBufferView==null||device.intermediaryBufferView.length==0){device.intermediaryBufferView=new Float32Array(HEAPF32.buffer,pIntermediaryBuffer,bufferSize*channels)}if(deviceType==window.miniaudio.device_type.capture||deviceType==window.miniaudio.device_type.duplex){for(var iChannel=0;iChannelwindow.miniaudio.get_device_by_index($0).webaudio.sampleRate,72989:$0=>{var device=window.miniaudio.get_device_by_index($0);if(device.scriptNode!==undefined){device.scriptNode.onaudioprocess=function(e){};device.scriptNode.disconnect();device.scriptNode=undefined}if(device.streamNode!==undefined){device.streamNode.disconnect();device.streamNode=undefined}device.webaudio.close();device.webaudio=undefined;device.pDevice=undefined},73389:$0=>{window.miniaudio.untrack_device_by_index($0)},73439:$0=>{var device=window.miniaudio.get_device_by_index($0);device.webaudio.resume();device.state=window.miniaudio.device_state.started},73578:$0=>{var device=window.miniaudio.get_device_by_index($0);device.webaudio.suspend();device.state=window.miniaudio.device_state.stopped},73718:()=>{if(!Module.wasmWorker){var workerUri="assets/packages/flutter_soloud/web/worker.dart.js";console.log("EM_ASM creating web worker!");Module.wasmWorker=new Worker(workerUri)}else{console.log("EM_ASM web worker already created!")}},73966:($0,$1)=>{if(Module.wasmWorker){console.log("EM_ASM posting message "+UTF8ToString($0)+" with value "+$1);Module.wasmWorker.postMessage(JSON.stringify({message:UTF8ToString($0),value:$1}))}else{console.error("Worker not found.")}}};function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}Module["ExitStatus"]=ExitStatus;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};Module["callRuntimeCallbacks"]=callRuntimeCallbacks;function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return SAFE_HEAP_LOAD(ptr,1,0);case"i8":return SAFE_HEAP_LOAD(ptr,1,0);case"i16":return SAFE_HEAP_LOAD((ptr>>1)*2,2,0);case"i32":return SAFE_HEAP_LOAD((ptr>>2)*4,4,0);case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return SAFE_HEAP_LOAD_D((ptr>>2)*4,4,0);case"double":return SAFE_HEAP_LOAD_D((ptr>>3)*8,8,0);case"*":return SAFE_HEAP_LOAD((ptr>>2)*4,4,1);default:abort(`invalid type for getValue: ${type}`)}}Module["getValue"]=getValue;function getValue_safe(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}Module["getValue_safe"]=getValue_safe;var noExitRuntime=Module["noExitRuntime"]||true;Module["noExitRuntime"]=noExitRuntime;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":SAFE_HEAP_STORE(ptr,value,1);break;case"i8":SAFE_HEAP_STORE(ptr,value,1);break;case"i16":SAFE_HEAP_STORE((ptr>>1)*2,value,2);break;case"i32":SAFE_HEAP_STORE((ptr>>2)*4,value,4);break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":SAFE_HEAP_STORE_D((ptr>>2)*4,value,4);break;case"double":SAFE_HEAP_STORE_D((ptr>>3)*8,value,8);break;case"*":SAFE_HEAP_STORE((ptr>>2)*4,value,4);break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue"]=setValue;function setValue_safe(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue_safe"]=setValue_safe;var stackRestore=val=>__emscripten_stack_restore(val);Module["stackRestore"]=stackRestore;var stackSave=()=>_emscripten_stack_get_current();Module["stackSave"]=stackSave;var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};Module["UTF8ArrayToString"]=UTF8ArrayToString;var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";Module["UTF8ToString"]=UTF8ToString;var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])};Module["___assert_fail"]=___assert_fail;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){SAFE_HEAP_STORE((this.ptr+4>>2)*4,type,4)}get_type(){return SAFE_HEAP_LOAD((this.ptr+4>>2)*4,4,1)}set_destructor(destructor){SAFE_HEAP_STORE((this.ptr+8>>2)*4,destructor,4)}get_destructor(){return SAFE_HEAP_LOAD((this.ptr+8>>2)*4,4,1)}set_caught(caught){caught=caught?1:0;SAFE_HEAP_STORE(this.ptr+12,caught,1)}get_caught(){return SAFE_HEAP_LOAD(this.ptr+12,1,0)!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;SAFE_HEAP_STORE(this.ptr+13,rethrown,1)}get_rethrown(){return SAFE_HEAP_LOAD(this.ptr+13,1,0)!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){SAFE_HEAP_STORE((this.ptr+16>>2)*4,adjustedPtr,4)}get_adjusted_ptr(){return SAFE_HEAP_LOAD((this.ptr+16>>2)*4,4,1)}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return SAFE_HEAP_LOAD((this.excPtr>>2)*4,4,1)}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}Module["ExceptionInfo"]=ExceptionInfo;var exceptionLast=0;Module["exceptionLast"]=exceptionLast;var uncaughtExceptionCount=0;Module["uncaughtExceptionCount"]=uncaughtExceptionCount;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};Module["___cxa_throw"]=___cxa_throw;function syscallGetVarargI(){var ret=SAFE_HEAP_LOAD((+SYSCALLS.varargs>>2)*4,4,0);SYSCALLS.varargs+=4;return ret}Module["syscallGetVarargI"]=syscallGetVarargI;var syscallGetVarargP=syscallGetVarargI;Module["syscallGetVarargP"]=syscallGetVarargP;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};Module["PATH"]=PATH;var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};Module["initRandomFill"]=initRandomFill;var randomFill=view=>(randomFill=initRandomFill())(view);Module["randomFill"]=randomFill;var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};Module["stringToUTF8Array"]=stringToUTF8Array;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};Module["FS_stdin_getChar"]=FS_stdin_getChar;var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};Module["TTY"]=TTY;var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};Module["zeroMemory"]=zeroMemory;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;Module["alignMemory"]=alignMemory;var mmapAlloc=size=>{abort()};Module["mmapAlloc"]=mmapAlloc;var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};Module["asyncLoad"]=asyncLoad;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};Module["FS_createDataFile"]=FS_createDataFile;var preloadPlugins=Module["preloadPlugins"]||[];Module["preloadPlugins"]=preloadPlugins;var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};Module["FS_createPreloadedFile"]=FS_createPreloadedFile;var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};Module["FS_modeStringToFlags"]=FS_modeStringToFlags;var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};Module["FS_getMode"]=FS_getMode;var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS:MEMFS}},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);SAFE_HEAP_STORE((buf>>2)*4,stat.dev,4);SAFE_HEAP_STORE((buf+4>>2)*4,stat.mode,4);SAFE_HEAP_STORE((buf+8>>2)*4,stat.nlink,4);SAFE_HEAP_STORE((buf+12>>2)*4,stat.uid,4);SAFE_HEAP_STORE((buf+16>>2)*4,stat.gid,4);SAFE_HEAP_STORE((buf+20>>2)*4,stat.rdev,4);tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+24>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+28>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+32>>2)*4,4096,4);SAFE_HEAP_STORE((buf+36>>2)*4,stat.blocks,4);var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+40>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+44>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+48>>2)*4,atime%1e3*1e3,4);tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+56>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+60>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+64>>2)*4,mtime%1e3*1e3,4);tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+72>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+76>>2)*4,tempI64[1],4);SAFE_HEAP_STORE((buf+80>>2)*4,ctime%1e3*1e3,4);tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((buf+88>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((buf+92>>2)*4,tempI64[1],4);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};Module["SYSCALLS"]=SYSCALLS;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;SAFE_HEAP_STORE((arg+offset>>1)*2,2,2);return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fcntl64"]=___syscall_fcntl64;function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>2)*4,termios.c_iflag||0,4);SAFE_HEAP_STORE((argp+4>>2)*4,termios.c_oflag||0,4);SAFE_HEAP_STORE((argp+8>>2)*4,termios.c_cflag||0,4);SAFE_HEAP_STORE((argp+12>>2)*4,termios.c_lflag||0,4);for(var i=0;i<32;i++){SAFE_HEAP_STORE(argp+i+17,termios.c_cc[i]||0,1)}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=SAFE_HEAP_LOAD((argp>>2)*4,4,0);var c_oflag=SAFE_HEAP_LOAD((argp+4>>2)*4,4,0);var c_cflag=SAFE_HEAP_LOAD((argp+8>>2)*4,4,0);var c_lflag=SAFE_HEAP_LOAD((argp+12>>2)*4,4,0);var c_cc=[];for(var i=0;i<32;i++){c_cc.push(SAFE_HEAP_LOAD(argp+i+17,1,0))}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>2)*4,0,4);return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();SAFE_HEAP_STORE((argp>>1)*2,winsize[0],2);SAFE_HEAP_STORE((argp+2>>1)*2,winsize[1],2)}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ioctl"]=___syscall_ioctl;function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_openat"]=___syscall_openat;var __abort_js=()=>{abort("")};Module["__abort_js"]=__abort_js;var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);Module["__emscripten_memcpy_js"]=__emscripten_memcpy_js;var readEmAsmArgsArray=[];Module["readEmAsmArgsArray"]=readEmAsmArgsArray;var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=SAFE_HEAP_LOAD(sigPtr++,1,1)){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?SAFE_HEAP_LOAD((buf>>2)*4,4,1):ch==105?SAFE_HEAP_LOAD((buf>>2)*4,4,0):SAFE_HEAP_LOAD_D((buf>>3)*8,8,0));buf+=wide?8:4}return readEmAsmArgsArray};Module["readEmAsmArgs"]=readEmAsmArgs;var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};Module["runEmAsmFunction"]=runEmAsmFunction;var _emscripten_asm_const_int=(code,sigPtr,argbuf)=>runEmAsmFunction(code,sigPtr,argbuf);Module["_emscripten_asm_const_int"]=_emscripten_asm_const_int;var getHeapMax=()=>2147483648;Module["getHeapMax"]=getHeapMax;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};Module["growMemory"]=growMemory;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};Module["_emscripten_resize_heap"]=_emscripten_resize_heap;function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_close"]=_fd_close;var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2)*4,4,1);var len=SAFE_HEAP_LOAD((iov+4>>2)*4,4,1);iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2)*4,num,4);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_read"]=_fd_read;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],SAFE_HEAP_STORE((newOffset>>2)*4,tempI64[0],4),SAFE_HEAP_STORE((newOffset+4>>2)*4,tempI64[1],4);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_seek"]=_fd_seek;var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2)*4,4,1);var len=SAFE_HEAP_LOAD((iov+4>>2)*4,4,1);iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!="undefined"){offset+=curr}}return ret};Module["doWritev"]=doWritev;function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);SAFE_HEAP_STORE((pnum>>2)*4,num,4);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_write"]=_fd_write;var _getentropy=(buffer,size)=>{randomFill(HEAPU8.subarray(buffer,buffer+size));return 0};Module["_getentropy"]=_getentropy;var getCFunc=ident=>{var func=Module["_"+ident];return func};Module["getCFunc"]=getCFunc;var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};Module["writeArrayToMemory"]=writeArrayToMemory;var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;var stackAlloc=sz=>__emscripten_stack_alloc(sz);Module["stackAlloc"]=stackAlloc;var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};Module["stringToUTF8OnStack"]=stringToUTF8OnStack;var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};Module["cwrap"]=cwrap;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();var wasmImports={a:___assert_fail,h:___cxa_throw,g:___syscall_fcntl64,j:___syscall_ioctl,k:___syscall_openat,o:__abort_js,l:__emscripten_memcpy_js,c:alignfault,d:_emscripten_asm_const_int,p:_emscripten_resize_heap,e:_fd_close,i:_fd_read,m:_fd_seek,f:_fd_write,n:_getentropy,b:segfault};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["r"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["t"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["u"])(a0);var _ma_device__on_notification_unlocked=Module["_ma_device__on_notification_unlocked"]=a0=>(_ma_device__on_notification_unlocked=Module["_ma_device__on_notification_unlocked"]=wasmExports["v"])(a0);var _ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=(a0,a1)=>(_ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=wasmExports["w"])(a0,a1);var _ma_free_emscripten=Module["_ma_free_emscripten"]=(a0,a1)=>(_ma_free_emscripten=Module["_ma_free_emscripten"]=wasmExports["x"])(a0,a1);var _ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=wasmExports["y"])(a0,a1,a2);var _ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=wasmExports["z"])(a0,a1,a2);var _createWorkerInWasm=Module["_createWorkerInWasm"]=()=>(_createWorkerInWasm=Module["_createWorkerInWasm"]=wasmExports["A"])();var _sendToWorker=Module["_sendToWorker"]=(a0,a1)=>(_sendToWorker=Module["_sendToWorker"]=wasmExports["B"])(a0,a1);var _nativeFree=Module["_nativeFree"]=a0=>(_nativeFree=Module["_nativeFree"]=wasmExports["C"])(a0);var _voiceEndedCallback=Module["_voiceEndedCallback"]=a0=>(_voiceEndedCallback=Module["_voiceEndedCallback"]=wasmExports["D"])(a0);var _setDartEventCallback=Module["_setDartEventCallback"]=(a0,a1,a2)=>(_setDartEventCallback=Module["_setDartEventCallback"]=wasmExports["E"])(a0,a1,a2);var _initEngine=Module["_initEngine"]=(a0,a1,a2)=>(_initEngine=Module["_initEngine"]=wasmExports["F"])(a0,a1,a2);var _dispose=Module["_dispose"]=()=>(_dispose=Module["_dispose"]=wasmExports["G"])();var _isInited=Module["_isInited"]=()=>(_isInited=Module["_isInited"]=wasmExports["H"])();var _loadFile=Module["_loadFile"]=(a0,a1)=>(_loadFile=Module["_loadFile"]=wasmExports["I"])(a0,a1);var _loadMem=Module["_loadMem"]=(a0,a1,a2,a3,a4)=>(_loadMem=Module["_loadMem"]=wasmExports["J"])(a0,a1,a2,a3,a4);var _loadWaveform=Module["_loadWaveform"]=(a0,a1,a2,a3,a4)=>(_loadWaveform=Module["_loadWaveform"]=wasmExports["K"])(a0,a1,a2,a3,a4);var _setWaveformScale=Module["_setWaveformScale"]=(a0,a1)=>(_setWaveformScale=Module["_setWaveformScale"]=wasmExports["L"])(a0,a1);var _setWaveformDetune=Module["_setWaveformDetune"]=(a0,a1)=>(_setWaveformDetune=Module["_setWaveformDetune"]=wasmExports["M"])(a0,a1);var _setWaveformFreq=Module["_setWaveformFreq"]=(a0,a1)=>(_setWaveformFreq=Module["_setWaveformFreq"]=wasmExports["N"])(a0,a1);var _setSuperWave=Module["_setSuperWave"]=(a0,a1)=>(_setSuperWave=Module["_setSuperWave"]=wasmExports["O"])(a0,a1);var _setWaveform=Module["_setWaveform"]=(a0,a1)=>(_setWaveform=Module["_setWaveform"]=wasmExports["P"])(a0,a1);var _speechText=Module["_speechText"]=(a0,a1)=>(_speechText=Module["_speechText"]=wasmExports["Q"])(a0,a1);var _pauseSwitch=Module["_pauseSwitch"]=a0=>(_pauseSwitch=Module["_pauseSwitch"]=wasmExports["R"])(a0);var _setPause=Module["_setPause"]=(a0,a1)=>(_setPause=Module["_setPause"]=wasmExports["S"])(a0,a1);var _getPause=Module["_getPause"]=a0=>(_getPause=Module["_getPause"]=wasmExports["T"])(a0);var _setRelativePlaySpeed=Module["_setRelativePlaySpeed"]=(a0,a1)=>(_setRelativePlaySpeed=Module["_setRelativePlaySpeed"]=wasmExports["U"])(a0,a1);var _getRelativePlaySpeed=Module["_getRelativePlaySpeed"]=a0=>(_getRelativePlaySpeed=Module["_getRelativePlaySpeed"]=wasmExports["V"])(a0);var _play=Module["_play"]=(a0,a1,a2,a3,a4,a5,a6)=>(_play=Module["_play"]=wasmExports["W"])(a0,a1,a2,a3,a4,a5,a6);var _stop=Module["_stop"]=a0=>(_stop=Module["_stop"]=wasmExports["X"])(a0);var _disposeSound=Module["_disposeSound"]=a0=>(_disposeSound=Module["_disposeSound"]=wasmExports["Y"])(a0);var _disposeAllSound=Module["_disposeAllSound"]=()=>(_disposeAllSound=Module["_disposeAllSound"]=wasmExports["Z"])();var _getLooping=Module["_getLooping"]=a0=>(_getLooping=Module["_getLooping"]=wasmExports["_"])(a0);var _setLooping=Module["_setLooping"]=(a0,a1)=>(_setLooping=Module["_setLooping"]=wasmExports["$"])(a0,a1);var _getLoopPoint=Module["_getLoopPoint"]=a0=>(_getLoopPoint=Module["_getLoopPoint"]=wasmExports["aa"])(a0);var _setLoopPoint=Module["_setLoopPoint"]=(a0,a1)=>(_setLoopPoint=Module["_setLoopPoint"]=wasmExports["ba"])(a0,a1);var _setVisualizationEnabled=Module["_setVisualizationEnabled"]=a0=>(_setVisualizationEnabled=Module["_setVisualizationEnabled"]=wasmExports["ca"])(a0);var _getVisualizationEnabled=Module["_getVisualizationEnabled"]=()=>(_getVisualizationEnabled=Module["_getVisualizationEnabled"]=wasmExports["da"])();var _getFft=Module["_getFft"]=a0=>(_getFft=Module["_getFft"]=wasmExports["ea"])(a0);var _getWave=Module["_getWave"]=a0=>(_getWave=Module["_getWave"]=wasmExports["fa"])(a0);var _setFftSmoothing=Module["_setFftSmoothing"]=a0=>(_setFftSmoothing=Module["_setFftSmoothing"]=wasmExports["ga"])(a0);var _getAudioTexture=Module["_getAudioTexture"]=a0=>(_getAudioTexture=Module["_getAudioTexture"]=wasmExports["ha"])(a0);var _getAudioTexture2D=Module["_getAudioTexture2D"]=a0=>(_getAudioTexture2D=Module["_getAudioTexture2D"]=wasmExports["ia"])(a0);var _getTextureValue=Module["_getTextureValue"]=(a0,a1)=>(_getTextureValue=Module["_getTextureValue"]=wasmExports["ja"])(a0,a1);var _getLength=Module["_getLength"]=a0=>(_getLength=Module["_getLength"]=wasmExports["ka"])(a0);var _seek=Module["_seek"]=(a0,a1)=>(_seek=Module["_seek"]=wasmExports["la"])(a0,a1);var _getPosition=Module["_getPosition"]=a0=>(_getPosition=Module["_getPosition"]=wasmExports["ma"])(a0);var _getGlobalVolume=Module["_getGlobalVolume"]=()=>(_getGlobalVolume=Module["_getGlobalVolume"]=wasmExports["na"])();var _setGlobalVolume=Module["_setGlobalVolume"]=a0=>(_setGlobalVolume=Module["_setGlobalVolume"]=wasmExports["oa"])(a0);var _getVolume=Module["_getVolume"]=a0=>(_getVolume=Module["_getVolume"]=wasmExports["pa"])(a0);var _setVolume=Module["_setVolume"]=(a0,a1)=>(_setVolume=Module["_setVolume"]=wasmExports["qa"])(a0,a1);var _getPan=Module["_getPan"]=a0=>(_getPan=Module["_getPan"]=wasmExports["ra"])(a0);var _setPan=Module["_setPan"]=(a0,a1)=>(_setPan=Module["_setPan"]=wasmExports["sa"])(a0,a1);var _setPanAbsolute=Module["_setPanAbsolute"]=(a0,a1,a2)=>(_setPanAbsolute=Module["_setPanAbsolute"]=wasmExports["ta"])(a0,a1,a2);var _getIsValidVoiceHandle=Module["_getIsValidVoiceHandle"]=a0=>(_getIsValidVoiceHandle=Module["_getIsValidVoiceHandle"]=wasmExports["ua"])(a0);var _getActiveVoiceCount=Module["_getActiveVoiceCount"]=()=>(_getActiveVoiceCount=Module["_getActiveVoiceCount"]=wasmExports["va"])();var _countAudioSource=Module["_countAudioSource"]=a0=>(_countAudioSource=Module["_countAudioSource"]=wasmExports["wa"])(a0);var _getVoiceCount=Module["_getVoiceCount"]=()=>(_getVoiceCount=Module["_getVoiceCount"]=wasmExports["xa"])();var _getProtectVoice=Module["_getProtectVoice"]=a0=>(_getProtectVoice=Module["_getProtectVoice"]=wasmExports["ya"])(a0);var _setProtectVoice=Module["_setProtectVoice"]=(a0,a1)=>(_setProtectVoice=Module["_setProtectVoice"]=wasmExports["za"])(a0,a1);var _getMaxActiveVoiceCount=Module["_getMaxActiveVoiceCount"]=()=>(_getMaxActiveVoiceCount=Module["_getMaxActiveVoiceCount"]=wasmExports["Aa"])();var _setMaxActiveVoiceCount=Module["_setMaxActiveVoiceCount"]=a0=>(_setMaxActiveVoiceCount=Module["_setMaxActiveVoiceCount"]=wasmExports["Ba"])(a0);var _createVoiceGroup=Module["_createVoiceGroup"]=()=>(_createVoiceGroup=Module["_createVoiceGroup"]=wasmExports["Ca"])();var _destroyVoiceGroup=Module["_destroyVoiceGroup"]=a0=>(_destroyVoiceGroup=Module["_destroyVoiceGroup"]=wasmExports["Da"])(a0);var _addVoiceToGroup=Module["_addVoiceToGroup"]=(a0,a1)=>(_addVoiceToGroup=Module["_addVoiceToGroup"]=wasmExports["Ea"])(a0,a1);var _isVoiceGroup=Module["_isVoiceGroup"]=a0=>(_isVoiceGroup=Module["_isVoiceGroup"]=wasmExports["Fa"])(a0);var _isVoiceGroupEmpty=Module["_isVoiceGroupEmpty"]=a0=>(_isVoiceGroupEmpty=Module["_isVoiceGroupEmpty"]=wasmExports["Ga"])(a0);var _fadeGlobalVolume=Module["_fadeGlobalVolume"]=(a0,a1)=>(_fadeGlobalVolume=Module["_fadeGlobalVolume"]=wasmExports["Ha"])(a0,a1);var _fadeVolume=Module["_fadeVolume"]=(a0,a1,a2)=>(_fadeVolume=Module["_fadeVolume"]=wasmExports["Ia"])(a0,a1,a2);var _fadePan=Module["_fadePan"]=(a0,a1,a2)=>(_fadePan=Module["_fadePan"]=wasmExports["Ja"])(a0,a1,a2);var _fadeRelativePlaySpeed=Module["_fadeRelativePlaySpeed"]=(a0,a1,a2)=>(_fadeRelativePlaySpeed=Module["_fadeRelativePlaySpeed"]=wasmExports["Ka"])(a0,a1,a2);var _schedulePause=Module["_schedulePause"]=(a0,a1)=>(_schedulePause=Module["_schedulePause"]=wasmExports["La"])(a0,a1);var _scheduleStop=Module["_scheduleStop"]=(a0,a1)=>(_scheduleStop=Module["_scheduleStop"]=wasmExports["Ma"])(a0,a1);var _oscillateVolume=Module["_oscillateVolume"]=(a0,a1,a2,a3)=>(_oscillateVolume=Module["_oscillateVolume"]=wasmExports["Na"])(a0,a1,a2,a3);var _oscillatePan=Module["_oscillatePan"]=(a0,a1,a2,a3)=>(_oscillatePan=Module["_oscillatePan"]=wasmExports["Oa"])(a0,a1,a2,a3);var _oscillateRelativePlaySpeed=Module["_oscillateRelativePlaySpeed"]=(a0,a1,a2,a3)=>(_oscillateRelativePlaySpeed=Module["_oscillateRelativePlaySpeed"]=wasmExports["Pa"])(a0,a1,a2,a3);var _oscillateGlobalVolume=Module["_oscillateGlobalVolume"]=(a0,a1,a2)=>(_oscillateGlobalVolume=Module["_oscillateGlobalVolume"]=wasmExports["Qa"])(a0,a1,a2);var _isFilterActive=Module["_isFilterActive"]=(a0,a1,a2)=>(_isFilterActive=Module["_isFilterActive"]=wasmExports["Ra"])(a0,a1,a2);var _getFilterParamNames=Module["_getFilterParamNames"]=(a0,a1,a2)=>(_getFilterParamNames=Module["_getFilterParamNames"]=wasmExports["Sa"])(a0,a1,a2);var _addFilter=Module["_addFilter"]=(a0,a1)=>(_addFilter=Module["_addFilter"]=wasmExports["Ta"])(a0,a1);var _removeFilter=Module["_removeFilter"]=(a0,a1)=>(_removeFilter=Module["_removeFilter"]=wasmExports["Ua"])(a0,a1);var _setFilterParams=Module["_setFilterParams"]=(a0,a1,a2,a3)=>(_setFilterParams=Module["_setFilterParams"]=wasmExports["Va"])(a0,a1,a2,a3);var _getFilterParams=Module["_getFilterParams"]=(a0,a1,a2,a3)=>(_getFilterParams=Module["_getFilterParams"]=wasmExports["Wa"])(a0,a1,a2,a3);var _fadeFilterParameter=Module["_fadeFilterParameter"]=(a0,a1,a2,a3,a4)=>(_fadeFilterParameter=Module["_fadeFilterParameter"]=wasmExports["Xa"])(a0,a1,a2,a3,a4);var _oscillateFilterParameter=Module["_oscillateFilterParameter"]=(a0,a1,a2,a3,a4,a5)=>(_oscillateFilterParameter=Module["_oscillateFilterParameter"]=wasmExports["Ya"])(a0,a1,a2,a3,a4,a5);var _play3d=Module["_play3d"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=>(_play3d=Module["_play3d"]=wasmExports["Za"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11);var _set3dSoundSpeed=Module["_set3dSoundSpeed"]=a0=>(_set3dSoundSpeed=Module["_set3dSoundSpeed"]=wasmExports["_a"])(a0);var _get3dSoundSpeed=Module["_get3dSoundSpeed"]=()=>(_get3dSoundSpeed=Module["_get3dSoundSpeed"]=wasmExports["$a"])();var _set3dListenerParameters=Module["_set3dListenerParameters"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=>(_set3dListenerParameters=Module["_set3dListenerParameters"]=wasmExports["ab"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11);var _set3dListenerPosition=Module["_set3dListenerPosition"]=(a0,a1,a2)=>(_set3dListenerPosition=Module["_set3dListenerPosition"]=wasmExports["bb"])(a0,a1,a2);var _set3dListenerAt=Module["_set3dListenerAt"]=(a0,a1,a2)=>(_set3dListenerAt=Module["_set3dListenerAt"]=wasmExports["cb"])(a0,a1,a2);var _set3dListenerUp=Module["_set3dListenerUp"]=(a0,a1,a2)=>(_set3dListenerUp=Module["_set3dListenerUp"]=wasmExports["db"])(a0,a1,a2);var _set3dListenerVelocity=Module["_set3dListenerVelocity"]=(a0,a1,a2)=>(_set3dListenerVelocity=Module["_set3dListenerVelocity"]=wasmExports["eb"])(a0,a1,a2);var _set3dSourceParameters=Module["_set3dSourceParameters"]=(a0,a1,a2,a3,a4,a5,a6)=>(_set3dSourceParameters=Module["_set3dSourceParameters"]=wasmExports["fb"])(a0,a1,a2,a3,a4,a5,a6);var _set3dSourcePosition=Module["_set3dSourcePosition"]=(a0,a1,a2,a3)=>(_set3dSourcePosition=Module["_set3dSourcePosition"]=wasmExports["gb"])(a0,a1,a2,a3);var _set3dSourceVelocity=Module["_set3dSourceVelocity"]=(a0,a1,a2,a3)=>(_set3dSourceVelocity=Module["_set3dSourceVelocity"]=wasmExports["hb"])(a0,a1,a2,a3);var _set3dSourceMinMaxDistance=Module["_set3dSourceMinMaxDistance"]=(a0,a1,a2)=>(_set3dSourceMinMaxDistance=Module["_set3dSourceMinMaxDistance"]=wasmExports["ib"])(a0,a1,a2);var _set3dSourceAttenuation=Module["_set3dSourceAttenuation"]=(a0,a1,a2)=>(_set3dSourceAttenuation=Module["_set3dSourceAttenuation"]=wasmExports["jb"])(a0,a1,a2);var _set3dSourceDopplerFactor=Module["_set3dSourceDopplerFactor"]=(a0,a1)=>(_set3dSourceDopplerFactor=Module["_set3dSourceDopplerFactor"]=wasmExports["kb"])(a0,a1);var _listCaptureDevices=Module["_listCaptureDevices"]=(a0,a1,a2)=>(_listCaptureDevices=Module["_listCaptureDevices"]=wasmExports["lb"])(a0,a1,a2);var _freeListCaptureDevices=Module["_freeListCaptureDevices"]=(a0,a1,a2)=>(_freeListCaptureDevices=Module["_freeListCaptureDevices"]=wasmExports["mb"])(a0,a1,a2);var _initCapture=Module["_initCapture"]=a0=>(_initCapture=Module["_initCapture"]=wasmExports["nb"])(a0);var _disposeCapture=Module["_disposeCapture"]=()=>(_disposeCapture=Module["_disposeCapture"]=wasmExports["ob"])();var _isCaptureInited=Module["_isCaptureInited"]=()=>(_isCaptureInited=Module["_isCaptureInited"]=wasmExports["pb"])();var _isCaptureStarted=Module["_isCaptureStarted"]=()=>(_isCaptureStarted=Module["_isCaptureStarted"]=wasmExports["qb"])();var _startCapture=Module["_startCapture"]=()=>(_startCapture=Module["_startCapture"]=wasmExports["rb"])();var _stopCapture=Module["_stopCapture"]=()=>(_stopCapture=Module["_stopCapture"]=wasmExports["sb"])();var _getCaptureFft=Module["_getCaptureFft"]=a0=>(_getCaptureFft=Module["_getCaptureFft"]=wasmExports["tb"])(a0);var _getCaptureWave=Module["_getCaptureWave"]=a0=>(_getCaptureWave=Module["_getCaptureWave"]=wasmExports["ub"])(a0);var _getCaptureTexture=Module["_getCaptureTexture"]=a0=>(_getCaptureTexture=Module["_getCaptureTexture"]=wasmExports["vb"])(a0);var _getCaptureAudioTexture2D=Module["_getCaptureAudioTexture2D"]=a0=>(_getCaptureAudioTexture2D=Module["_getCaptureAudioTexture2D"]=wasmExports["wb"])(a0);var _getCaptureTextureValue=Module["_getCaptureTextureValue"]=(a0,a1)=>(_getCaptureTextureValue=Module["_getCaptureTextureValue"]=wasmExports["xb"])(a0,a1);var _setCaptureFftSmoothing=Module["_setCaptureFftSmoothing"]=a0=>(_setCaptureFftSmoothing=Module["_setCaptureFftSmoothing"]=wasmExports["yb"])(a0);var _emscripten_get_sbrk_ptr=()=>(_emscripten_get_sbrk_ptr=wasmExports["zb"])();var _sbrk=a0=>(_sbrk=wasmExports["Ab"])(a0);var _emscripten_stack_get_base=()=>(_emscripten_stack_get_base=wasmExports["Bb"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["Cb"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["Db"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["Eb"])();var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["Fb"])(a0);var dynCall_iiiji=Module["dynCall_iiiji"]=(a0,a1,a2,a3,a4,a5)=>(dynCall_iiiji=Module["dynCall_iiiji"]=wasmExports["Gb"])(a0,a1,a2,a3,a4,a5);var dynCall_jii=Module["dynCall_jii"]=(a0,a1,a2)=>(dynCall_jii=Module["dynCall_jii"]=wasmExports["Hb"])(a0,a1,a2);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["Ib"])(a0,a1,a2,a3,a4);Module["ccall"]=ccall;Module["cwrap"]=cwrap;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); diff --git a/web/libflutter_soloud_plugin.wasm b/web/libflutter_soloud_plugin.wasm index 241c595..94b3654 100755 Binary files a/web/libflutter_soloud_plugin.wasm and b/web/libflutter_soloud_plugin.wasm differ