From eabc4f432dacf9437565fe7e503aae3b589c6206 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Fri, 16 Jun 2023 23:46:18 +0530 Subject: [PATCH 01/37] Use shared library and dependency injection --- meson.build | 30 +- src/Application.vala | 39 +- src/Core/Analysers/ChordAnalyser.vala | 318 -------- src/Core/Analysers/StyleAnalyser.vala | 265 ------- src/Core/Analysers/VoiceAnalyser.vala | 85 --- src/Core/ArrangerWorkstation.vala | 243 ------ src/Core/AudioEngine/SynthProvider.vala | 235 ------ .../AudioEngine/SynthSettingsPresets.vala | 141 ---- src/Core/AudioEngine/Synthesizer.vala | 341 --------- src/Core/Automators/Arperggiator.vala | 0 src/Core/Automators/Harmonizer.vala | 0 src/Core/Drivers/AudioDriverSniffer.vala | 0 src/Core/Drivers/MIDIInputHost.vala | 0 src/Core/FileLoaders/StyleFileLoader.vala | 82 --- src/Core/MIDIPlayers/MetronomeLFOPlayer.vala | 0 src/Core/MIDIPlayers/SongPlayer.vala | 0 src/Core/MIDIPlayers/StyleEngine.vala | 689 ------------------ .../Plugins/AudioPlugins/AudioPlugin.vala | 79 -- .../Plugins/AudioPlugins/Lv2/LV2EvBuf.vala | 253 ------- .../Plugins/AudioPlugins/Lv2/LV2Manager.vala | 113 --- .../Plugins/AudioPlugins/Lv2/LV2Plugin.vala | 525 ------------- .../AudioPlugins/Lv2/LV2PortAnalyser.vala | 279 ------- .../Plugins/AudioPlugins/Lv2/LV2SyMap.vala | 61 -- .../Plugins/AudioPlugins/Lv2/LV2Worker.vala | 217 ------ .../AudioPlugins/Lv2/Ports/LV2AtomPort.vala | 23 - .../Lv2/Ports/LV2ControlPort.vala | 23 - .../AudioPlugins/Lv2/Ports/LV2Port.vala | 19 - src/Core/Plugins/AudioPlugins/Port.vala | 16 - src/Core/Plugins/Plugin.vala | 91 --- src/Core/Plugins/PluginManager.vala | 41 -- src/Core/Racks/DSPRack.vala | 25 - src/Core/Racks/Rack.vala | 194 ----- src/Core/Racks/VoiceRack.vala | 62 -- src/Core/SamplingPads/SamplePlayer.vala | 0 src/Core/SamplingPads/SampleRecorder.vala | 0 src/Core/StateManager/RegistryManager.vala | 0 src/Interfaces/MediaKeyListener.vala | 0 src/Interfaces/SoundIndicator.vala | 0 src/Models/Chord.vala | 51 -- src/Models/Registry.vala | 30 - src/Models/Style.vala | 85 --- src/Models/StylePart.vala | 31 - src/Models/Voice.vala | 33 - src/Services/EventBus.vala | 49 -- src/Services/Theme.vala | 65 -- src/{Services => }/Settings.vala | 44 +- src/Shell/Dialogs/PluginWindow.vala | 0 src/Shell/Dialogs/PowerDialog.vala | 91 --- src/Shell/Layouts/AssignablesBoard.vala | 19 - src/Shell/Layouts/DesktopLayout.vala | 126 ---- .../Layouts/Display/AudioPluginPicker.vala | 72 -- src/Shell/Layouts/Display/DSPScreen.vala | 130 ---- src/Shell/Layouts/Display/HomeScreen.vala | 341 --------- src/Shell/Layouts/Display/PluginScreen.vala | 89 --- src/Shell/Layouts/Display/StyleScreen.vala | 101 --- src/Shell/Layouts/Display/VoiceScreen.vala | 147 ---- src/Shell/Layouts/InfoDisplay.vala | 178 ----- src/Shell/Layouts/KeyboardPanel.vala | 84 --- src/Shell/Layouts/KioskLayout.vala | 32 - src/Shell/Layouts/MixerBoard.vala | 12 - src/Shell/Layouts/MobileLayout.vala | 175 ----- src/Shell/Layouts/PluginView.vala | 15 - src/Shell/Layouts/RegistryPanel.vala | 12 - src/Shell/Layouts/SamplerPadsPanel.vala | 12 - src/Shell/Layouts/StyleControlPanel.vala | 591 --------------- src/Shell/Layouts/SynthControlPanel.vala | 19 - src/Shell/Layouts/VoiceNavPanel.vala | 12 - src/Shell/MainWindow.vala | 199 ----- .../Widgets/AudioPluginControl.vala | 113 --- src/Shell/Widgets/BeatVisualization.vala | 101 --- .../Widgets/Display/DSPInstanceMenuItem.vala | 129 ---- src/Shell/Widgets/Display/DSPMenuItem.vala | 112 --- src/Shell/Widgets/Display/DisplayWindow.vala | 129 ---- src/Shell/Widgets/Display/StyleMenuItem.vala | 66 -- src/Shell/Widgets/Display/VoiceMenuItem.vala | 108 --- .../Display/WheelScrollableWidget.vala | 39 - src/Shell/Widgets/Key.vala | 78 -- src/Shell/Widgets/Keyboard.vala | 197 ----- src/Shell/Widgets/Knob.vala | 368 ---------- src/Shell/Widgets/Octave.vala | 142 ---- src/Utils/AccentColors.vala | 90 --- src/Utils/Console.vala | 84 --- src/Utils/DisplayTheme.vala | 79 -- src/Utils/ErrorDomains.vala | 20 - src/Utils/MIDI.vala | 85 --- src/Utils/Math.vala | 52 -- src/Utils/StyleMIDIModifiers.vala | 242 ------ src/meson.build | 101 +-- subprojects/ens-aw-core | 1 + subprojects/ens-aw-core.wrap | 4 + subprojects/zix.wrap | 4 - 91 files changed, 60 insertions(+), 9618 deletions(-) delete mode 100644 src/Core/Analysers/ChordAnalyser.vala delete mode 100644 src/Core/Analysers/StyleAnalyser.vala delete mode 100644 src/Core/Analysers/VoiceAnalyser.vala delete mode 100644 src/Core/ArrangerWorkstation.vala delete mode 100644 src/Core/AudioEngine/SynthProvider.vala delete mode 100644 src/Core/AudioEngine/SynthSettingsPresets.vala delete mode 100644 src/Core/AudioEngine/Synthesizer.vala delete mode 100644 src/Core/Automators/Arperggiator.vala delete mode 100644 src/Core/Automators/Harmonizer.vala delete mode 100644 src/Core/Drivers/AudioDriverSniffer.vala delete mode 100644 src/Core/Drivers/MIDIInputHost.vala delete mode 100644 src/Core/FileLoaders/StyleFileLoader.vala delete mode 100644 src/Core/MIDIPlayers/MetronomeLFOPlayer.vala delete mode 100644 src/Core/MIDIPlayers/SongPlayer.vala delete mode 100644 src/Core/MIDIPlayers/StyleEngine.vala delete mode 100644 src/Core/Plugins/AudioPlugins/AudioPlugin.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2EvBuf.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2Manager.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2Plugin.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2PortAnalyser.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2SyMap.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/LV2Worker.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2AtomPort.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2ControlPort.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2Port.vala delete mode 100644 src/Core/Plugins/AudioPlugins/Port.vala delete mode 100644 src/Core/Plugins/Plugin.vala delete mode 100644 src/Core/Plugins/PluginManager.vala delete mode 100644 src/Core/Racks/DSPRack.vala delete mode 100644 src/Core/Racks/Rack.vala delete mode 100644 src/Core/Racks/VoiceRack.vala delete mode 100644 src/Core/SamplingPads/SamplePlayer.vala delete mode 100644 src/Core/SamplingPads/SampleRecorder.vala delete mode 100644 src/Core/StateManager/RegistryManager.vala delete mode 100644 src/Interfaces/MediaKeyListener.vala delete mode 100644 src/Interfaces/SoundIndicator.vala delete mode 100644 src/Models/Chord.vala delete mode 100644 src/Models/Registry.vala delete mode 100644 src/Models/Style.vala delete mode 100644 src/Models/StylePart.vala delete mode 100644 src/Models/Voice.vala delete mode 100644 src/Services/EventBus.vala delete mode 100644 src/Services/Theme.vala rename src/{Services => }/Settings.vala (69%) delete mode 100644 src/Shell/Dialogs/PluginWindow.vala delete mode 100644 src/Shell/Dialogs/PowerDialog.vala delete mode 100644 src/Shell/Layouts/AssignablesBoard.vala delete mode 100644 src/Shell/Layouts/DesktopLayout.vala delete mode 100644 src/Shell/Layouts/Display/AudioPluginPicker.vala delete mode 100644 src/Shell/Layouts/Display/DSPScreen.vala delete mode 100644 src/Shell/Layouts/Display/HomeScreen.vala delete mode 100644 src/Shell/Layouts/Display/PluginScreen.vala delete mode 100644 src/Shell/Layouts/Display/StyleScreen.vala delete mode 100644 src/Shell/Layouts/Display/VoiceScreen.vala delete mode 100644 src/Shell/Layouts/InfoDisplay.vala delete mode 100644 src/Shell/Layouts/KeyboardPanel.vala delete mode 100644 src/Shell/Layouts/KioskLayout.vala delete mode 100644 src/Shell/Layouts/MixerBoard.vala delete mode 100644 src/Shell/Layouts/MobileLayout.vala delete mode 100644 src/Shell/Layouts/PluginView.vala delete mode 100644 src/Shell/Layouts/RegistryPanel.vala delete mode 100644 src/Shell/Layouts/SamplerPadsPanel.vala delete mode 100644 src/Shell/Layouts/StyleControlPanel.vala delete mode 100644 src/Shell/Layouts/SynthControlPanel.vala delete mode 100644 src/Shell/Layouts/VoiceNavPanel.vala delete mode 100644 src/Shell/MainWindow.vala delete mode 100644 src/Shell/Plugins/AudioPlugins/Widgets/AudioPluginControl.vala delete mode 100644 src/Shell/Widgets/BeatVisualization.vala delete mode 100644 src/Shell/Widgets/Display/DSPInstanceMenuItem.vala delete mode 100644 src/Shell/Widgets/Display/DSPMenuItem.vala delete mode 100644 src/Shell/Widgets/Display/DisplayWindow.vala delete mode 100644 src/Shell/Widgets/Display/StyleMenuItem.vala delete mode 100644 src/Shell/Widgets/Display/VoiceMenuItem.vala delete mode 100644 src/Shell/Widgets/Display/WheelScrollableWidget.vala delete mode 100644 src/Shell/Widgets/Key.vala delete mode 100644 src/Shell/Widgets/Keyboard.vala delete mode 100644 src/Shell/Widgets/Knob.vala delete mode 100644 src/Shell/Widgets/Octave.vala delete mode 100644 src/Utils/AccentColors.vala delete mode 100644 src/Utils/Console.vala delete mode 100644 src/Utils/DisplayTheme.vala delete mode 100644 src/Utils/ErrorDomains.vala delete mode 100644 src/Utils/MIDI.vala delete mode 100644 src/Utils/Math.vala delete mode 100644 src/Utils/StyleMIDIModifiers.vala create mode 160000 subprojects/ens-aw-core create mode 100644 subprojects/ens-aw-core.wrap delete mode 100644 subprojects/zix.wrap diff --git a/meson.build b/meson.build index b1e90a00..aeb82f2b 100644 --- a/meson.build +++ b/meson.build @@ -5,8 +5,7 @@ project ( version: '0.1.0', meson_version: '>=0.57.0', default_options: [ - 'buildtype=debugoptimized', - 'wrap_mode=nofallback' + 'buildtype=debugoptimized' ] ) @@ -30,11 +29,6 @@ add_project_arguments ( add_project_arguments ( ['--vapidir', join_paths (meson.current_source_dir (), 'vapi')], - # Set Driver Compatibilities - '-D', 'ALSA_DRIVER', - '-D', 'PULSEAUDIO_DRIVER', - '-D', 'JACK_DRIVER', - # '-D', 'PIPEWIRE_CORE_DRIVER', # Uncomment to enable pipewire core support provided fluidsynth supports it language: 'vala' ) @@ -46,29 +40,15 @@ asresources = gnome.compile_resources ( c_name: 'as' ) +build_dir = meson.current_build_dir() +message(build_dir.split('/')[-1]) + # Listing dependencies dependencies = [ dependency ('x11'), - dependency ('granite-7'), - dependency ('libadwaita-1'), dependency ('gtk4'), dependency ('glib-2.0'), - dependency ('gobject-2.0'), - dependency ('libsoup-3.0'), - dependency ('json-glib-1.0'), - dependency ('fluidsynth'), - dependency ('gstreamer-1.0'), - dependency ('lv2'), - dependency ('lilv-0'), - dependency ('suil-0'), - dependency ('zix-0', fallback: ['zix', 'zix_dep'], default_options: [ - 'tests=disabled', 'default_library=static', - 'docs=disabled', 'tests_cpp=disabled', - ]), - dependency ('libpipewire-0.3'), - meson.get_compiler ('vala').find_library ('posix'), - meson.get_compiler ('c').find_library ('m', required : true), - meson.get_compiler ('c').find_library ('X11', required : true), + dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']) ] # Set up the profile diff --git a/src/Application.vala b/src/Application.vala index 3fb63493..56c0f1fd 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -3,9 +3,9 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -namespace Ensembles { - public Services.Settings settings; +using Ensembles.ArrangerWorkstation; +namespace Ensembles { /** * ## Ensembles Application * @@ -27,41 +27,44 @@ namespace Ensembles { } } - public static Services.EventBus event_bus = new Services.EventBus (); + // public static Services.EventBus event_bus = new Services.EventBus (); private string[] ? arg_file = null; public static bool raw_midi_input = false; public static bool kiosk_mode = false; public static bool verbose = false; - public static Shell.MainWindow main_window; - public static Core.ArrangerWorkstation arranger_workstation; + // public static Shell.MainWindow main_window; + // public static Core.ArrangerWorkstation arranger_workstation; + public AWCore aw_core; construct { flags |= ApplicationFlags.HANDLES_OPEN | ApplicationFlags.HANDLES_COMMAND_LINE; application_id = Constants.APP_ID; - settings = new Services.Settings (); } protected override void activate () { Console.log ("Initializing GUI Theme"); - Services.Theme.init_theme (); + // Services.Theme.init_theme (); Console.log ("Initializing Main Window"); - main_window = new Shell.MainWindow (this); - this.add_window (main_window); - main_window.show_ui (); - Console.log ( - "GUI Initialization Complete!", - Console.LogLevel.SUCCESS - ); + // main_window = new Shell.MainWindow (this); + // this.add_window (main_window); + // main_window.show_ui (); + // Console.log ( + // "GUI Initialization Complete!", + // Console.LogLevel.SUCCESS + // ); Console.log ("Initializing Arranger Workstation"); - arranger_workstation = new Core.ArrangerWorkstation (); + aw_core = AWCore.instance + .load_soundfont_from_path (Constants.SF2DATADIR) + .load_style_from_path (Constants.PKGDATADIR); - if (settings.version != Constants.VERSION) { - settings.version = Constants.VERSION; + if (Settings.instance.version != Constants.VERSION) { + Settings.instance.version = Constants.VERSION; + // Show welcome screen } if (Constants.PROFILE == "development") { @@ -90,7 +93,7 @@ namespace Ensembles { } if (verbose || raw_midi_input || kiosk_mode) { - Console.get_console_header (); + Console.get_console_header (Constants.VERSION, Constants.DISPLAYVER); } if (raw_midi_input) { diff --git a/src/Core/Analysers/ChordAnalyser.vala b/src/Core/Analysers/ChordAnalyser.vala deleted file mode 100644 index 26214529..00000000 --- a/src/Core/Analysers/ChordAnalyser.vala +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Core.Analysers { - public class ChordAnalyser : Object { - private uint8[] key_track; - private uint8[] chord_possibility; - - public enum ChordDetectionMode { - SPLIT_LONG = 0, - SPLIT_SHORT = 1, - FULL_RANGE = 2 - } - - construct { - key_track = new uint8[13]; - chord_possibility = new uint8[144]; - } - - /** This function returns an inferred {@link Ensembles.Models.Chord} based on subsequent - * invocations of note-on and note-off events - * - * @param key Key or note number - * @param on Whether the key is pressed or released - * @return A {@link Ensembles.Models.Chord} as determined from subsequent keypresses - */ - public Chord infer (uint8 key, bool on) { - key_track [key % 12] = on ? 1 : 0; - - uint8 n_keys = 0; - int16 probable_root = -1; - - for (uint8 i = 0; i < 12; i++) { - n_keys += key_track[i]; - if (probable_root < 0 && key_track[i] == 1) { - probable_root = i; - } - } - - for (uint8 i = 0; i < 144; i++) { - chord_possibility[i] = 0; - } - - uint8 i = 0; - - if (n_keys < 4) { - // Major - for (; i < 5; i++) { - chord_possibility [i] = 6 * key_track[i] + key_track[i + 4] + key_track[i + 7]; // One way to play it - } - /* ^ - * | - * | - * Root contribution - */ - for (; i < 9; i++) { - chord_possibility [i] = key_track[i - 5] + 6 * key_track[i] + key_track[i + 4]; // Another way to play it - } - for (; i < 12; i++) { - chord_possibility [i] = key_track[i - 8] + key_track[i - 5] + 6 * key_track[i]; // Yet another way to play it - } - - // minor - for (; i < 17; i++) { - chord_possibility [i] = 6 * key_track[i - 12] + key_track[i - 12 + 3] + key_track[i - 12 + 7]; - } - for (; i < 21; i++) { - chord_possibility [i] = key_track[i - 12 - 5] + 6 * key_track[i - 12] + key_track[i - 12 + 3]; - } - for (; i < 24; i++) { - chord_possibility [i] = key_track[i - 12 - 9] + key_track[i - 12 - 5] + 6 * key_track[i - 12]; - } - - // diminished - for (; i < 29; i++) { - chord_possibility [i] = 6 * key_track[i - 24] + key_track[i - 24 + 3] + key_track[i - 24 + 6]; - } - for (; i < 33; i++) { - chord_possibility [i] = key_track[i - 24 + 6] + 6 * key_track[i - 24] + key_track[i - 24 + 3]; - } - for (; i < 36; i++) { - chord_possibility [i] = key_track[i - 24 - 9] + key_track[i - 24 - 6] + 6 * key_track[i - 24]; - } - - // suspended 2 - for (; i < 41; i++) { - chord_possibility [i] = 6 * key_track[i - 36] + key_track[i - 36 + 2] + key_track[i - 36 + 7]; - } - for (; i < 45; i++) { - chord_possibility [i] = key_track[i - 36 - 5] + 6 * key_track[i - 36] + key_track[i - 36 + 2]; - } - for (; i < 48; i++) { - chord_possibility [i] = key_track[i - 36 - 10] + key_track[i - 36 - 5] + 6 * key_track[i - 36]; - } - - // suspended 4 - for (; i < 53; i++) { - chord_possibility [i] = (i - 48 == probable_root && n_keys > 2 ? 7 : 6) * key_track[i - 48] + - key_track[i - 48 + 5] + key_track[i - 48 + 7]; - } - for (; i < 57; i++) { - chord_possibility [i] = key_track[i - 48 - 5] + - (i - 48 == probable_root && n_keys > 2 ? 7 : 6) * key_track[i - 48] + key_track[i - 48 + 5]; - } - for (; i < 60; i++) { - chord_possibility [i] = key_track[i - 48 - 7] + key_track[i - 48 - 5] + - (i - 48 == probable_root && n_keys > 2 ? 7 : 6) * key_track[i - 48]; - } - - // augmented - for (; i < 65; i++) { - chord_possibility [i] = 6 * key_track[i - 60] + key_track[i - 60 + 4] + key_track[i - 60 + 8]; - } - for (; i < 69; i++) { - chord_possibility [i] = key_track[i - 60 - 4] + 6 * key_track[i - 60] + key_track[i - 60 + 4]; - } - for (; i < 72; i++) { - chord_possibility [i] = key_track[i - 60 - 8] + key_track[i - 60 - 4] + 6 * key_track[i - 60]; - } - } else if (n_keys == 4) { - // Dominant Sixth - for (i = 72; i < 77; i++) { - chord_possibility [i] = 6 * key_track[i - 72] + key_track[i - 72 + 4] + - key_track[i - 72 + 7] + key_track[i - 72 + 9]; - } - for (; i < 81; i++) { - chord_possibility [i] = key_track[i - 72 - 5] + - key_track[i - 72 - 3] + 6 * key_track[i - 72] + key_track[i - 72 + 4]; - } - for (; i < 84; i++) { - chord_possibility [i] = key_track[i - 72 - 8] + - key_track[i - 72 - 5] + key_track[i - 72 - 3] + 6 * key_track[i - 72]; - } - - // Dominant Seventh - for (; i < 89; i++) { - chord_possibility [i] = 6 * key_track[i - 84] + key_track[i - 84 + 4] + - key_track[i - 84 + 7] + key_track[i - 84 + 10]; - } - for (; i < 93; i++) { - chord_possibility [i] = key_track[i - 84 - 5] + - key_track[i - 84 - 2] + 6 * key_track[i - 84] + key_track[i - 84 + 4]; - } - for (; i < 96; i++) { - chord_possibility [i] = key_track[i - 84 - 8] + - key_track[i - 84 - 5] + key_track[i - 84 - 2] + 6 * key_track[i - 84]; - } - - // Major Seventh - for (; i < 101; i++) { - chord_possibility [i] = 6 * key_track[i - 96] + - key_track[i - 96 + 4] + key_track[i - 96 + 7] + key_track[i - 96 + 11]; - } - for (; i < 105; i++) { - chord_possibility [i] = key_track[i - 96 - 5] + - key_track[i - 96 - 1] + 6 * key_track[i - 96] + key_track[i - 96 + 4]; - } - for (; i < 108; i++) { - chord_possibility [i] = key_track[i - 96 - 8] + - key_track[i - 96 - 5] + key_track[i - 96 - 1] + 6 * key_track[i - 96]; - } - - // minor seventh - for (; i < 113; i++) { - chord_possibility [i] = 6 * key_track[i - 108] + - key_track[i - 108 + 3] + key_track[i - 108 + 7] + key_track[i - 108 + 10]; - } - for (; i < 117; i++) { - chord_possibility [i] = key_track[i - 108 - 5] + - key_track[i - 108 - 2] + 6 * key_track[i - 108] + key_track[i - 108 + 3]; - } - for (; i < 120; i++) { - chord_possibility [i] = key_track[i - 108 - 9] + - key_track[i - 108 - 5] + key_track[i - 108 - 2] + 6 * key_track[i - 108]; - } - - // add9 - for (; i < 125; i++) { - chord_possibility [i] = 6 * key_track[i - 120] + - key_track[i - 120 + 4] + key_track[i - 120 + 7] + key_track[i - 120 + 2]; - } - for (; i < 129; i++) { - chord_possibility [i] = key_track[i - 120 - 5] + - key_track[i - 120 + 2] + 6 * key_track[i - 120] + key_track[i - 120 + 4]; - } - for (; i < 132; i++) { - chord_possibility [i] = key_track[i - 120 - 8] + - key_track[i - 120 - 5] + key_track[i - 120 - 10] + 6 * key_track[i - 120]; - } - } else if (n_keys == 5) { - // Dominant 9th - for (; i < 137; i++) { - chord_possibility [i] = 6 * key_track[i - 132] + - key_track[i - 132 + 4] + key_track[i - 132 + 7] + key_track[i - 132 + 10] + key_track[i - 132 + 2]; - } - for (; i < 141; i++) { - chord_possibility [i] = key_track[i - 132 - 5] + key_track[i - 132 - 2] + - key_track[i - 120 + 2] + 6 * key_track[i - 132] + key_track[i - 132 + 4]; - } - for (; i < 144; i++) { - chord_possibility [i] = key_track[i - 132 - 8] + - key_track[i - 132 - 5] + key_track[i - 132 - 2] + 6 * key_track[i - 132] + key_track[i - 120 - 10]; - } - } - - i = n_keys < 4 ? 0 : n_keys == 4 ? 72 : 132; - uint8 max_i = n_keys < 4 ? 72 : n_keys == 4 ? 132 : 144; - int16 max = -1; - int16 max_index = 0; - for (; i < max_i; i++) { - // printf("%d ", chord_possibility[i]); - if (max < chord_possibility[i]) { - max = chord_possibility[i]; - max_index = i; - } - } - - var chord = Chord (); - - // Set the chord type - if (max_index < 12) { - chord.type = ChordType.MAJOR; - } else if (max_index < 24) { - chord.type = ChordType.MINOR; - } else if (max_index < 36) { - chord.type = ChordType.DIMINISHED; - } else if (max_index < 48) { - chord.type = ChordType.SUSPENDED_2; - } else if (max_index < 60) { - chord.type = ChordType.SUSPENDED_4; - } else if (max_index < 72) { - chord.type = ChordType.AUGMENTED; - } else if (max_index < 84) { - chord.type = ChordType.SIXTH; - } else if (max_index < 96) { - chord.type = ChordType.SEVENTH; - } else if (max_index < 108) { - chord.type = ChordType.MAJOR_7TH; - } else if (max_index < 120) { - chord.type = ChordType.MINOR_7TH; - } else if (max_index < 132) { - chord.type = ChordType.ADD_9TH; - } else { - chord.type = ChordType.NINTH; - } - - // Set the root note - if (max > 0) { - if (max_index >= 0 && max_index <= 6) { - chord.root = convert_to_chord (max_index); - } else if (max_index >= 7 && max_index <= 18) { - chord.root = convert_to_chord (max_index - 12); - } else if (max_index >= 19 && max_index <= 30) { - chord.root = convert_to_chord (max_index - 24); - } else if (max_index >= 31 && max_index <= 42) { - chord.root = convert_to_chord (max_index - 36); - } else if (max_index >= 43 && max_index <= 54) { - chord.root = convert_to_chord (max_index - 48); - } else if (max_index >= 55 && max_index <= 66) { - chord.root = convert_to_chord (max_index - 60); - } else if (max_index >= 67 && max_index <= 78) { - chord.root = convert_to_chord (max_index - 72); - } else if (max_index >= 79 && max_index <= 90) { - chord.root = convert_to_chord (max_index - 84); - } else if (max_index >= 91 && max_index <= 102) { - chord.root = convert_to_chord (max_index - 96); - } else if (max_index >= 103 && max_index <= 114) { - chord.root = convert_to_chord (max_index - 108); - } else if (max_index >= 115 && max_index <= 126) { - chord.root = convert_to_chord (max_index - 120); - } else if (max_index >= 127 && max_index <= 138) { - chord.root = convert_to_chord (max_index - 132); - } else if (max_index >= 139 && max_index <= 156) { - chord.root = convert_to_chord (max_index - 150); - } else { - chord.root = ChordRoot.NONE; - } - } - - return chord; - } - - private ChordRoot convert_to_chord (int16 root) { - switch (root) { - case 0: - return ChordRoot.C; - case 1: - return ChordRoot.CS; - case 2: - return ChordRoot.D; - case 3: - return ChordRoot.EF; - case 4: - return ChordRoot.E; - case 5: - return ChordRoot.F; - case 6: - return ChordRoot.FS; - case -5: - return ChordRoot.G; - case -4: - return ChordRoot.AF; - case -3: - return ChordRoot.A; - case -2: - return ChordRoot.BF; - case -1: - return ChordRoot.B; - } - - return ChordRoot.NONE; - } - } -} diff --git a/src/Core/Analysers/StyleAnalyser.vala b/src/Core/Analysers/StyleAnalyser.vala deleted file mode 100644 index 3a503cba..00000000 --- a/src/Core/Analysers/StyleAnalyser.vala +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Core.Analysers { - /** - * A style analyser can analyse an `enstl` style and describe it. - * The analysis takes place when the object is created using the given path - * and the resulting `Style` object can be retreived using the - * `get_style ()` method. - */ - public class StyleAnalyser : Object { - public bool valid = false; - - private string enstl_path; - private string name; - private string genre; - private uint8[] copyright_notice; - private uint8 time_signature_n; - private uint8 time_signature_d; - private uint32 ticks_per_beat; - private uint32 tempo_ms; - private bool scale_type; - private StylePart[] parts; - - private const string[] EXPECTED_PARTS = { - "CONFIG", - "INT_1", - "INT_2", - "INT_3", - "BRK", - "VAR_A", - "FILL_A", - "VAR_B", - "FILL_B", - "VAR_C", - "FILL_C", - "VAR_D", - "FILL_D", - "END_1", - "EOS", - "END_2", - "EOS", - "END_3", - "EOS" - }; - - /** - * Creates a new `StyleAnalyser` object for analysing the style in the - * given path. - * - * @param enstl_path path to the enstl file - */ - public StyleAnalyser (string enstl_path) throws StyleError, Error { - this.enstl_path = enstl_path; - - var file_tokens = enstl_path.split ("/"); - string file_name = file_tokens[file_tokens.length - 1]; - int file_name_delimit_index = file_name.index_of_char ('@'); - genre = file_name.substring (0, file_name_delimit_index); - name = file_name.substring (file_name_delimit_index + 1, - file_name.index_of_char ('.') - file_name_delimit_index - 1).replace ("_", " "); - - var style_file = File.new_for_path (enstl_path); - - if (!style_file.query_exists ()) { - Console.log ("Style file is missing or invalid", Ensembles.Console.LogLevel.WARNING); - } - - uint8[] buffer; - - var fs = style_file.read (); - var dis = new DataInputStream (fs); - dis.set_byte_order (GLib.DataStreamByteOrder.LITTLE_ENDIAN); - - dis.seek (0, GLib.SeekType.END); - var filelen = dis.tell (); - dis.seek (0, GLib.SeekType.SET); - - buffer = new uint8[filelen]; - - if (!dis.read_all (buffer, out filelen)) { - dis.close (); - throw new StyleError.INVALID_FILE ("Failed to read style file. Make sure the file is accessible"); - } - - dis.close (); - - - ticks_per_beat = 0; - parts = new StylePart[18]; - uint8 expected_part_index = 0; - uint8 marker_index = 0; - bool default_tempo_acquired = false; - - for (uint64 i = 0; i < filelen; i++) { - // Find ticks per beat from MTHD header - if (buffer[i] == 0x4D && buffer[i + 1] == 0x54 && buffer[i + 2] == 0x68 && buffer[i + 3] == 0x64) { - uint8 a = buffer[i + 12]; - uint8 b = buffer[i + 13]; - ticks_per_beat = (a << 8) | (b & 0x000000FF); - } - - // Get Meta Events - if (ticks_per_beat > 0 && buffer[i] == 0xFF) { - // Find copyright notice - if (buffer[i + 1] == 0x02) { - uint8 copyright_str_len = buffer[i + 2]; - - copyright_notice = new uint8[copyright_str_len]; - for (uint8 j = 0; j < copyright_str_len; j++) { - copyright_notice[j] = buffer[i + 3 + j]; - } - } - - // Get default tempo - if (!default_tempo_acquired && buffer[i + 1] == 0x51) { - tempo_ms = get_tempo (buffer, i + 2); - default_tempo_acquired = true; - } - - // Find time signature - if (buffer[i + 1] == 0x58 && buffer[i + 2] == 0x04) { - time_signature_n = buffer[i + 3]; - time_signature_d = (uint8)Math.pow (2, buffer[i + 4]); - } - - // Get marker data - if (buffer[i + 1] == 0x06) { - uint8 marker_str_length = buffer[i + 2]; - uint8[] marker_str = new uint8[marker_str_length]; - - for (uint8 j = 0; j < marker_str_length; j++) { - marker_str[j] = buffer[i + 3 + j]; - } - - string str = (string)marker_str; - // Get measure - int marker_token_index = str.index_of_char (':'); - - int scale_type_index = str.index_of_char (';'); - - uint measure = 0; - if (marker_token_index > 0 && marker_token_index < marker_str_length) { - measure = uint.parse (str.substring (marker_token_index + 1, - scale_type_index < marker_str_length - ? scale_type_index - marker_token_index - 1: -1)); - } - - int i_scale_type = 0; - if (scale_type_index > 0 && scale_type_index < marker_str_length) { - i_scale_type = int.parse (str.substring (scale_type_index + 1)); - } - scale_type = i_scale_type > 0; - - var marker_name = str.substring (0, marker_token_index); - - if (marker_name[0] != 'C') { - parts[marker_index++] = StylePart () { - time_stamp = (uint)(((measure - 1) * 4 * time_signature_n * ticks_per_beat) - / time_signature_d), - style_part_type = get_style_part_type_from_marker (marker_name) - }; - } - - if (marker_name != EXPECTED_PARTS[expected_part_index++]) { - if (expected_part_index == 1) { - throw new StyleError.INVALID_LAYOUT ("Expected config marker"); - } else { - throw new StyleError.INVALID_LAYOUT ("Expected %s marker after %s marker", - EXPECTED_PARTS[expected_part_index - 1], EXPECTED_PARTS[expected_part_index - 2]); - } - } - } - } - } - } - - /** - * Get the analysed style object - */ - public Style get_style () { - return Style () { - name = this.name, - genre = this.genre, - tempo = (uint8)(60000000 / this.tempo_ms), - time_signature_n = this.time_signature_n, - time_signature_d = this.time_signature_d, - time_resolution = this.ticks_per_beat, - enstl_path = this.enstl_path, - copyright_notice = (string)this.copyright_notice, - scale_type = this.scale_type ? ChordType.MINOR : ChordType.MAJOR, - parts = this.parts - }; - } - - // private uint32 get_variable_length_value (uint8[] buffer, uint64 offset) { - // uint32 value = buffer[offset]; - - // uint8 c = 0xFF; - // uint i = 0; - - // if ((value & 0x80) > 0) { - // value &= 0x7F; - // do { - // c = buffer[offset + (i++)]; - // value = (value << 7) | (c & 0x7F); - // } while ((c & 0x80) > 0); - // } - - // return value; - // } - - private uint32 get_tempo (uint8[] buffer, uint64 offset) { - uint8 len = buffer[offset]; - - uint32 tempo = 0; - for (uint8 i = 1; i <= len; i++) { - tempo = (tempo << 8) | buffer[offset + i]; - } - - return tempo; - } - - private StylePartType get_style_part_type_from_marker (string marker) { - switch (marker) { - case "INT_1": - return (StylePartType.INTRO_1); - case "INT_2": - return (StylePartType.INTRO_2); - case "INT_3": - return (StylePartType.INTRO_3); - case "BRK": - return (StylePartType.BREAK); - case "VAR_A": - return (StylePartType.VARIATION_A); - case "VAR_B": - return (StylePartType.VARIATION_B); - case "VAR_C": - return (StylePartType.VARIATION_C); - case "VAR_D": - return (StylePartType.VARIATION_D); - case "FILL_A": - return (StylePartType.FILL_A); - case "FILL_B": - return (StylePartType.FILL_B); - case "FILL_C": - return (StylePartType.FILL_C); - case "FILL_D": - return (StylePartType.FILL_D); - case "END_1": - return (StylePartType.ENDING_1); - case "END_2": - return (StylePartType.ENDING_2); - case "END_3": - return (StylePartType.ENDING_3); - } - - return (StylePartType.EOS); - } - } -} diff --git a/src/Core/Analysers/VoiceAnalyser.vala b/src/Core/Analysers/VoiceAnalyser.vala deleted file mode 100644 index 24de4aaa..00000000 --- a/src/Core/Analysers/VoiceAnalyser.vala +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Core.Analysers { - public class VoiceAnalyser : Object { - private List voice_list; - - public signal void voice_analysed (string name); - - public VoiceAnalyser ( - AudioEngine.SynthProvider synth_provider, - string sf_path, - string sf_schema_path - ) { - voice_list = new List (); - - unowned Fluid.Synth sf_synth = synth_provider.utility_synth; - unowned Fluid.SoundFont soundfont = sf_synth.get_sfont (0); - - - FileStream stream = FileStream.open (sf_schema_path, "r"); - string? line = ""; - line = stream.read_line (); - string category = ""; - - uint index = 0; - unowned Fluid.Preset sf_preset = null; - soundfont.iteration_start (); - sf_preset = soundfont.iteration_next (); - while (sf_preset != null) { - int preset_num = sf_preset.get_num (); - int bank_num = sf_preset.get_banknum (); - var voice_name = sf_preset.get_name (); - - if (line != null) { - var parts = line.split (","); - int schema_bank = int.parse (parts[0]); - int schema_preset = int.parse (parts[1]); - - if (bank_num == schema_bank && preset_num == schema_preset) { - category = parts[2]; - line = stream.read_line (); - } - } - - voice_list.append (Voice () { - index = index++, - preset = (uint8) preset_num, - bank = (uint8) bank_num, - name = voice_name, - category = category, - sf_path = sf_path - }); - - Application.event_bus.send_initial_status (_("Loading voice: ") + voice_name + "…"); - Thread.usleep (15000); - - sf_preset = soundfont.iteration_next (); - } - } - - public Voice[] get_voices () { - var n = voice_list.length (); - var voices = new Voice[n]; - - for (uint i = 0; i < n; i++) { - var voice = voice_list.nth_data (i); - voices[i] = Voice () { - name = voice.name, - category = voice.category, - sf_path = voice.sf_path, - preset = voice.preset, - bank = voice.bank, - index = voice.index - }; - } - - return voices; - } - } -} diff --git a/src/Core/ArrangerWorkstation.vala b/src/Core/ArrangerWorkstation.vala deleted file mode 100644 index f4ae396b..00000000 --- a/src/Core/ArrangerWorkstation.vala +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.MIDIPlayers; -using Ensembles.Core.Plugins; -using Ensembles.Core.Racks; -using Ensembles.Models; - -namespace Ensembles.Core { - /** - * ## Arranger Workstation - * - * This forms the core of the app. This houses all the behind the scenes - * stuff that make every beat beat and every sound sound. - */ - public class ArrangerWorkstation : Object { - private AudioEngine.SynthProvider synth_provider; - private AudioEngine.Synthesizer synthesizer; - private StyleEngine style_engine; - private PluginManager plugin_manager; - private DSPRack main_dsp_rack; - private VoiceRack voice_l_rack; - private VoiceRack voice_r1_rack; - private VoiceRack voice_r2_rack; - - // Arranger Data - private Style[] styles; - private Style next_style; - private bool stopping_style; - - private Voice[] voices; - - private const string SF_PATH = Constants.SF2DATADIR + "/EnsemblesGM.sf2"; - private const string SF_SCHEMA_PATH = Constants.SF2DATADIR + "/EnsemblesGMSchema.csv"; - - construct { - #if PIPEWIRE_CORE_DRIVER - Pipewire.init (null, null); - #endif - synth_provider = new AudioEngine.SynthProvider (); - synth_provider.init_driver ("pulseaudio", 0.3); - Console.log ("Loading Soundfont from %s".printf (SF_PATH)); - try { - synthesizer = new AudioEngine.Synthesizer (synth_provider, SF_PATH); - } catch (FluidError e) { - Console.log (e.message, Console.LogLevel.ERROR); - } - - Console.log ("Initializing Plugin Racks"); - main_dsp_rack = new DSPRack (); - synthesizer.add_rack (main_dsp_rack); - - voice_l_rack = new VoiceRack (); - synthesizer.add_rack (voice_l_rack); - - voice_r1_rack = new VoiceRack (); - synthesizer.add_rack (voice_r1_rack); - - voice_r2_rack = new VoiceRack (); - synthesizer.add_rack (voice_r2_rack); - - build_events (); - } - - public ArrangerWorkstation () { - new Thread ("ensembles-data-discovery", load_data); - } - - /** - * Load all data like voices, styles and plugins - */ - public void load_data () { - Thread.usleep (500000); - // Load Styles - Console.log ("Searching for styles…"); - var style_loader = new FileLoaders.StyleFileLoader (); - uint n_styles = 0; - styles = style_loader.get_styles (out n_styles); - Console.log ( - "Found %u styles".printf (n_styles), - Console.LogLevel.SUCCESS - ); - - // Load Voices - Console.log ("Loading voices…"); - var voice_loader = new Analysers.VoiceAnalyser ( - synth_provider, - SF_PATH, - SF_SCHEMA_PATH - ); - Console.log ( - "Voices loaded successfully!", - Console.LogLevel.SUCCESS - ); - voices = voice_loader.get_voices (); - - // Load Plugins - Console.log ("Loading Audio Plugins…"); - plugin_manager = new PluginManager (); - Console.log ( - "%u Audio Plugins Loaded Successfully!" - .printf (plugin_manager.audio_plugins.length ()), - Console.LogLevel.SUCCESS - ); - - add_plugins_to_voice_racks (); - - Application.event_bus.send_initial_status (""); - - // Send ready signal - Idle.add (() => { - Ensembles.Application.event_bus.arranger_ready (); - return false; - }); - } - - private void build_events () { - Application.event_bus.style_play_toggle.connect (() => { - if (style_engine != null) { - style_engine.toggle_play (); - } - }); - - Application.event_bus.style_set_part.connect ( - (part) => { - if (style_engine != null) { - style_engine.queue_next_part (part); - } - } - ); - - Application.event_bus.style_break.connect (() => { - if (style_engine != null) { - style_engine.break_play (); - } - }); - - Application.event_bus.style_sync.connect (() => { - if (style_engine != null) { - style_engine.sync (); - } - }); - - Application.event_bus.style_change.connect ( - (style) => { - queue_change_style (style); - }); - } - - /** - * Creates a style engine with given style - * - * @param style A Style descriptor - */ - public void queue_change_style (Models.Style style) { - Console.log ("Changing style to the " + style.to_string ()); - next_style = style; - if (!stopping_style) { - stopping_style = true; - new Thread ("queue-load-style", () => { - uint8 current_tempo = 0; - bool was_playing = false; - StylePartType current_part = StylePartType.VARIATION_A; - if (style_engine != null) { - current_part = style_engine.current_part; - was_playing = style_engine.stop_and_wait (out current_tempo); - } - - style_engine = new StyleEngine ( - synth_provider, - next_style, - current_tempo - ); - stopping_style = false; - - style_engine.queue_next_part (current_part); - - if (was_playing) { - style_engine.play (); - } - }); - } - } - - /** - * Returns an array of styles loaded by the arranger workstation. - */ - public unowned Style[] get_styles () { - return styles; - } - - /** - * Returns an array of voices loaded by the arranger workstation. - */ - public unowned Voice[] get_voices () { - return voices; - } - - private void add_plugins_to_voice_racks () { - unowned List plugins = - plugin_manager.audio_plugins; - for (uint32 i = 0; i < plugins.length (); i++) { - if (plugins.nth_data (i).category == - AudioPlugins.AudioPlugin.Category.VOICE) { - try { - voice_l_rack.append (plugins.nth_data (i).duplicate ()); - voice_r1_rack.append (plugins.nth_data (i).duplicate ()); - voice_r2_rack.append (plugins.nth_data (i).duplicate ()); - } catch (PluginError e) { - - } - } - } - - voice_l_rack.active = true; - voice_r1_rack.active = true; - voice_r2_rack.active = true; - } - - public unowned List get_audio_plugins () { - return plugin_manager.audio_plugins; - } - - public unowned Racks.DSPRack get_main_dsp_rack () { - return main_dsp_rack; - } - - public unowned Racks.VoiceRack get_voice_rack ( - VoiceHandPosition position - ) { - switch (position) { - case VoiceHandPosition.LEFT: - return voice_l_rack; - case VoiceHandPosition.RIGHT_LAYERED: - return voice_r2_rack; - default: - return voice_r1_rack; - } - } - } -} diff --git a/src/Core/AudioEngine/SynthProvider.vala b/src/Core/AudioEngine/SynthProvider.vala deleted file mode 100644 index 7e95237a..00000000 --- a/src/Core/AudioEngine/SynthProvider.vala +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.AudioEngine { - /** - * ## Synthesizer Instance Provider - * - * Manages FluidSynth instances and driver configurations. - */ - public class SynthProvider : Object { - private Fluid.Synth _rendering_synth; - private Fluid.AudioDriver rendering_driver; - private Fluid.Settings rendering_settings; - - public delegate void SynthRenderHandler ( - int len, - float* input_l, - float* input_r, - float** output_l, - float** output_r - ); - - private static float* wet_buffer_l; - private static float* wet_buffer_r; - - public static SynthRenderHandler synth_render_handler; - - ~SynthProvider () { - Fluid.free (wet_buffer_l); - Fluid.free (wet_buffer_r); - } - - /** - * This synth instance is used for actually renderring audio - */ - public unowned Fluid.Synth rendering_synth { - get { - if (_rendering_synth == null) { - rendering_settings = new Fluid.Settings (); - rendering_settings.setnum ("synth.gain", 1); - rendering_settings.setnum ("synth.overflow.percussion", 5000.0); - rendering_settings.setint ("synth.midi-channels", 64); - rendering_settings.setstr ("synth.midi-bank-select", "gs"); - rendering_settings.setint ("synth.polyphony", 1024); - - _rendering_synth = new Fluid.Synth (rendering_settings); - rendering_driver = new Fluid.AudioDriver.with_audio_callback ( - rendering_settings, - (synth, len, fx, aout) => { - // Log current unix time before the synthesizer processes audio - Synthesizer.processing_start_time = new DateTime.now_utc ().to_unix (); - - if (fx == null) { - /* Note that some audio drivers may not provide buffers for effects like - * reverb and chorus. In this case it's your decision what to do. If you - * had called process() like in the else branch below, no - * effects would have been rendered. Instead, you may mix the effects - * directly into the out buffers. */ - if (((Fluid.Synth)synth).process (len, aout, aout) != Fluid.OK) { - return Fluid.FAILED; - } - } else { - /* Call the synthesizer to fill the output buffers with its - * audio output. */ - if (((Fluid.Synth)synth).process (len, fx, aout) != Fluid.OK) { - return Fluid.FAILED; - } - } - - // All processing is stereo // Repeat processing if the plugin is mono - float* dry_buffer_l = aout[0]; - float* dry_buffer_r = aout[1]; - - // Apply effects here - if (wet_buffer_l == null || wet_buffer_r == null) { - wet_buffer_l = malloc (len * sizeof (float)); - wet_buffer_r = malloc (len * sizeof (float)); - } - - // int size_l, size_r; - - if (synth_render_handler != null) { - for (int k = 0; k < len; k++) { - wet_buffer_l[k] = dry_buffer_l[k]; - wet_buffer_r[k] = dry_buffer_r[k]; - } - /* - * The audio buffer data is sent to the plugin system - */ - synth_render_handler (len, - dry_buffer_l, - dry_buffer_r, - &wet_buffer_l, - &wet_buffer_r); - - for (int k = 0; k < len; k++) { - dry_buffer_l[k] = wet_buffer_l[k]; - dry_buffer_r[k] = wet_buffer_r[k]; - } - } - - return Fluid.OK; - }, _rendering_synth); - } - return _rendering_synth; - } - } - - private Fluid.Synth _utility_synth; - private Fluid.AudioDriver utility_driver; - private Fluid.Settings utility_settings; - - /** This instance is never used to render audio and only use for Midi players - */ - public unowned Fluid.Synth utility_synth { - get { - if (_utility_synth == null) { - utility_settings = new Fluid.Settings (); - utility_settings.setnum ("synth.overflow.percussion", 5000.0); - utility_settings.setstr ("synth.midi-bank-select", "gs"); - utility_settings.setint ("synth.cpu-cores", 4); - - _utility_synth = new Fluid.Synth (utility_settings); - utility_driver = new Fluid.AudioDriver (utility_settings, _utility_synth); - } - return _utility_synth; - } - } - - /** - * Sets driver configuration of synthesizer instance - * - * This should be called before accessing any synth - */ - public int init_driver (string driver_name, double buffer_length_multiplier) { - switch (driver_name) { - case "alsa": - rendering_settings.setstr ("audio.driver", "alsa"); - rendering_settings.setint ("audio.periods", 8); - rendering_settings.setint ("audio.period-size", (int)(86.0 + (buffer_length_multiplier * 938.0))); - rendering_settings.setint ("audio.realtime-prio", 80); - - utility_settings.setstr ("audio.driver", "alsa"); - utility_settings.setint ("audio.periods", 16); - utility_settings.setint ("audio.period-size", (int)(64.0 + (buffer_length_multiplier * 938.0))); - utility_settings.setint ("audio.realtime-prio", 70); - - return (int)(86.0 + (buffer_length_multiplier * 938.0)); - case "pulseaudio": - rendering_settings.setstr ("audio.driver", "pulseaudio"); - rendering_settings.setint ("audio.periods", 8); - rendering_settings.setint ("audio.period-size", - (int)(1024.0 + (buffer_length_multiplier * 3072.0))); - rendering_settings.setint ("audio.realtime-prio", 80); - // rendering_settings.setint ("audio.pulseaudio.adjust-latency", 0); - - utility_settings.setstr ("audio.driver", "pulseaudio"); - utility_settings.setint ("audio.periods", 2); - utility_settings.setint ("audio.period-size", 512); - utility_settings.setint ("audio.realtime-prio", 90); - utility_settings.setint ("audio.pulseaudio.adjust-latency", 0); - - return (int)(1024.0 + (buffer_length_multiplier * 3072.0)); - case "pipewire-pulse": - rendering_settings.setstr ("audio.driver", "pulseaudio"); - rendering_settings.setint ("audio.periods", 8); - rendering_settings.setint ("audio.period-size", (int)(512.0 + (buffer_length_multiplier * 3584.0))); - rendering_settings.setint ("audio.pulseaudio.adjust-latency", 0); - - utility_settings.setstr ("audio.driver", "pulseaudio"); - utility_settings.setint ("audio.periods", 2); - utility_settings.setint ("audio.period-size", 512); - - return (int)(512.0 + (buffer_length_multiplier * 3584.0)); - case "jack": - rendering_settings.setnum ("synth.gain", 0.005); - rendering_settings.setstr ("audio.driver", "jack"); - rendering_settings.setstr ("audio.jack.id", "Ensembles Audio Output"); - - utility_settings.setstr ("audio.driver", "jack"); - utility_settings.setstr ("audio.jack.id", "Ensembles Utility"); - - return 0; - case "pipewire": - rendering_settings.setstr ("audio.driver", "pipewire"); - rendering_settings.setint ("audio.period-size", (int)(256.0 + (buffer_length_multiplier * 3584.0))); - rendering_settings.setint ("audio.realtime-prio", 80); - rendering_settings.setstr ("audio.pipewire.media-role", "Production"); - rendering_settings.setstr ("audio.pipewire.media-type", "Audio"); - rendering_settings.setstr ("audio.pipewire.media-category", "Playback"); - - utility_settings.setstr ("audio.driver", "pipewire"); - utility_settings.setint ("audio.period-size", 256); - utility_settings.setint ("audio.realtime-prio", 90); - utility_settings.setstr ("audio.pipewire.media-role", "Game"); - utility_settings.setstr ("audio.pipewire.media-type", "Audio"); - utility_settings.setstr ("audio.pipewire.media-category", "Playback"); - - return (int)(256.0 + (buffer_length_multiplier * 3584.0)); - } - - return 0; - } - } -} - - -/* - * RENDER SYNTH CHANNEL UTILIZATION SCHEMATICS - * ---------------------------------------------- - * - * Style, Song: - * 0 - 15 - * - * Metronome: - * 16 - * - * MIDI INPUT: - * Voice R1 ~ 17 - * Voice R2 ~ 18 - * Voice L ~ 19 - * CHORD-EP ~ 20 - * CHORD-Strings ~ 21 - * CHORD-Bass ~ 22 - * - * CHIMES: - * 23 - * - * RECORDER: - * Voice R2 ~ 24 - * Voice L ~ 25 - * All tracks ~ 26 - 63 - */ diff --git a/src/Core/AudioEngine/SynthSettingsPresets.vala b/src/Core/AudioEngine/SynthSettingsPresets.vala deleted file mode 100644 index a42116f3..00000000 --- a/src/Core/AudioEngine/SynthSettingsPresets.vala +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - namespace Ensembles.Core.AudioEngine.SynthSettingsPresets { - /** Reverb presets - */ - public class ReverbPresets { - public const double[] ROOM_SIZE = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}; - public const double[] WIDTH = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; - public const double[] LEVEL = { 0, 0.05, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 }; - } - - /** Chorus presets - */ - public class ChorusPresets { - public const double[] DEPTH = {0, 4, 4, 4, 6, 10, 20, 25, 30, 35, 40 }; - public const uint8[] NR = { 0, 2, 3, 3, 4, 5, 6, 8, 10, 16, 20 }; - public const double[] LEVEL = { 0, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2 }; - } - - public class ModulatorSettings : Object { - private int16[] pan_value; - private int16[] reverb_value; - private int16[] chorus_value; - private int16[] pitch_value; - private int16[] expression_value; - private int16[] modulation_value; - private int16[] cut_off_value; - private int16[] resonance_value; - - construct { - pan_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - pan_value[i] = -65; - } - - reverb_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - reverb_value[i] = -1; - } - - chorus_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - chorus_value[i] = -1; - } - - pitch_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - pitch_value[i] = -65; - } - - expression_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - expression_value[i] = -1; - } - - modulation_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - modulation_value[i] = -1; - } - - cut_off_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - cut_off_value[i] = -1; - } - - resonance_value = new int16 [16]; - for (uint8 i = 0; i < 16; i++) { - resonance_value[i] = -1; - } - } - - /** Gets the modulator value of style channel by modulator number - */ - public int16 get_mod_buffer_value (uint8 modulator, uint8 channel) { - switch (modulator) { - case 1: - return modulation_value[channel]; - case 10: - return pan_value[channel]; - case 11: - return expression_value[channel]; - case 66: - return pitch_value[channel]; - case 71: - return resonance_value[channel]; - case 74: - return cut_off_value[channel]; - case 91: - return reverb_value[channel]; - case 93: - return chorus_value[channel]; - } - return -1; - } - - /** Sets the modulator value of style channel by modulator number - */ - public void set_mod_buffer_value (uint8 modulator, uint8 channel, int16 value) { - switch (modulator) { - case 1: - modulation_value[channel] = value; - break; - case 10: - pan_value[channel] = value; - break; - case 11: - expression_value[channel] = value; - break; - case 66: - pitch_value[channel] = value; - break; - case 71: - resonance_value[channel] = value; - break; - case 74: - cut_off_value[channel] = value; - break; - case 91: - reverb_value[channel] = value; - break; - case 93: - chorus_value[channel] = value; - break; - } - } - } - - public class StyleGainSettings : Object { - /** Style gain values */ - public int16[] gain; - construct { - gain = new int16[16]; - for (uint i = 0; i < 16; i++) { - gain[i] = -1; - } - } - } -} diff --git a/src/Core/AudioEngine/Synthesizer.vala b/src/Core/AudioEngine/Synthesizer.vala deleted file mode 100644 index b0832dd8..00000000 --- a/src/Core/AudioEngine/Synthesizer.vala +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.AudioEngine { - /** - * ## Synthesizer - * - * The FluidSynth SoundFont™ Synthesizer forms the base audio engine for the - * app. - * - * All midi events either from the midi players or from the plugins will be - * to and from here. - * - * All sound from the plugins and samplers are also channel through this - * synthesizer. - */ - public class Synthesizer : Object { - - private bool _input_enabled = true; - - public bool input_enabled { - get { - return _input_enabled; - } - set { - _input_enabled = value; - } - } - - public bool layer { get; set; } - public bool split { get; set; } - - public static int64 processing_start_time; - - private static uint32 buffer_size; - - private Analysers.ChordAnalyser chord_analyser; - private SynthSettingsPresets.StyleGainSettings style_gain_settings; - private SynthSettingsPresets.ModulatorSettings modulator_settings; - private unowned Fluid.Synth rendering_synth; - - public List racks; - - public static double sample_rate { get; private set; } - - private int soundfont_id; - - construct { - chord_analyser = new Analysers.ChordAnalyser (); - style_gain_settings = new SynthSettingsPresets.StyleGainSettings (); - modulator_settings = new SynthSettingsPresets.ModulatorSettings (); - racks = new List (); - } - - public Synthesizer (SynthProvider synth_provider, string soundfont) throws FluidError { - Console.log ("Initializing Synthesizer…"); - rendering_synth = synth_provider.rendering_synth; - buffer_size = rendering_synth.get_internal_bufsize (); - double sample_rate = 1; - var s = rendering_synth.get_settings (); - s.getnum ("synth.sample-rate", out sample_rate); - Console.log ("Sample Rate: %0.1lf Hz".printf (sample_rate)); - Synthesizer.sample_rate = sample_rate; - SynthProvider.synth_render_handler = process_audio; - - if (Fluid.is_soundfont (soundfont)) { - soundfont_id = synth_provider.rendering_synth.sfload (soundfont, true); - synth_provider.utility_synth.sfload (soundfont, true); - - // Initialize Voices - rendering_synth.program_select (17, soundfont_id, 0, 0); - rendering_synth.program_select (18, soundfont_id, 0, 49); - rendering_synth.program_select (19, soundfont_id, 0, 33); - - // Initialize chord voices - rendering_synth.program_select (20, soundfont_id, 0, 5); - rendering_synth.program_select (21, soundfont_id, 0, 33); - rendering_synth.program_select (22, soundfont_id, 0, 49); - - // Initialize metronome voice - rendering_synth.program_select (16, soundfont_id, 128, 0); - - // Initialize intro chime voice - rendering_synth.program_select (23, soundfont_id, 0, 96); - } else { - throw new FluidError.INVALID_SF (_("SoundFont from path: %s is either missing or invalid"), soundfont); - } - - set_synth_defaults (); - - build_events (); - } - - private void build_events () { - Application.event_bus.style_midi_event.connect (handle_midi_event_from_player); - Application.event_bus.synth_send_event.connect (handle_midi_event); - Application.event_bus.synth_halt_notes.connect (halt_notes); - Application.event_bus.synth_sounds_off.connect (stop_all_sounds); - Application.event_bus.arranger_ready.connect (play_intro_sound); - Application.event_bus.voice_chosen.connect ((hand_position, name, bank, preset) => { - uint8 channel = 17; - switch (hand_position) { - case VoiceHandPosition.LEFT: - channel = 19; - break; - case VoiceHandPosition.RIGHT_LAYERED: - channel = 18; - break; - default: - break; - } - - rendering_synth.program_select (channel, soundfont_id, bank, preset); - }); - } - - private void set_synth_defaults () { - // CutOff for Realtime synth - rendering_synth.cc (17, MIDI.Control.CUT_OFF, 40); - rendering_synth.cc (18, MIDI.Control.CUT_OFF, 0); - rendering_synth.cc (19, MIDI.Control.CUT_OFF, 0); - - // Reverb and Chorus for R1 voice - rendering_synth.cc (17, MIDI.Control.REVERB, 100); - rendering_synth.cc (17, MIDI.Control.CHORUS, 100); - - // Reverb and Chorus for intro tone - rendering_synth.cc (23, MIDI.Control.REVERB, 127); - rendering_synth.cc (23, MIDI.Control.CHORUS, 100); - rendering_synth.cc (23, MIDI.Control.CUT_OFF, 40); - rendering_synth.cc (23, MIDI.Control.RESONANCE, 80); - - // Reverb and Chorus for Metronome - rendering_synth.cc (16, MIDI.Control.REVERB, 0); - rendering_synth.cc (16, MIDI.Control.CHORUS, 0); - - // Default gain for Realtime synth - rendering_synth.cc (17, MIDI.Control.GAIN, 100); - rendering_synth.cc (18, MIDI.Control.GAIN, 90); - rendering_synth.cc (19, MIDI.Control.GAIN, 80); - - - // Default pitch of all synths - for (int i = 17; i < 64; i++) { - rendering_synth.cc (i, MIDI.Control.EXPLICIT_PITCH, 64); - } - - // Default cut-off and resonance for recorder - for (int i = 24; i < 64; i++) { - rendering_synth.cc (i, MIDI.Control.CUT_OFF, 40); - rendering_synth.cc (i, MIDI.Control.RESONANCE, 10); - } - - // Default pitch for styles - for (int i = 0; i < 16; i++) { - rendering_synth.cc (i, MIDI.Control.EXPLICIT_PITCH, 64); - } - - set_master_reverb_active (true); - edit_master_reverb (8); - - set_master_chorus_active (true); - edit_master_chorus (2); - } - - private void play_intro_sound () { - Timeout.add (200, () => { - rendering_synth.noteon (23, 65, 110); - return false; - }); - - Timeout.add (300, () => { - rendering_synth.noteon (23, 60, 90); - return false; - }); - - Timeout.add (400, () => { - rendering_synth.noteon (23, 72, 127); - return false; - }); - - Timeout.add (500, () => { - rendering_synth.noteoff (23, 65); - rendering_synth.noteoff (23, 60); - rendering_synth.noteoff (23, 72); - return false; - }); - } - - private void process_audio ( - int len, - float* input_l, - float* input_r, - float** output_l, - float** output_r - ) { - foreach (var rack in racks) { - rack.process_audio ( - len, input_l, input_r, output_l, output_r - ); - - // Copy back to input for next rack - for (int i = 0; i < len; i++) { - input_l[i] = * (* output_l + i); - input_r[i] = * (* output_r + i); - } - } - } - - public void add_rack (Racks.Rack rack) { - racks.append (rack); - } - - public static uint32 get_buffer_size () { - return buffer_size; - } - - public static int64 get_process_start_time () { - return processing_start_time; - } - - private void edit_master_reverb (int level) { - if (rendering_synth != null) { - rendering_synth.set_reverb_group_roomsize (-1, SynthSettingsPresets.ReverbPresets.ROOM_SIZE[level]); - rendering_synth.set_reverb_group_damp (-1, 0.1); - rendering_synth.set_reverb_group_width (-1, SynthSettingsPresets.ReverbPresets.WIDTH[level]); - rendering_synth.set_reverb_group_level (-1, SynthSettingsPresets.ReverbPresets.LEVEL[level]); - } - } - - private void set_master_reverb_active (bool active) { - if (rendering_synth != null) { - rendering_synth.reverb_on (-1, active); - } - } - - private void edit_master_chorus (int level) { - if (rendering_synth != null) { - rendering_synth.set_chorus_group_depth (-1, SynthSettingsPresets.ChorusPresets.DEPTH[level]); - rendering_synth.set_chorus_group_level (-1, SynthSettingsPresets.ChorusPresets.LEVEL[level]); - rendering_synth.set_chorus_group_nr (-1, SynthSettingsPresets.ChorusPresets.NR[level]); - } - } - - private void set_master_chorus_active (bool active) { - if (rendering_synth != null) { - rendering_synth.chorus_on (-1, active); - } - } - - private int handle_midi_event (Fluid.MIDIEvent event) { - bool handled = false; - foreach (var rack in racks) { - var voice_rack = rack as Racks.VoiceRack; - if (voice_rack != null) { - if (voice_rack.send_midi_event (event) == Fluid.OK) { - handled = true; - } - } - } - - var type = event.get_type (); - var key = event.get_key (); - - switch (type) { - case MIDI.EventType.NOTE_ON: - Application.event_bus.synth_received_note ((uint8) key, true); - break; - case MIDI.EventType.NOTE_OFF: - Application.event_bus.synth_received_note ((uint8) key, false); - break; - default: - break; - } - - if (handled) { - return Fluid.OK; - } - - return rendering_synth.handle_midi_event (event); - } - - private int handle_midi_event_from_player (Fluid.MIDIEvent event) { - int type = event.get_type (); - int chan = event.get_channel (); - int cont = event.get_control (); - int value= event.get_value (); - - if (type == MIDI.EventType.CONTROL_CHANGE) { - if ( - cont == MIDI.Control.EXPLICIT_BANK_SELECT && - (value == 1 || value == 8 || value == 16 || value == 126) - ) { - int sf_id, program_id, bank_id; - rendering_synth.get_program (chan, out sf_id, out bank_id, out program_id); - rendering_synth.program_select (chan, soundfont_id, value, program_id); - } - - if (cont == MIDI.Control.GAIN) { - if (style_gain_settings.gain[chan] >= 0) { - event.set_value (style_gain_settings.gain[chan]); - } - } - - if (cont == MIDI.Control.PAN) { - if (modulator_settings.get_mod_buffer_value (MIDI.Control.PAN, (uint8)chan) >= -64) { - event.set_value (modulator_settings.get_mod_buffer_value (10, (uint8)chan)); - } - } else { - if (modulator_settings.get_mod_buffer_value ((uint8)cont, (uint8)chan) >= 0) { - event.set_value ( - modulator_settings.get_mod_buffer_value ((uint8)cont, (uint8)chan) - ); - } - } - } - - if (type == MIDI.EventType.NOTE_ON) { - // velocity_buffer[chan] = value; - } - - return rendering_synth.handle_midi_event (event); - } - - private void halt_notes (bool except_drums) { - for (uint8 i = 0; i < 16; i++) { - if (!except_drums || (i != 9 && i != 10)) { - rendering_synth.all_notes_off (i); - } - } - } - - private void stop_all_sounds () { - for (uint8 i = 0; i < 16; i++) { - rendering_synth.all_sounds_off (i); - } - } - } -} diff --git a/src/Core/Automators/Arperggiator.vala b/src/Core/Automators/Arperggiator.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/Automators/Harmonizer.vala b/src/Core/Automators/Harmonizer.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/Drivers/AudioDriverSniffer.vala b/src/Core/Drivers/AudioDriverSniffer.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/Drivers/MIDIInputHost.vala b/src/Core/Drivers/MIDIInputHost.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/FileLoaders/StyleFileLoader.vala b/src/Core/FileLoaders/StyleFileLoader.vala deleted file mode 100644 index 963bd33c..00000000 --- a/src/Core/FileLoaders/StyleFileLoader.vala +++ /dev/null @@ -1,82 +0,0 @@ -using Ensembles.Models; - -namespace Ensembles.Core.FileLoaders { - public class StyleFileLoader : Object { - public Style[] styles; - - private List style_list; - - private string stock_style_path; - private string user_style_path; - - public StyleFileLoader () { - stock_style_path = Constants.PKGDATADIR + "/StyleFiles"; - user_style_path = Environment.get_user_special_dir (GLib.UserDirectory.DOCUMENTS) + - "/ensembles" + "/styles"; - - style_list = new List (); - - try { - Dir dir = Dir.open (stock_style_path, 0); - string? name = null; - while ((name = dir.read_name ()) != null) { - string path = Path.build_filename (stock_style_path, name); - if (path.has_suffix (".enstl") && path.contains ("@")) { - try { - var analyser = new Analysers.StyleAnalyser (path); - style_list.append (analyser.get_style ()); - } catch (StyleError e) { - Console.log (e, Console.LogLevel.WARNING); - } catch (Error e) { - Console.log ("Style file not found or invalid!", Console.LogLevel.WARNING); - } - } - } - } catch (FileError e) { - Console.log ("Stock style directory not found", Console.LogLevel.WARNING); - } - - try { - Dir dir = Dir.open (user_style_path, 0); - string? name = null; - while ((name = dir.read_name ()) != null) { - string path = Path.build_filename (user_style_path, name); - if (path.has_suffix (".enstl") && path.contains ("@")) { - try { - var analyser = new Analysers.StyleAnalyser (path); - style_list.append (analyser.get_style ()); - } catch (StyleError e) { - Console.log (e, Console.LogLevel.WARNING); - } catch (Error e) { - Console.log ("Style file not found or invalid!", Console.LogLevel.WARNING); - } - } - } - } catch (FileError e) { - Console.log ("User style directory not found", Console.LogLevel.TRACE); - } - - style_list.sort (stylecmp); - } - - /** - * Get an array of style objects which can be passed into - * style engines to play them - */ - public Style[] get_styles (out uint len) { - len = style_list.length (); - var styles = new Style[len]; - uint i = 0; - - foreach (var style in style_list) { - styles[i++] = (owned)style; - } - - return styles; - } - - private CompareFunc stylecmp = (a, b) => { - return (a.genre).ascii_casecmp (b.genre); - }; - } -} diff --git a/src/Core/MIDIPlayers/MetronomeLFOPlayer.vala b/src/Core/MIDIPlayers/MetronomeLFOPlayer.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/MIDIPlayers/SongPlayer.vala b/src/Core/MIDIPlayers/SongPlayer.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/MIDIPlayers/StyleEngine.vala b/src/Core/MIDIPlayers/StyleEngine.vala deleted file mode 100644 index 764f059f..00000000 --- a/src/Core/MIDIPlayers/StyleEngine.vala +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Core.MIDIPlayers { - /** - * ## Style Engine - * - * A style engine object can be made to play a particular Ensembles style. - * An Ensembles style is a special MIDI file with `.enstl` extension. - * The style engine can take care of style playback using the appropriate - * chords and changing the style part. - */ - public class StyleEngine : Object { - // Style data - private unowned Style style; - - // Fluid Player for style - private Fluid.Player style_player; - - // Utility synth for playing style file - private unowned Fluid.Synth utility_synth; - - // Player state - private uint32 absolute_beat_number = 0; - private uint32 absolute_measure_number = 0; - private StylePartType _current_part; - public StylePartType current_part { - get { - return _current_part; - } - private set { - _current_part = value; - Application.event_bus.style_current_part_changed (value); - } - } - private StylePartType _next_part; - private StylePartType next_part { - get { - return _next_part; - } - set { - _next_part = value; - Application.event_bus.style_next_part_changed (value); - } - } - private StylePartType current_variation; - - // Per channel note-on tracking flags - private int[] channel_note_on = { - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1 - }; - - // Chord data - private Chord chord; - private bool alt_channels_active = false; - private HashTable part_bounds_map; - - // Change queues - private bool queue_fill = false; - private bool queue_break = false; - private bool queue_chord_change = false; - private bool force_change_part = false; - private bool sync_start = false; - private bool sync_stop = false; - - // Thresholds - private uint8 time_resolution_limit = 0; - private uint measure_length; - - construct { - part_bounds_map = new HashTable (direct_hash, direct_equal); - } - - /** - * Creates a new instance of a style engine object using the given style. - * - * @param synth_provider A synth provider object - * @param style The style to use for the style engine - * @param current_tempo If this value is greater than 0 then the style - * engine will be initialized with this value. - */ - public StyleEngine (AudioEngine.SynthProvider synth_provider, Models.Style? style, - uint8? custom_tempo = 0) { - this.style = style; - utility_synth = synth_provider.utility_synth; - - style_player = new Fluid.Player (utility_synth); - style_player.set_tick_callback ( (style_engine_ref, ticks) => { - return ((StyleEngine?)style_engine_ref).parse_ticks (ticks); - }, this); - style_player.set_playback_callback ((style_engine_ref, event) =>{ - return ((StyleEngine?)style_engine_ref).parse_midi_events (event); - }, this); - - style_player.add (style.enstl_path); - - style.update_part_hash_table (part_bounds_map); - - var actual_tempo = style_player.get_midi_tempo (); - if (custom_tempo >= 40) { - style_player.set_tempo (Fluid.TempoType.EXTERNAL_BPM, (double)custom_tempo); - actual_tempo = custom_tempo; - } - - if (actual_tempo < 130) { - time_resolution_limit = 1; - } else if (actual_tempo < 182) { - time_resolution_limit = 2; - } else { - time_resolution_limit = 3; - } - - current_variation = StylePartType.VARIATION_A; - next_part = StylePartType.VARIATION_A; - current_part = StylePartType.VARIATION_A; - - halt_continuous_notes (); - measure_length = style.time_resolution * style.time_signature_n; - } - - private void halt_continuous_notes () { - for (uint channel = 0; channel < 16; channel++) { - if (channel < 9 || channel > 10) { - channel_note_on[channel] = -1; - } - } - - Application.event_bus.synth_halt_notes (true); - } - - private int parse_ticks (int ticks) { - // If there is a chord change - if (queue_chord_change) { - queue_chord_change = false; - Application.event_bus.synth_halt_notes (true); - for (uint8 channel = 0; channel < 16; channel++) { - if ((channel < 9 || channel > 10) && channel_note_on[channel] >= 0) { - resend_key (channel_note_on[channel], channel); - } - } - } - - var current_part_bounds = part_bounds_map.get (current_part); - uint current_measure_start = (uint)Math.floor ((double)ticks / (double)measure_length) * measure_length; - uint current_measure_end = (uint)Math.ceil ((double)(ticks - 1) / (double)measure_length) * measure_length; - - // Fill Ins - if (queue_fill) { - queue_fill = false; - Application.event_bus.style_break_changed (false); - if (Ensembles.settings.autofill) { - switch (current_part) { - case StylePartType.VARIATION_A: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_C; - break; - default: - break; - } - break; - case StylePartType.VARIATION_B: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_C; - break; - default: - break; - } - break; - case StylePartType.VARIATION_C: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_C; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_C; - break; - default: - break; - } - break; - case StylePartType.VARIATION_D: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_D; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_D; - break; - default: - break; - } - break; - case StylePartType.BREAK: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_C; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_D; - break; - default: - break; - } - break; - default: - break; - } - } else { - switch (current_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_C; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_D; - break; - default: - switch (next_part) { - case StylePartType.VARIATION_A: - current_part = StylePartType.FILL_A; - break; - case StylePartType.VARIATION_B: - current_part = StylePartType.FILL_B; - break; - case StylePartType.VARIATION_C: - current_part = StylePartType.FILL_C; - break; - case StylePartType.VARIATION_D: - current_part = StylePartType.FILL_D; - break; - default: - break; - } - break; - } - } - - var fill_part_bounds = part_bounds_map.get (current_part); - var fill_start = fill_part_bounds.start + (ticks - current_measure_start); - - if (Ensembles.settings.autofill && next_part < current_variation) { - halt_continuous_notes (); - } - - return style_player.seek ((int)fill_start); - } - - // Break - if (queue_break) { - queue_break = false; - Application.event_bus.style_break_changed (true); - var break_part_bounds = part_bounds_map.get (StylePartType.BREAK); - var break_start = break_part_bounds.start + (ticks - current_measure_start); - current_part = StylePartType.BREAK; - halt_continuous_notes (); - - return style_player.seek ((int)break_start); - } - - bool measure; - if (is_beat (ticks, out measure)) { - Application.event_bus.beat (measure, style.time_signature_n, style.time_signature_d); - // print ("%d %u %u %u %u\n", ticks, current_part_bounds.start, - // current_part_bounds.end, current_measure_start, current_measure_end); - // print ("%d, %u, %d\n", ticks, current_measure_end, current_part); - - if (ticks >= current_measure_end) { - if (sync_stop) { - sync_stop = false; - sync_start = true; - Application.event_bus.style_sync_changed (true); - current_part = current_variation; - next_part = current_variation; - stop (); - } - switch (current_part) { - // If we are currently in a variation - case StylePartType.VARIATION_A: - case StylePartType.VARIATION_B: - case StylePartType.VARIATION_C: - case StylePartType.VARIATION_D: - // If the next part is the same, - // wait for current measure to end - current_variation = current_part; - if (current_part == next_part) { - if (ticks >= current_part_bounds.end) { - return seek_measure (part_bounds_map.get (next_part).start); - } - } else { - current_part = next_part; - return seek_measure (part_bounds_map.get (next_part).start); - } - break; - case StylePartType.INTRO_1: - case StylePartType.INTRO_2: - case StylePartType.INTRO_3: - if (current_part == next_part) { - next_part = current_variation; - } - if (ticks >= current_part_bounds.end || force_change_part) { - current_part = next_part; - force_change_part = false; - return seek_measure (part_bounds_map.get (next_part).start); - } - break; - case StylePartType.ENDING_1: - case StylePartType.ENDING_2: - case StylePartType.ENDING_3: - if (force_change_part) { - force_change_part = false; - current_part = next_part; - return seek_measure (part_bounds_map.get (next_part).start); - } - if (ticks >= current_part_bounds.end) { - if (current_part == next_part) { - current_part = current_variation; - next_part = current_variation; - stop (); - } else { - current_part = next_part; - return seek_measure (part_bounds_map.get (next_part).start); - } - } - break; - case StylePartType.FILL_A: - case StylePartType.FILL_B: - case StylePartType.FILL_C: - case StylePartType.FILL_D: - if (current_part == StylePartType.FILL_A) { - current_variation = StylePartType.VARIATION_A; - } else if (current_part == StylePartType.FILL_B) { - current_variation = StylePartType.VARIATION_B; - } else if (current_part == StylePartType.FILL_C) { - current_variation = StylePartType.VARIATION_C; - } else if (current_part == StylePartType.FILL_D) { - current_variation = StylePartType.VARIATION_D; - } - current_part = next_part; - return seek_measure (part_bounds_map.get (next_part).start); - case StylePartType.BREAK: - if (current_part == StylePartType.INTRO_1 || - current_part == StylePartType.INTRO_2 || - current_part == StylePartType.INTRO_3 || - current_part == StylePartType.ENDING_1 || - current_part == StylePartType.ENDING_2 || - current_part == StylePartType.ENDING_3) { - current_part = current_variation; - next_part = current_variation; - } else { - current_part = next_part; - } - Application.event_bus.style_break_changed (false); - return seek_measure (part_bounds_map.get (next_part).start); - default: - break; - } - } - } - - return Fluid.OK; - } - - private int seek_measure (int ticks) { - halt_continuous_notes (); - absolute_beat_number = ticks / style.time_resolution; - absolute_measure_number = ticks / (style.time_resolution * style.time_signature_n); - return style_player.seek (ticks); - } - - private bool is_beat (int ticks, out bool measure) { - var q = ticks / style.time_resolution; - if (q != absolute_beat_number) { - absolute_beat_number = q; - - var mq = ticks / (style.time_resolution * style.time_signature_n); - if (mq != absolute_measure_number) { - absolute_measure_number = mq; - measure = true; - } else { - measure = false; - } - return true; - } - - measure = false; - - return false; - } - - private int parse_midi_events (Fluid.MIDIEvent? event) { - int type = event.get_type (); - int channel = event.get_channel (); - int control = event.get_control (); - int key = event.get_key (); - int value = event.get_value (); - int velocity = event.get_velocity (); - - // Bypass voice halt signal - if (control == 120) { - return Fluid.OK; - } - // Check if alt_channel signal is active - else if (channel == 11 && control == 82) { - alt_channels_active = value > 63; - } - - // If alt channels is enabled, that means it will disable half of - // the channels based on the scale type - if (type == MIDI.EventType.NOTE_ON && alt_channels_active) { - if (style.scale_type != chord.type) { - if (channel == 0 || - channel == 2 || - channel == 3 || - channel == 4 || - channel == 6 || - channel == 7) { - return Fluid.OK; - } - } - } else { - if (channel == 11 || - channel == 12 || - channel == 13 || - channel == 14 || - channel == 15) { - return Fluid.OK; - } - } - - var new_event = new Fluid.MIDIEvent (); - new_event.set_type (type); - new_event.set_channel (channel); - new_event.set_pitch (event.get_pitch ()); - new_event.set_program (event.get_program ()); - new_event.set_value (value); - new_event.set_velocity (velocity); - new_event.set_control (control); - - // Track which notes are on so that they can be continued after - // chord change - if (channel < 9 || channel > 10) { - if (type == MIDI.EventType.NOTE_ON) { - // The shift allows storing two intergers in one. - // This way we can store both key and velocity in one int. - // It is reteived in `resend_key ()` function - channel_note_on[channel] = key | (velocity << 16); - } else if (type == MIDI.EventType.NOTE_OFF) { - channel_note_on[channel] = -1; - } - } - - // Modify tonal channels with chord - if (channel != 9 && channel != 10 && - (type == MIDI.EventType.NOTE_ON || type == MIDI.EventType.NOTE_OFF)) { - new_event.set_key (StyleMIDIModifers.modify_key_by_chord (key, chord, - style.scale_type, alt_channels_active)); - } - else { - new_event.set_key (key); - } - - // Send data to synth - Application.event_bus.style_midi_event (new_event); - - return Fluid.OK; - } - - private void resend_key (int value, int channel) { - var new_event = new Fluid.MIDIEvent (); - new_event.set_channel (channel); - new_event.set_type (MIDI.EventType.NOTE_ON); - // Decode key and velocity from the integer value - new_event.set_key (StyleMIDIModifers.modify_key_by_chord (value & 0xFFFF, - chord, style.scale_type, alt_channels_active)); - new_event.set_velocity ((value >> 16) & 0xFFFF); - - Application.event_bus.style_midi_event (new_event); - } - - /** - * Starts style playback if not already playing. - */ - public void play () { - if (style_player.get_status () != Fluid.PlayerStatus.PLAYING) { - next_part = current_part; - Application.event_bus.synth_sounds_off (); - style_player.seek (part_bounds_map.get (current_part).start); - style_player.play (); - } - } - - /** - * Stops the style playback if already playing. - */ - public void stop () { - if (style_player.get_status () == Fluid.PlayerStatus.PLAYING) { - style_player.stop (); - halt_continuous_notes (); - Application.event_bus.beat_reset (); - } - } - - /** - * Plays the style if not already playing - * or stops the style if playing. - */ - public void toggle_play () { - if (style_player.get_status () != Fluid.PlayerStatus.PLAYING) { - play (); - } else { - stop (); - } - - sync_start = false; - sync_stop = false; - Application.event_bus.style_sync_changed (false); - } - - /** - * Change the style variation level or trigger a fill-in. - * - * @param part The style part to queue - */ - public void queue_next_part (StylePartType part) { - // Wait for measure end if already playing else instantly change part - if (style_player.get_status () == Fluid.PlayerStatus.PLAYING) { - if (part != StylePartType.INTRO_1 && - part != StylePartType.INTRO_2 && - part != StylePartType.INTRO_3 && - part != StylePartType.ENDING_1 && - part != StylePartType.ENDING_2 && - part != StylePartType.ENDING_3 && - current_part != StylePartType.INTRO_1 && - current_part != StylePartType.INTRO_2 && - current_part != StylePartType.INTRO_3 && - current_part != StylePartType.ENDING_1 && - current_part != StylePartType.ENDING_2 && - current_part != StylePartType.ENDING_3) { - if (next_part == part || Ensembles.settings.autofill) { - queue_fill = true; - } - } - - if (next_part != part) { - next_part = part; - } else if ( - current_part == StylePartType.INTRO_1 || - current_part == StylePartType.INTRO_2 || - current_part == StylePartType.INTRO_3 || - current_part == StylePartType.ENDING_1 || - current_part == StylePartType.ENDING_2 || - current_part == StylePartType.ENDING_3 - ) { - next_part = part; - force_change_part = true; - } - } else { - current_part = part; - if (part == StylePartType.VARIATION_A || - part == StylePartType.VARIATION_B || - part == StylePartType.VARIATION_C || - part == StylePartType.VARIATION_D) { - next_part = part; - current_variation = part; - } - } - - queue_break = false; - } - - /** - * Inserts a minimum voice section during playback. It could be a short - * build-up or a drop. - */ - public void break_play () { - if (style_player.get_status () == Fluid.PlayerStatus.PLAYING) { - queue_break = true; - Application.event_bus.style_break_changed (true); - } - } - - /** - * Start the style playback with chord input or stop the style - * playback on the next measure. - */ - public void sync () { - if (style_player.get_status () == Fluid.PlayerStatus.PLAYING) { - sync_start = false; - sync_stop = !sync_stop; - } else { - sync_start = !sync_start; - sync_stop = false; - } - - Application.event_bus.style_sync_changed (sync_start || sync_stop); - } - - /** - * Ask the style player to stop and wait. - * - * **Note:** This is a blocking call, meaning the function will wait until the - * style player is done playing the current measure. - * - * @param current_tempo Variable to store the current tempo - */ - public bool stop_and_wait (out uint8 current_tempo) { - current_tempo = 0; - if (style_player.get_status () == Fluid.PlayerStatus.PLAYING) { - sync_stop = true; - current_tempo = (uint8) style_player.get_bpm (); - style_player.join (); - Application.event_bus.style_sync_changed (false); - return true; - } - - return false; - } - - /** - * Change the chord of the style. - * - * This will stop all voices that are playing the current chord - * and restart them selectively with the new chord. - * - * @param chord The chord to change to - */ - public void change_chord (Chord chord) { - if (chord.root != ChordRoot.NONE) { - queue_chord_change = true; - } - - if (sync_start) { - sync_start = false; - Application.event_bus.style_sync_changed (false); - play (); - } - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/AudioPlugin.vala b/src/Core/Plugins/AudioPlugins/AudioPlugin.vala deleted file mode 100644 index dba6fed1..00000000 --- a/src/Core/Plugins/AudioPlugins/AudioPlugin.vala +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins.AudioPlugins { - /** - * The base audio plugin type. - * - * An audio plugin can be used for DSP or as voices, expanding - * the standard set of sampled voices that Ensembles come with. - */ - public abstract class AudioPlugin : Plugin { - public enum Category { - DSP, - VOICE, - UNSUPPORTED - } - - public enum Protocol { - NATIVE, - LADSPA, - LV2, - CARLA - } - - // Plugin Information - /** - * The technology this plugin is based on - */ - public Protocol protocol { get; protected set; } - public Category category { get; protected set; } - - public bool stereo_source { get; protected set; } - public bool stereo_sink { get; protected set; } - - protected float _mix_gain = 1; - public float mix_gain { - get { - return _mix_gain; - } - set { - _mix_gain = value; - } - } - - protected Port[] audio_in_ports; - protected Port[] audio_out_ports; - - /** - * Whether the audio plugin can process stereo audio. - */ - public bool stereo { get; protected set; } - - protected AudioPlugin () { - base (); - } - - public abstract void connect_source_buffer (void* in_l, void* in_r); - - public abstract void connect_sink_buffer (void* out_l, void* out_r); - - public abstract int send_midi_event (Fluid.MIDIEvent midi_event); - - /** - * Connect a port to local variable. Connect all ports before activating - * plugin - */ - public abstract void connect_port (Port port, void* data_pointer); - - /** - * Running this function will fill the sink buffers with processed audio - * as per the functionality defined in this function - */ - public abstract void process (uint32 sample_count); - - public abstract AudioPlugin duplicate () throws PluginError; - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2EvBuf.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2EvBuf.vala deleted file mode 100644 index c5bb5113..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2EvBuf.vala +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2008-2016 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -// This is a vala gobject port of LV2 evbuf.c code written by David Robillard. - -using LV2; -using LV2.URID; - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class LV2EvBuf : Object { - public uint32 capacity { get; protected set; } - private Urid atom_chunk; - private Urid atom_sequence; - // Unlike the original implementation, it was not possible to allocate - // the EvBuf struct with a custom capacity in Vala. So using a pointer - // to dynamically allocate just the buffer instead. - private Atom.Sequence* buf; - - /** - * Size of the atom event sequence - */ - public uint32 size { - get { - if (buf.atom.type != atom_sequence) { - return 0; - } - - return buf.atom.size - (uint32) sizeof (Atom.SequenceBody); - } - } - - /** - * Creates a new event buffer instance. - * - * @param capacity maximum capacity of event buffer - * @param atom_chunk URID of an atom chunk - * @param atom_sequence URID of an atom sequence - */ - public LV2EvBuf (uint32 capacity, Urid atom_chunk, Urid atom_sequence) { - return_if_fail (capacity > 0); - - Object ( - capacity: capacity - ); - - this.atom_chunk = atom_chunk; - this.atom_sequence = atom_sequence; - buf = (Atom.Sequence*) Aligned.alloc0 (sizeof (Atom.Sequence) + capacity, 1, 64); - - reset (true); - } - - /** - * "Clears" the event buffer by resetting it's size. - * - * @param input whether the buffer is associated with an input port - */ - public void reset (bool input) { - if (input) { - buf.atom.size = (uint32) sizeof (Atom.SequenceBody); - buf.atom.type = (uint32) atom_sequence; - } else { - buf.atom.size = (uint32) capacity; - buf.atom.type = (uint32) atom_chunk; - } - } - - /** - * Returns a pointer to the event sequence. - */ - public Atom.Sequence* get_buffer () { - return buf; - } - - /** - * Returns an iterator which can be used to iterate through - * the event sequence from the beginning. - */ - public Iter begin () { - return Iter () { - evbuf = this, - offset = 0 - }; - } - - /** - * Returns an iterator which can be used to iterate through - * the event sequence from the end. - */ - public Iter end () { - return Iter () { - evbuf = this, - offset = pad_size (this.size) - }; - } - - /** - * Iterator which allows iterating through the event sequence. - */ - public struct Iter { - /** - * The event buffer which this iterator is associated with. - */ - unowned LV2EvBuf evbuf; - /** - * Current position of the iterator. - */ - uint32 offset; - - /** - * If the iterator position is within the buffer size. - */ - public bool is_valid () { - return offset < evbuf.size; - } - - /** - * Get the iterator to the next event in the sequence. - */ - public Iter next () { - if (!is_valid ()) { - return this; - } - - Atom.Event* aev = atom_sequence_contents (evbuf.buf, offset); - - return Iter () { - evbuf = evbuf, - offset = offset + pad_size ( - (uint32) sizeof (Atom.Event) + aev->body.size - ) - }; - } - - /** - * Retrieve event data from the current iterator position in the - * sequence. - * - * @param frames MIDI clock times when the event is to be activated - * @param subframes MIDI clock time subdivisions - * @param size length of the event sequence - * @param data pointer to the event sequence data - */ - public bool get ( - out uint32 frames, - out uint32 subframes, - out uint32 type, - out uint32 size, - out uint8* data - ) { - frames = subframes = type = size = 0; - data = null; - - if (!is_valid ()) { - return false; - } - - Atom.Event* aev = atom_sequence_contents (evbuf.buf, offset); - - frames = (uint32) aev->time_frames; - subframes = 0; - type = aev->body.type; - size = aev->body.size; - data = atom_body (&aev->body); - return true; - } - - /** - * Wrties event data in the current iterator position in the - * sequence. - * - * @param frames MIDI clock times when the event is to be activated - * @param subframes MIDI clock time subdivisions - * @param size length of the event sequence - * @param data pointer to the event sequence data - */ - public bool write ( - uint32 frames, - uint32 subframes, - uint32 type, - uint32 size, - uint8* data - ) { - if ( - (evbuf.capacity - sizeof (Atom.Atom) - evbuf.buf.atom.size) - < (sizeof (Atom.Event) + size) - ) { - return false; - } - - Atom.Event* aev = atom_sequence_contents (evbuf.buf, offset); - aev->time_frames = frames; - aev->body.type = type; - aev->body.size = size; - - // print("writing: %ld\n", (long) aev.time_frames); - - Memory.copy (atom_body (&aev->body), data, size); - - var _size = pad_size ((uint32) sizeof (Atom.Event) + size); - evbuf.buf.atom.size += _size; - offset += _size; - - return true; - } - } - - /** - * Round up the value of "size" to the nearest multiple of 8. - */ - public static uint32 pad_size (uint32 size) { - return (size + 7) & (~7); - } - - /** - * Extract the contents of an atom sequene. - */ - public static Atom.Event* atom_sequence_contents (Atom.Sequence* atom, uint32 offset) { - return (Atom.Event*) (((uint8*) atom) + sizeof (Atom.Sequence) + offset); - } - - /** - * Extract the body of an atom. - */ - public static void* atom_body (Atom.Atom* atom) { - return (void*) (((uint8*) atom) + sizeof (Atom.Atom)); - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2Manager.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2Manager.vala deleted file mode 100644 index 7a32f5af..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2Manager.vala +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2007-2022 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - /** - * The LV2 Manager object manages LV2 Plugins. - */ - public class LV2Manager : Object { - internal static Lilv.World world = new Lilv.World (); - - internal static SyMap symap = new SyMap (); - internal static Mutex symap_lock = Mutex (); - - internal static HashTable node_map = - new HashTable ( - str_hash, - (k1, k2) => { - return k1 == k2; - } - ); - - public void load_plugins (PluginManager plugin_manager) { - assert (world != null); - - Console.log ("Loading LV2 Plugins…"); - world.load_all (); - - var plugins = world.get_all_plugins (); - - for (var iter = plugins.begin (); !plugins.is_end (iter); iter = plugins.next (iter)) { - var lilv_plugin = plugins.get (iter); - - if (lilv_plugin != null) { - try { - var plugin = new LV2Plugin (lilv_plugin, this); - plugin_manager.audio_plugins.append (plugin); - - Application.event_bus.send_initial_status (_("Loading LV2 plugin: ") + plugin.name + "…"); - } catch (PluginError e) { - Console.log ( - "Skipped LV2 plugin: " + - lilv_plugin.get_uri ().as_uri (), - Console.LogLevel.WARNING - ); - } - - Thread.usleep (20000); - } - } - - Console.log ( - "LV2 Plugins Loaded Successfully!", - Console.LogLevel.SUCCESS - ); - } - - // LV2 Feature Implementations - - // URI -> Lilv Node Mapping - internal static unowned Lilv.Node get_node_by_uri (string uri) { - if (node_map.contains (uri)) { - return node_map.get (uri); - } - - return add_node_uri (uri); - } - - internal static unowned Lilv.Node add_node_uri (string uri) { - node_map.insert (uri, new Lilv.Node.uri (world, uri)); - return node_map.get (uri); - } - - // LV2 URID - public LV2.URID.Urid map_uri (string uri) { - Lv2.LV2Manager.symap_lock.lock (); - LV2.URID.Urid urid = Lv2.LV2Manager.symap.map (uri); - Lv2.LV2Manager.symap_lock.unlock (); - return urid; - } - - public string unmap_uri (LV2.URID.Urid urid) { - Lv2.LV2Manager.symap_lock.lock (); - string uri = Lv2.LV2Manager.symap.unmap ((uint32)urid); - Lv2.LV2Manager.symap_lock.unlock (); - return uri; - } - - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2Plugin.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2Plugin.vala deleted file mode 100644 index f4734780..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2Plugin.vala +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2007-2016 David Robillard - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - --- - * Copyright (C) 2008-2012 Carl Hetherington - * Copyright (C) 2008-2017 Paul Davis - * Copyright (C) 2008-2019 David Robillard - * Copyright (C) 2012-2019 Robin Gareus - * Copyright (C) 2013-2018 John Emmas - * Copyright (C) 2013 Michael R. Fisher - * Copyright (C) 2014-2016 Tim Mayberry - * Copyright (C) 2016-2017 Damien Zammit - * Copyright (C) 2016 Nick Mainsbridge - * Copyright (C) 2017 Johannes Mueller - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * --- - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - /** - * An LV2 Plugin that can be used for DSP or as voices, expanding - * the standard set of sampled voices that Ensembles come with. - * - * LV2 is an extensible open standard for audio plugins. - * LV2 has a simple core interface, which is accompanied by extensions - * that add more advanced functionality. - */ - public class LV2Plugin : Plugins.AudioPlugins.AudioPlugin { - public string plugin_uri { get; private set; } - public string plugin_class { get; private set; } - - // LV2 Features //////////////////////////////////////////////////////// - private LV2.Feature*[] features; - private const string[] SUPPORTED_FEATURE_URIS = { - LV2.URID._map, - LV2.URID._unmap - // LV2.Worker._schedule - }; - - LV2.Feature urid_map_feature; - LV2.Feature urid_unmap_feature; - // LV2.Feature scheduler_feature; - // LV2.Feature options_feature; - - // Feature Maps - LV2.URID.UridMap urid_map; - LV2.URID.UridUnmap urid_unmap; - // LV2.Worker.Schedule schedule; - - // Plugin Worker Thread - LV2Worker worker; - Zix.Sem plugin_sem_lock; - - // Plugin Instances //////////////////////////////////////////////////// - private Lilv.Instance lv2_instance_l; // Stereo audio / Mono L Processor - private Lilv.Instance lv2_instance_r; // Mono R Processor - - // Ports /////////////////////////////////////////////////////////////// - // Control ports - public LV2ControlPort[] control_in_ports; - public float[] control_in_variables; - - // Atom ports - // MIDI - public LV2AtomPort[] atom_midi_in_ports; - public Fluid.MIDIEvent[] midi_event_buffer; - public LV2EvBuf[] atom_midi_in_variables; - public uint8 midi_input_event_count; - - public unowned Lilv.Plugin? lilv_plugin { get; protected set; } - public unowned LV2Manager? lv2_manager { get; protected set; } - - public LV2Plugin (Lilv.Plugin? lilv_plugin, LV2Manager? manager) throws PluginError { - Object ( - lilv_plugin: lilv_plugin, - lv2_manager: manager - ); - - if (!features_are_supported ()) { - throw new PluginError.UNSUPPORTED_FEATURE ("Feature not supported"); - } - - name = lilv_plugin.get_name ().as_string (); - plugin_uri = lilv_plugin.get_uri ().as_uri (); - plugin_class = lilv_plugin.get_class ().get_label ().as_string (); - author_name = lilv_plugin.get_author_name ().as_string (); - author_email = lilv_plugin.get_author_email ().as_string (); - author_homepage = lilv_plugin.get_author_homepage ().as_string (); - - protocol = Protocol.LV2; - - // Get all ports from plugin - category = get_category (); - } - - private Category get_category () { - var port_analyser = new LV2PortAnalyser (lilv_plugin); - if ( // Check if it is DSP (effect) plugin - ( - plugin_class.contains ("Amplifier") || - plugin_class.contains ("Utility") || - plugin_class.contains ("Reverb") - ) && ( - port_analyser.audio_in_port_list.length () > 0 && - port_analyser.audio_out_port_list.length () > 0 - ) - ) { - return Category.DSP; - } else if ( // Check if it is Voice (instrument) plugin - plugin_class == "Instrument Plugin" || - ( - port_analyser.n_atom_midi_in_ports > 0 && - port_analyser.audio_in_port_list.length () > 0 && - port_analyser.audio_out_port_list.length () > 0 - ) - ) { - return Category.VOICE; - } - - return Category.UNSUPPORTED; - } - - /** - * Creates a workable instance of the lv2 plugin. - * Instantiate must be called on this object before connecting any ports - * or running the plugin. - */ - public override void instantiate () { - if (lv2_instance_l == null) { - Console.log("Instantiating LV2 Plugin %s, with URI: %s".printf(name, plugin_uri)); - active = false; - setup_workers (); - create_features (); - - lv2_instance_l = lilv_plugin.instantiate (AudioEngine.Synthesizer.sample_rate, features); - // Check if plugin is mono - if (!stereo) { - lv2_instance_r = lilv_plugin.instantiate (AudioEngine.Synthesizer.sample_rate, features); - } - - create_ports (); - allocate_control_ports (); - allocate_midi_port_buffers (); - build_ui (); - } - } - - private void allocate_control_ports () { - control_in_variables = new float[control_in_ports.length]; - for (uint32 i = 0; i < control_in_ports.length; i++) { - control_in_variables[i] = control_in_ports[i].default_value; - connect_port (control_in_ports[i], &control_in_variables[i]); - } - } - - private void allocate_midi_port_buffers () { - atom_midi_in_variables = new LV2EvBuf [atom_midi_in_ports.length]; - - for (uint8 i = 0; i < atom_midi_in_ports.length; i++) { - atom_midi_in_variables[i] = new LV2EvBuf ( - AudioEngine.Synthesizer.get_buffer_size (), - lv2_manager.map_uri (LV2.Atom._Chunk), - lv2_manager.map_uri (LV2.Atom._Sequence) - ); - - atom_midi_in_variables[i].reset (true); - - connect_port (atom_midi_in_ports[i], atom_midi_in_variables[i].get_buffer ()); - } - } - - public override AudioPlugin duplicate () throws PluginError { - return new LV2Plugin (lilv_plugin, lv2_manager); - } - - protected override void activate () { - if (lv2_instance_l != null) { - lv2_instance_l.activate (); - } - - if (lv2_instance_r != null) { - lv2_instance_r.activate (); - } - } - - protected override void deactivate () { - if (lv2_instance_l != null) { - lv2_instance_l.deactivate (); - } - - if (lv2_instance_r != null) { - lv2_instance_r.deactivate (); - } - } - - public override void connect_source_buffer (void* in_l, void* in_r) { - if (stereo) { - // Stereo plugin - for (uint8 i = 0; i < audio_in_ports.length; i++) { - if ((i & 1) == 0) { // If even - if (lv2_instance_l != null) { - lv2_instance_l.connect_port ( - audio_in_ports[i].index, - in_l - ); - } - } else { - if (lv2_instance_l != null) { - lv2_instance_l.connect_port ( - audio_in_ports[i].index, - in_r - ); - } - } - } - } else { - lv2_instance_l.connect_port ( - audio_in_ports[0].index, - in_l - ); - - lv2_instance_r.connect_port ( - audio_in_ports[0].index, - in_r - ); - } - } - - public override void connect_sink_buffer (void* out_l, void* out_r) { - if (stereo) { - for (uint8 i = 0; i < audio_out_ports.length; i++) { - if ((i & 1) == 0) { // If even - if (lv2_instance_l != null) { - lv2_instance_l.connect_port ( - audio_out_ports[i].index, - out_l - ); - } - } else { - if (lv2_instance_l != null) { - lv2_instance_l.connect_port ( - audio_out_ports[i].index, - out_r - ); - } - } - } - } else { - lv2_instance_l.connect_port ( - audio_out_ports[0].index, - out_l - ); - - lv2_instance_r.connect_port ( - audio_out_ports[0].index, - out_r - ); - } - } - - public override void connect_port (Port port, void* data_pointer) { - if (lv2_instance_l != null) { - lv2_instance_l.connect_port (port.index, data_pointer); - } - - if (lv2_instance_r != null) { - lv2_instance_r.connect_port (port.index, data_pointer); - } - } - - public override int send_midi_event (Fluid.MIDIEvent midi_event) { - if (active) { - // print ("midi, %d\n", midi_event.get_key ()); - if (midi_event_buffer == null) { - midi_event_buffer = new Fluid.MIDIEvent [AudioEngine.Synthesizer.get_buffer_size ()]; - } - - midi_event_buffer[midi_input_event_count] = new Fluid.MIDIEvent (); - midi_event_buffer[midi_input_event_count].set_type (midi_event.get_type ()); - midi_event_buffer[midi_input_event_count].set_key (midi_event.get_key ()); - midi_event_buffer[midi_input_event_count++].set_velocity (midi_event.get_velocity ()); - - return Fluid.OK; - } - - return Fluid.FAILED; - } - - private void fill_event_buffers () { - for (uint16 p = 0; p < atom_midi_in_ports.length; p++) { - // unowned LV2AtomPort port = atom_midi_in_ports[p]; - unowned LV2EvBuf evbuf = atom_midi_in_variables[p]; - evbuf.reset (true); - var iter = evbuf.begin (); - - // print ("midi buffer size %d\n", midi_event_buffer.length); - - for (uint8 i = 0; i < midi_input_event_count; i++) { - unowned Fluid.MIDIEvent midi_event = midi_event_buffer[i]; - var buffer = new uint8[3]; - buffer[0] = (uint8) midi_event.get_type (); - buffer[1] = (uint8) midi_event.get_key (); - buffer[2] = (uint8) midi_event.get_velocity (); - iter.write ( - (uint32) ( - new DateTime.now_utc ().to_unix () - AudioEngine.Synthesizer.get_process_start_time () - ), - 0, - (uint32) lv2_manager.map_uri (LV2.MIDI._MidiEvent), - 3, - buffer - ); - } - } - - midi_input_event_count = 0; - } - - public override void process (uint32 sample_count) { - fill_event_buffers (); - - if (lv2_instance_l != null) { - lv2_instance_l.run (sample_count); - } - - if (lv2_instance_r != null) { - lv2_instance_r.run (sample_count); - } - } - - private void setup_workers () { - Zix.Sem.init (out plugin_sem_lock, 1); - worker = new LV2Worker (plugin_sem_lock, true); - worker.handle = (LV2.Handle) this; - } - - /** - * Create plugin features - */ - private void create_features () { - urid_map = LV2.URID.UridMap (); - urid_map.map = lv2_manager.map_uri; - - urid_unmap = LV2.URID.UridUnmap (); - urid_unmap.unmap = lv2_manager.unmap_uri; - - // schedule = LV2.Worker.Schedule (); - // schedule.schedule_work = worker.schedule; - - features = new LV2.Feature* [2]; - urid_map_feature = register_feature (LV2.URID._map, &urid_map); - urid_unmap_feature = register_feature (LV2.URID._unmap, &urid_unmap); - // scheduler_feature = register_feature (LV2.Worker._schedule, &schedule); - - features[0] = &urid_map_feature; - features[1] = &urid_unmap_feature; - // features[2] = &scheduler_feature; - } - - private bool features_are_supported () { - var lilv_features = lilv_plugin.get_required_features (); - for (var iter = lilv_features.begin (); !lilv_features.is_end (iter); - iter = lilv_features.next (iter)) { - string required_feature = lilv_features.get (iter).as_uri (); - print ("checking: %s\n", required_feature); - if (!feature_supported (required_feature)) { - return false; - } - } - - return true; - } - - private bool feature_supported (string feature) { - for (uint8 i = 0; i < SUPPORTED_FEATURE_URIS.length; i++) { - if (feature == SUPPORTED_FEATURE_URIS[i]) { - return true; - } - } - - return false; - } - - private LV2.Feature register_feature (string uri, void* data) { - return LV2.Feature () { - URI = uri, - data = data - }; - } - - private void create_ports () { - var port_analyser = new LV2PortAnalyser (lilv_plugin); - - var n_audio_in_ports = port_analyser.audio_in_port_list.length (); - audio_in_ports = new Port[n_audio_in_ports]; - - // If there's more than one audio in port then presume that - // the plugin is stereo - stereo = n_audio_in_ports > 1; - for (uint32 p = 0; p < n_audio_in_ports; p++) { - unowned LV2Port _port = - port_analyser.audio_in_port_list.nth_data (p); - audio_in_ports[p] = new LV2Port ( - _port.name, - _port.index, - _port.properties, - _port.symbol, - _port.turtle_token - ); - } - - var n_audio_out_ports = port_analyser.audio_out_port_list.length (); - audio_out_ports = new Port[n_audio_out_ports]; - for (uint32 p = 0; p < n_audio_out_ports; p++) { - unowned LV2Port _port = - port_analyser.audio_out_port_list.nth_data (p); - audio_out_ports[p] = new LV2Port ( - _port.name, - _port.index, - _port.properties, - _port.symbol, - _port.turtle_token - ); - } - - var n_control_in_ports = port_analyser.control_in_port_list.length (); - control_in_ports = new LV2ControlPort[n_control_in_ports]; - for (uint32 p = 0; p < n_control_in_ports; p++) { - unowned LV2ControlPort _port = - port_analyser.control_in_port_list.nth_data (p); - control_in_ports[p] = new LV2ControlPort ( - _port.name, - _port.index, - _port.properties, - _port.symbol, - _port.turtle_token, - _port.min_value, - _port.max_value, - _port.default_value, - _port.step - ); - } - - var n_atom_in_ports = port_analyser.atom_in_port_list.length (); - // MIDI Ports - atom_midi_in_ports = new LV2AtomPort[port_analyser.n_atom_midi_in_ports]; - - for (uint32 p = 0, i = 0; p < n_atom_in_ports; p++) { - unowned LV2AtomPort _port = - port_analyser.atom_in_port_list.nth_data (p); - if ((_port.flags & LV2AtomPort.Flags.SUPPORTS_MIDI_EVENT) > LV2AtomPort.Flags.NONE) { - atom_midi_in_ports[i++] = new LV2AtomPort ( - _port.name, - _port.index, - _port.properties, - _port.symbol, - _port.turtle_token, - _port.flags - ); - } - } - } - - private void build_ui () { - var box = new Gtk.Box ( - Gtk.Orientation.HORIZONTAL, - 8 - ) { - spacing = 4, - valign = Gtk.Align.CENTER, - homogeneous = control_in_ports.length < 4 - }; - - bool is_ui_required = false; - - if (control_in_ports.length > 0) { - for (uint i = 0; i < control_in_ports.length; i++) { - var plugin_control = new Shell.Plugins.AudioPlugins.Widgets.AudioPluginControl ( - control_in_ports[i], - & (control_in_variables[i]), - control_in_ports.length > 3 ? Gtk.IconSize.NORMAL : Gtk.IconSize.LARGE - ); - box.append (plugin_control); - } - - is_ui_required = true; - } - - if (is_ui_required) { - ui = box; - } - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2PortAnalyser.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2PortAnalyser.vala deleted file mode 100644 index e288fe5c..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2PortAnalyser.vala +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2007-2016 David Robillard - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - --- - * Copyright (C) 2008-2012 Carl Hetherington - * Copyright (C) 2008-2017 Paul Davis - * Copyright (C) 2008-2019 David Robillard - * Copyright (C) 2012-2019 Robin Gareus - * Copyright (C) 2013-2018 John Emmas - * Copyright (C) 2013 Michael R. Fisher - * Copyright (C) 2014-2016 Tim Mayberry - * Copyright (C) 2016-2017 Damien Zammit - * Copyright (C) 2016 Nick Mainsbridge - * Copyright (C) 2017 Johannes Mueller - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * --- - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - /** - * The LV2PortAnalyser object is used to analyse LV2 ports - * and provide port descriptors which the plugin object can the use to - * create the ports. - */ - public class LV2PortAnalyser : Object { - /** - * The Lilv Plugin whose ports are being described. - */ - unowned Lilv.Plugin lilv_plugin { get; protected set; } - - /** - * These ports represents a buffer for storing dry audio. - */ - public List audio_in_port_list; - /** - * These ports represents a buffer for storing wet audio. - */ - public List audio_out_port_list; - /** - * These ports represents basic control input ports. - */ - public List control_in_port_list; - /** - * These ports represents basic control output ports. - */ - public List control_out_port_list; - /** - * These ports represents atom input ports. - */ - public List atom_in_port_list; - /** - * These ports represents atom output ports. - */ - public List atom_out_port_list; - - // Atom ports classifications - public uint16 n_atom_midi_in_ports { get; private set; } - public uint16 n_atom_midi_out_ports { get; private set; } - - /** - * Creates a new `LV2PortAnalyser` instance. - * - * @param lilv_plugin the lilv plugin object whose ports to describe - */ - public LV2PortAnalyser (Lilv.Plugin lilv_plugin) { - this.lilv_plugin = lilv_plugin; - fetch_ports (); - } - - private void fetch_ports () { - audio_in_port_list = new List (); - audio_out_port_list = new List (); - control_in_port_list = new List (); - atom_in_port_list = new List (); - atom_out_port_list = new List (); - - var n_ports = lilv_plugin.get_num_ports (); - for (uint32 i = 0; i < n_ports; i++) { - // Get port from plugin - unowned Lilv.Port port = lilv_plugin.get_port_by_index (i); - - var name = lilv_plugin.port_get_name (port).as_string (); - print ("port: " + name + "\n"); - var symbol = lilv_plugin.port_get_symbol (port).as_string (); - var turtle_token = lilv_plugin.port_get_symbol (port).get_turtle_token (); - var properties = get_port_properties (port); - - // Plugin class flags - bool is_audio_port = false; - bool is_input_port = false; - bool is_output_port = false; - bool is_control_port = false; - bool is_atom_port = false; - - // Get all classes associated with this port - unowned Lilv.Nodes port_classes = lilv_plugin.port_get_classes (port); - - for (var class_iter = port_classes.begin (); - !port_classes.is_end (class_iter); - class_iter = port_classes.next (class_iter)) { - switch (port_classes.get (class_iter).as_string ()) { - case LV2.Core._AudioPort: - is_audio_port = true; - break; - case LV2.Core._ControlPort: - is_control_port = true; - break; - case LV2.Atom._AtomPort: - is_atom_port = true; - break; - case LV2.Core._InputPort: - is_input_port = true; - break; - case LV2.Core._OutputPort: - is_output_port = true; - break; - } - } - - if (is_audio_port) { - if (is_input_port) { - audio_in_port_list.append (new LV2Port ( - name, - i, - properties, - symbol, - turtle_token - )); - } else if (is_output_port) { - audio_out_port_list.append (new LV2Port ( - name, - i, - properties, - symbol, - turtle_token - )); - } - } else if (is_control_port) { - Lilv.Node default_value; - Lilv.Node min_value; - Lilv.Node max_value; - - lilv_plugin.port_get_range (port, out default_value, out min_value, out max_value); - - if (is_input_port) { - control_in_port_list.append (new LV2ControlPort ( - name, - i, - properties, - symbol, - turtle_token, - min_value.as_float (), - max_value.as_float (), - default_value.as_float (), - 0.1f - )); - } - } else if (is_atom_port) { - var flags = LV2AtomPort.Flags.NONE; - Lilv.Nodes buffer_types = lilv_plugin.port_get_value ( - port, - LV2Manager.get_node_by_uri (LV2.Atom._bufferType) - ); - - Lilv.Nodes atom_supports = lilv_plugin.port_get_value ( - port, - LV2Manager.get_node_by_uri (LV2.Atom._supports) - ); - - if ( - buffer_types.contains ( - LV2Manager.get_node_by_uri (LV2.Atom._Sequence) - ) - ) { - flags |= LV2AtomPort.Flags.SEQUENCE; - - if (atom_supports.contains ( - LV2Manager.get_node_by_uri (LV2.MIDI._MidiEvent) - )) { - flags |= LV2AtomPort.Flags.SUPPORTS_MIDI_EVENT; - } - } - - if (is_input_port) { - atom_in_port_list.append ( - new LV2AtomPort ( - name, - i, - properties, - symbol, - turtle_token, - flags - ) - ); - - if ( - (flags & LV2AtomPort.Flags.SUPPORTS_MIDI_EVENT) > - LV2AtomPort.Flags.NONE - ) { - n_atom_midi_in_ports++; - } - } else if (is_output_port) { - atom_out_port_list.append ( - new LV2AtomPort ( - name, - i, - properties, - symbol, - turtle_token, - flags - ) - ); - - if ( - (flags & LV2AtomPort.Flags.SUPPORTS_MIDI_EVENT) > - LV2AtomPort.Flags.NONE - ) { - n_atom_midi_out_ports++; - } - } - } - } - } - - - private string[] get_port_properties (Lilv.Port port) { - var prop_list = new List (); - - var properties = lilv_plugin.port_get_properties (port); - - for (var props_iter = properties.begin (); - !properties.is_end (props_iter); - props_iter = properties.next (props_iter)) { - var prop = properties.get (props_iter).as_string (); - print ("port prop:" + prop + "\n"); - prop_list.append (prop); - } - - var n = prop_list.length (); - - var props = new string[n]; - for (uint32 i = 0; i < n; i++) { - props[i] = prop_list.nth_data (i) + ""; // Make owned - } - return props; - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2SyMap.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2SyMap.vala deleted file mode 100644 index 201b23e2..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2SyMap.vala +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2011-2022 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class SyMap { - private List symbols; - public SyMap () { - symbols = new List (); - } - - public uint32 map (string sym) { - int index = search (sym); - - if (index < 0) { - symbols.append (sym); - return symbols.length () - 1; - } - - return (uint32) index; - } - - public string unmap (uint32 index) { - return symbols.nth_data (index); - } - - private int search (string sym) { - int index = -1; - for (int i = 0; i < symbols.length (); i++) { - if (symbols.nth_data (i) == sym) { - index = i; - } - } - - return index; - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/LV2Worker.vala b/src/Core/Plugins/AudioPlugins/Lv2/LV2Worker.vala deleted file mode 100644 index 672d9a31..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/LV2Worker.vala +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2008-2016 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -// This is a vala gobject port of Jalv worker.c code written by David Robillard. - -using LV2; - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class LV2Worker : Object { - private Zix.Ring requests; ///< Requests to the worker - private Zix.Ring responses; ///< Responses from the worker - private void* response; - private unowned Zix.Sem plugin_instance_lock; - private bool queue_exit; - private Zix.Sem sem; - private Zix.Thread thread; - public Handle handle; - private unowned Worker.Interface? iface; - public bool threaded { get; private set; } - - private const uint MAX_PACKET_SIZE = 4096U; - - public LV2Worker (Zix.Sem? plugin_instance_lock, bool threaded) { - this.threaded = threaded; - responses = new Zix.Ring (null, MAX_PACKET_SIZE);; - response = Posix.calloc (1, MAX_PACKET_SIZE);; - this.plugin_instance_lock = plugin_instance_lock; - queue_exit = false; - - responses.mlock (); - - if (threaded && launch () != SUCCESS) { - free (response); - } - } - - ~LV2Worker () { - exit (); - free (response); - } - - private static Worker.Status write_packet (Zix.Ring target, [CCode (type="const uint32_t")] uint32 size, [CCode (type="const void*")] void* data) { - Zix.Ring.Transaction tx = target.begin_write (); - if (target.amend_write (tx, &size, (uint32) sizeof(uint32)) != Zix.Status.SUCCESS || - target.amend_write (tx, data, size) != Zix.Status.SUCCESS) { - return Worker.Status.ERR_NO_SPACE; - } - - target.commit_write (tx); - return Worker.Status.SUCCESS; - } - - private static Worker.Status respond (Worker.RespondHandle handle, [CCode (type="const uint32_t")] uint32 size, [CCode (type="const void*")] void* data) { - return write_packet (((LV2Worker) handle).responses, size, data); - } - - public Zix.ThreadResult func () { - void* buf = null; - - while (true) { - // Wait for a request - sem.wait (); - if (queue_exit) { - break; - } - - // Read the size header of request - uint32 size = 0; - requests.read (&size, (uint32) sizeof(uint32)); - - // Reallocate buffer to allocate request if necessary - void* new_buf = realloc (buf, size); - if (new_buf != null) { - // Read request into buffer - buf = new_buf; - requests.read (buf, size); - - // Lock and dispatch request to plugin's work handler - plugin_instance_lock.wait (); - iface.work ( - handle, - respond, - (LV2.Worker.RespondHandle) this, - size, buf - ); - plugin_instance_lock.post (); - } else { - // Reallocation failed, skip request to avoid corrupting ring - requests.skip (size); - } - } - - free (buf); - return (Zix.ThreadResult) null; - } - - public Zix.Status launch () { - var st = Zix.Sem.init (out sem, 0); - - if (st != Zix.Status.SUCCESS) { - return st; - } else { - st = Zix.Thread.create (out thread, MAX_PACKET_SIZE, func); - - if (st != Zix.Status.SUCCESS) { - return st; - } - } - - var _requests = new Zix.Ring (null, MAX_PACKET_SIZE); - - if (_requests == null) { - thread.join (); - sem.destroy (); - st = Zix.Status.NO_MEM; - return st; - } - - _requests.mlock (); - requests = (owned) _requests; - return st; - } - - public void start (Worker.Interface iface, Handle handle) { - this.iface = iface; - this.handle = handle; - } - - public void exit () { - if (threaded) { - queue_exit = true; - sem.post (); - thread.join (); - threaded = false; - } - } - - public Worker.Status schedule (uint32 size, void* data) { - var st = Worker.Status.SUCCESS; - - if (size == 0) { - st = Worker.Status.ERR_UNKNOWN; - } - - if (threaded) { - // Schedule a request to be executed by the worker thread - st = write_packet (requests, size, data); - if (st == Worker.Status.SUCCESS) { - sem.post (); - } - } else { - plugin_instance_lock.wait (); - st = iface.work ( - handle, - respond, - (LV2.Worker.RespondHandle) this, - size, - data - ); - plugin_instance_lock.post (); - } - - return st; - } - - public void emit_responses (Handle lv2_handle) { - const uint32 size_size = (uint32) sizeof(uint32); - - if (responses != null) { - uint32 size = 0U; - while (responses.read (&size, size_size) == size_size) { - if (responses.read (response, size) == size) { - iface.work_response (lv2_handle, size, response); - } - } - } - } - - public void end_run () { - if (iface != null && iface.end_run != null) { - iface.end_run (handle); - } - } - } -} - -// These are required as the library Worker doesn't yet have typedefs for these function pointers in Interface -[CCode (cname = " interface_work_t", has_target = false)] -extern delegate Worker.Status InterfaceWorkFunc (Handle instance, Worker.RespondFunc respond, Worker.RespondHandle handle, uint32 size, void* data); -[CCode (cname = " interface_work_reponse_t", has_target = false)] -extern delegate Worker.Status InterfaceWorkResponseFunc (Handle instance, uint32 size, [CCode (type="const void*")] void* body); -[CCode (cname = " interface_end_run_t", has_target = false)] -extern delegate Worker.Status InterfaceEndRunFunc (Handle instance); diff --git a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2AtomPort.vala b/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2AtomPort.vala deleted file mode 100644 index e9b222c6..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2AtomPort.vala +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class LV2AtomPort : LV2Port { - [Flags] - public enum Flags { - NONE, - SEQUENCE, - SUPPORTS_MIDI_EVENT - } - - public Flags flags { get; private set; } - - public LV2AtomPort (string name, uint32 index, owned string[] properties, - string symbol, string turtle_token = "", Flags flags) { - base (name, index, properties, symbol, turtle_token); - this.flags = flags; - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2ControlPort.vala b/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2ControlPort.vala deleted file mode 100644 index c950b74f..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2ControlPort.vala +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class LV2ControlPort : LV2Port { - public float default_value { get; private set; } - public float min_value { get; private set; } - public float max_value { get; private set; } - public float step { get; private set; } - - public LV2ControlPort (string name, uint32 index, owned string[] properties, - string symbol, string turtle_token = "", float min_value = 0, float max_value = 1, - float default_value = 0, float step = 0.1f) { - base (name, index, properties, symbol, turtle_token); - this.default_value = default_value; - this.min_value = min_value; - this.max_value = max_value; - this.step = step; - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2Port.vala b/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2Port.vala deleted file mode 100644 index 5edc48a8..00000000 --- a/src/Core/Plugins/AudioPlugins/Lv2/Ports/LV2Port.vala +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins.AudioPlugins.Lv2 { - public class LV2Port : Port { - public string[] properties { get; private set; } - public string symbol { get; private set; } - public string turtle_token { get; private set; } - - public LV2Port (string name, uint32 index, owned string[] properties, - string symbol, string turtle_token = "") { - base (name, index); - this.symbol = symbol; - this.turtle_token = turtle_token; - } - } -} diff --git a/src/Core/Plugins/AudioPlugins/Port.vala b/src/Core/Plugins/AudioPlugins/Port.vala deleted file mode 100644 index 5fafee73..00000000 --- a/src/Core/Plugins/AudioPlugins/Port.vala +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins.AudioPlugins { - public class Port : Object { - public string name { get; private set; } - public uint32 index { get; private set; } - - public Port (string name, uint32 index) { - this.name = name; - this.index = index; - } - } -} diff --git a/src/Core/Plugins/Plugin.vala b/src/Core/Plugins/Plugin.vala deleted file mode 100644 index 4a74e7a8..00000000 --- a/src/Core/Plugins/Plugin.vala +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins { - /** - * The base plugin type. - * - * A plugin is used to add additional functionality - * or features to ensembles. - */ - public abstract class Plugin : Object { - /** - * Name of the plugin. - */ - public string name { get; protected set; } - /** - * Name of the author of this plugin. - */ - public string author_name { get; protected set; } - /** - * Email address of the author of this plugin. - */ - public string author_email { get; protected set; } - /** - * Homepage or the main URL of the plugin. - */ - public string author_homepage { get; protected set; } - /** - * The license associated with this plugin. - */ - public string license { get; protected set; } - - private bool _active; - - /** - * The plugin will only work if it's active. - */ - public bool active { - get { - return _active; - } - set { - _active = value; - if (value) { - activate (); - } else { - deactivate (); - } - } - } - - private Gtk.Widget _ui = null; - - /** - * Plugin's own UI which can be displayed inside the window management - * framework of Ensembles. - * - * If the plugin doesn't come with an UI then this value will be `null`. - */ - public Gtk.Widget ui { - get { - return _ui; - } - protected set { - _ui = value; - } - } - - protected Plugin () { - active = false; - instantiate (); - } - - ~Plugin () { - active = false; - } - - /** - * This function is called when the plugin is instantiated. - * This just means that the plugin data is created. A Plugin cannot be - * used without instantiation. - */ - public abstract void instantiate (); - - protected abstract void activate (); - - protected abstract void deactivate (); - } -} diff --git a/src/Core/Plugins/PluginManager.vala b/src/Core/Plugins/PluginManager.vala deleted file mode 100644 index 96d46b73..00000000 --- a/src/Core/Plugins/PluginManager.vala +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Core.Plugins { - /** - * ## Plugin Manager - * - * Plugins add additional functionality to Ensembles externally. - * - * The following types of plugins may be supported: - * - Audio Plugins - * - Style Plugins - * - Display Theme Plugins - * - Functional Plugins - */ - public class PluginManager : Object { - /** - * Audio Plugins (Voices and DSP) - */ - public List audio_plugins; - - private AudioPlugins.Lv2.LV2Manager lv2_audio_plugin_manager; - - construct { - // Load Audio Plugins ////////////////////////////////////////////// - audio_plugins = new List (); - - // Load LADSPA Plugins - - // Load LV2 Plugins - lv2_audio_plugin_manager = new AudioPlugins.Lv2.LV2Manager (); - lv2_audio_plugin_manager.load_plugins (this); - - // Load Carla Plugins - - // Load Native Plugins - } - } -} diff --git a/src/Core/Racks/DSPRack.vala b/src/Core/Racks/DSPRack.vala deleted file mode 100644 index c5df3ad9..00000000 --- a/src/Core/Racks/DSPRack.vala +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Core.Racks { - /** - * ## DSP Rack - * - * This defines a rack which gets populated with DSP plugins. - * The final output of the synthesizer / voice plugin is processed by all - * the plugins in this rack. - * - * _**Note:** DSP - Digital Signal Processing_ - */ - public class DSPRack : Rack { - public DSPRack () { - Object ( - rack_type: AudioPlugin.Category.DSP - ); - } - } -} diff --git a/src/Core/Racks/Rack.vala b/src/Core/Racks/Rack.vala deleted file mode 100644 index 6581b764..00000000 --- a/src/Core/Racks/Rack.vala +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Core.Racks { - /** - * Racks can be populated with plugins which are then used to - * process audio - */ - public abstract class Rack : Object { - protected List plugins; - - public bool active = true; - - public AudioPlugin.Category rack_type { get; protected set; } - - // Sound buffers - float[] aud_buf_dry_l; - float[] aud_buf_dry_r; - float[] aud_buf_mix_l; - float[] aud_buf_mix_r; - - construct { - plugins = new List (); - } - - public unowned List get_plugins () { - return plugins; - } - - /** - * Add a plugin to the end of the rack - * - * @param plugin AudioPlugin to append to the rack - */ - public void append (AudioPlugin plugin) throws PluginError { - if (plugin.category != rack_type) { - throw new PluginError.INVALID_CATEGORY ("Attempted to add plugin of different category"); - } - - plugins.append (plugin); - plugin.instantiate (); - - connect_audio_ports ((int) plugins.length () - 1); - } - - /** - * Add a plugin to the specified position - * - * @param plugin AudioPlugin to add to the rack - * @param position The position in the stack where the plugin must - * be added - */ - public void insert (AudioPlugin plugin, int position) throws PluginError { - if (plugin.category != rack_type) { - throw new PluginError.INVALID_CATEGORY ("Attempted to add plugin of different category"); - } - - plugins.insert (plugin, position); - plugin.instantiate (); - - connect_audio_ports (position); - } - - /** - * Remove a plugin from a given position on the rack - * - * @param position position in the stack from where the plugin will - * be removed - */ - public void remove (int position) { - AudioPlugin plugin = plugins.nth_data (position); - plugin.active = false; - plugins.remove (plugin); - - connect_audio_ports (); - } - - /** - * Remove a plugin from the rack - * - * @param plugin plugin to remove - */ - public void remove_data (AudioPlugin plugin) { - plugin.active = false; - plugins.remove (plugin); - - connect_audio_ports (); - } - - /** - * Activate or deactivate a plugin - * - * A plugin will not process audio if it's not active - * - * @param position The position of the plugin in the rack - * @param active Whether the plugin should be enabled or not - */ - public virtual void set_plugin_active (int position, bool active = true) { - AudioPlugin plugin = plugins.nth_data (position); - plugin.active = active; - } - - /** - * Process a given stereo audio buffer using plugins - * - * @param len Length of buffer to process - * @param buffer_in_l Audio input buffer for left channel - * @param buffer_in_r Audio input buffer for right channel - * @param buffer_out_l Audio output buffer for left channel - * @param buffer_out_r Audio output buffer for right channel - */ - public void process_audio (int len, float* buffer_in_l, float* buffer_in_r, - float** buffer_out_l, float** buffer_out_r) { - // If the main buffers aren't initialised - // initialize them - if (aud_buf_dry_l == null || aud_buf_dry_r == null || - aud_buf_mix_l == null || aud_buf_mix_r == null) { - aud_buf_dry_l = new float[len]; - aud_buf_dry_r = new float[len]; - aud_buf_mix_l = new float[len]; - aud_buf_mix_r = new float[len]; - } - - // Fill main dry buffers with audio data - for (int i = 0; i < len; i++) { - aud_buf_dry_l[i] = buffer_in_l[i]; - aud_buf_dry_r[i] = buffer_in_r[i]; - } - - // Process audio using plugins - run_plugins (len); - - // Fill out buffers using wet mix; - // Wet mix has been copied to the dry buffer; See below - for (int i = 0; i < len; i++) { - * (* buffer_out_l + i) = aud_buf_dry_l[i]; - * (* buffer_out_r + i) = aud_buf_dry_r[i]; - } - } - - protected void run_plugins (uint32 sample_count) { - if (active) { - var rack_thread = new Thread ("rack_thread", () => { - foreach (AudioPlugin plugin in plugins) { - if (plugin.active) { - // Have the plugin process the audio buffer - plugin.process (sample_count); - - // Copy wet audio to dry buffer as per mix amount - for (uint32 j = 0; j < sample_count; j++) { - aud_buf_dry_l[j] = Utils.Math.map_range_unclampedf ( - plugin.mix_gain, - 0, - 1, - aud_buf_dry_l[j], - aud_buf_mix_l[j] - ); - - aud_buf_dry_r[j] = Utils.Math.map_range_unclampedf ( - plugin.mix_gain, - 0, - 1, - aud_buf_dry_r[j], - aud_buf_mix_r[j] - ); - } - - // Next plugin ready to run - } - } - }); - - rack_thread.join (); - } - } - - protected void connect_audio_ports (int change_index = -1) { - var was_active = active; - active = false; - - foreach (AudioPlugin plugin in plugins) { - plugin.connect_source_buffer (aud_buf_dry_l, aud_buf_dry_r); - plugin.connect_sink_buffer (aud_buf_mix_l, aud_buf_mix_r); - } - - active = was_active; - Application.event_bus.rack_reconnected (this, change_index); - } - } -} diff --git a/src/Core/Racks/VoiceRack.vala b/src/Core/Racks/VoiceRack.vala deleted file mode 100644 index d61d3f14..00000000 --- a/src/Core/Racks/VoiceRack.vala +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Core.Racks { - /** - * ## Voice Rack - * - * This rack supports voice / instrument plugins. - * - * Every individual voice plugin can be associated with an instance - * of DSP Rack. - */ - public class VoiceRack : Rack { - private List dsp_racks; - - /** - * Whether only a single instance of a plugin is allowed to process audio. - */ - public bool exclusive_mode { get; set; } - - public VoiceRack () { - Object ( - rack_type: AudioPlugin.Category.VOICE, - exclusive_mode: true - ); - - dsp_racks = new List (); - } - - public int send_midi_event (Fluid.MIDIEvent event) { - if (!active) { - return Fluid.FAILED; - } - - bool handled = false; - foreach (var plugin in plugins) { - if (plugin.active && plugin.send_midi_event (event) == Fluid.OK) { - handled = true; - } - } - - return handled ? Fluid.OK : Fluid.FAILED; - } - - public override void set_plugin_active (int position, bool active = true) { - base.set_plugin_active (position, active); - - if (active && exclusive_mode) { - uint n = plugins.length (); - for (uint i = 0; i < n; i++) { - if (i != position) { - plugins.nth_data (i).active = false; - } - } - } - } - } -} diff --git a/src/Core/SamplingPads/SamplePlayer.vala b/src/Core/SamplingPads/SamplePlayer.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/SamplingPads/SampleRecorder.vala b/src/Core/SamplingPads/SampleRecorder.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Core/StateManager/RegistryManager.vala b/src/Core/StateManager/RegistryManager.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Interfaces/MediaKeyListener.vala b/src/Interfaces/MediaKeyListener.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Interfaces/SoundIndicator.vala b/src/Interfaces/SoundIndicator.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Models/Chord.vala b/src/Models/Chord.vala deleted file mode 100644 index 8eff8031..00000000 --- a/src/Models/Chord.vala +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Models { - /** - * Represents root note of chord - */ - public enum ChordRoot { - C = 0, - CS = 1, - D = 2, - EF = 3, - E = 4, - F = 5, - FS = 6, - G = -5, - AF = -4, - A = -3, - BF = -2, - B = -1, - NONE = -6; - } - - /** - * Represents the type of chord - */ - public enum ChordType { - MAJOR = 0, - MINOR = 1, - DIMINISHED = 2, - SUSPENDED_2 = 3, - SUSPENDED_4 = 4, - AUGMENTED = 5, - SIXTH = 6, - SEVENTH = 7, - MAJOR_7TH = 8, - MINOR_7TH = 9, - ADD_9TH = 10, - NINTH = 11 - } - - /** - * Represents musical chords - */ - public struct Chord { - public ChordRoot root; - public ChordType type; - } -} diff --git a/src/Models/Registry.vala b/src/Models/Registry.vala deleted file mode 100644 index 7725e61e..00000000 --- a/src/Models/Registry.vala +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Models { - public struct Registry { - public Voice voice_r1; - public Voice voice_r2; - public Voice voice_l; - public Style style; - public uint8 tempo; - public int8 transpose; - public bool transpose_active; - public int8 octave_shift; - public bool octave_shift_active; - public uint8 reverb_level; - public bool reverb_active; - public uint8 chorus_level; - public bool chorus_active; - public bool accomp_active; - public bool layer_active; - public bool split_active; - public uint8 harmonizer_type; - public bool harmnonizer_active; - public uint8 arpeggiator_type; - public bool arperggiator_active; - } -} diff --git a/src/Models/Style.vala b/src/Models/Style.vala deleted file mode 100644 index 5190639e..00000000 --- a/src/Models/Style.vala +++ /dev/null @@ -1,85 +0,0 @@ - -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Models { - /** - * Data structure representing auto accompaniment styles - */ - public struct Style { - public string name; - public string genre; - public uint8 tempo; - public uint8 time_signature_n; - public uint8 time_signature_d; - public uint32 time_resolution; - public string enstl_path; - public string copyright_notice; - public ChordType scale_type; - public StylePart[] parts; - - public string to_string () { - string output = "Style Object ->\n╭──────────────────────────────────────────────────────────╮\n"; - output += "│ \x1B[1m%s\x1B[0m, Genre: %s".printf (name, genre); - for (uint8 i = 0; i < 48 - (name.length + genre.length); i++) {output += " ";} - output += "│\n"; - output += "│ Tempo: %u BPM, Time Signature: %u/%u".printf (tempo, time_signature_n, time_signature_d); - for ( - uint8 i = 0; - i < 27 - (tempo.to_string ().length + time_signature_n.to_string ().length - + time_signature_d.to_string ().length); - i++ - ) { output += " "; } - output += "│\n"; - output += "│ " + copyright_notice; - if (copyright_notice.length < 60) { - for ( - uint8 i = 0; - i < 57 - copyright_notice.length; - i++ - ) { output += " "; } - output += "│"; - } - - output += "\n┢━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┪\n"; - output += "┃PART │ 1 │ 2 │ 3 │ 4 ┃\n"; - output += "┡┅┅┅┅┅┅┅┅┅┅┿┅┅┅┅┅┅┅┅┅┅┅┿┅┅┅┅┅┅┅┅┅┅┅┿┅┅┅┅┅┅┅┅┅┅┅┿┅┅┅┅┅┅┅┅┅┅┅┩\n"; - output += "│INTRO │ %07u │ %07u │ %07u │ N/A │\n".printf ( - 2 * parts[0].time_stamp, 2 * parts[1].time_stamp, 2 * parts[2].time_stamp - ); - output += "│VARIATION │ %07u │ %07u │ %07u │ %07u │\n".printf ( - 2 * parts[4].time_stamp, 2 * parts[6].time_stamp, 2 * parts[8].time_stamp, 2 * parts[10].time_stamp - ); - output += "│FILL-IN │ %07u │ %07u │ %07u │ %07u │\n".printf ( - 2 * parts[5].time_stamp, 2 * parts[7].time_stamp, 2 * parts[9].time_stamp, 2 * parts[11].time_stamp - ); - output += "│BREAK │ %07u │ N/A │ N/A │ N/A │\n".printf ( - 2 * parts[3].time_stamp - ); - output += "│ENDING │ %07u │ %07u │ %07u │ N/A │\n".printf ( - 2 * parts[12].time_stamp, 2 * parts[14].time_stamp, 2 * parts[16].time_stamp - ); - output += "│EOS │ %07u │ %07u │ %07u │ N/A │\n".printf ( - 2 * parts[13].time_stamp, 2 * parts[15].time_stamp, 2 * parts[17].time_stamp - ); - output += "╰──────────┴───────────┴───────────┴───────────┴───────────╯"; - - return output; - } - - /** - * Updates a given hash table with `StylePartType` as the key and the - * part bounds as the value. - */ - public void update_part_hash_table (HashTable? hash_table) { - for (uint8 i = 0; i < parts.length; i++) { - hash_table.insert (parts[i].style_part_type, StylePartBounds () { - start = (int)parts[i].time_stamp, - end = (int)parts[i + 1].time_stamp - }); - } - } - } -} diff --git a/src/Models/StylePart.vala b/src/Models/StylePart.vala deleted file mode 100644 index 974945b1..00000000 --- a/src/Models/StylePart.vala +++ /dev/null @@ -1,31 +0,0 @@ - -namespace Ensembles.Models { - public enum StylePartType { - INTRO_1, - INTRO_2, - INTRO_3, - BREAK, - VARIATION_A, - VARIATION_B, - VARIATION_C, - VARIATION_D, - FILL_A, - FILL_B, - FILL_C, - FILL_D, - ENDING_1, - ENDING_2, - ENDING_3, - EOS - } - - public struct StylePart { - public uint time_stamp; - public StylePartType style_part_type; - } - - public struct StylePartBounds { - public int start; - public int end; - } -} diff --git a/src/Models/Voice.vala b/src/Models/Voice.vala deleted file mode 100644 index fabfb761..00000000 --- a/src/Models/Voice.vala +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - /** - * Describes which hand is playing the voice - */ - public enum VoiceHandPosition { - /** Playing on left hand of split */ - LEFT, - /** Playing on right hand of split as the main voice*/ - RIGHT, - /** Playing on the right side of split layered with main voice */ - RIGHT_LAYERED - } - - namespace Models { - /** - * Data structure representing voice or timbre data in soundfont - */ - public struct Voice { - public uint index; - public uint8 bank; - public uint8 preset; - public string name; - public string category; - public string sf_path; - } - } -} diff --git a/src/Services/EventBus.vala b/src/Services/EventBus.vala deleted file mode 100644 index 196888be..00000000 --- a/src/Services/EventBus.vala +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Services { - public class EventBus : Object { - // Shell Events - public signal void size_change (); - public signal bool show_menu (bool show); - public signal void menu_shown (bool shown); - public signal void send_initial_status (string status); - - // Homescreen - public signal void voice_chosen (VoiceHandPosition position, string name, uint8 bank, uint8 preset); - - // Core Events - public signal void arranger_ready (); - - public signal void beat (bool measure, uint8 time_signature_n, uint8 time_signature_d); - public signal void beat_reset (); - - // Style Player Events - public signal void style_change (Style style); - public signal void style_chord_changed (Ensembles.Models.Chord chord); - public signal int style_midi_event (Fluid.MIDIEvent event); - public signal void style_play_toggle (); - public signal void style_set_part (StylePartType part); - public signal void style_current_part_changed (StylePartType part_type); - public signal void style_next_part_changed (StylePartType part_type); - public signal void style_sync (); - public signal void style_sync_changed (bool active); - public signal void style_break (); - public signal void style_break_changed (bool active); - - // Synthesizer - public signal int synth_send_event (Fluid.MIDIEvent event); - public signal void synth_received_note (uint8 note_number, bool on); - public signal void synth_halt_notes (bool except_drums = false); - public signal void synth_sounds_off (); - public signal int synth_midi_reroute (int channel, Fluid.MIDIEvent event); - - // Plugins - public signal void rack_reconnected (Core.Racks.Rack rack, int change_index); - public signal void show_plugin_ui (Core.Plugins.AudioPlugins.AudioPlugin plugin); - } -} diff --git a/src/Services/Theme.vala b/src/Services/Theme.vala deleted file mode 100644 index c5373b9c..00000000 --- a/src/Services/Theme.vala +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Services { - public class Theme { - static Gtk.CssProvider main_css_provider; - static Gtk.CssProvider complimentary_css_provider; - - public static string theme_color = "blueberry"; - - public static void init_theme () { - weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()); - default_theme.add_resource_path ("/com/github/subhadeepjasu/ensembles/icons"); - - GLib.Value theme_value = GLib.Value (GLib.Type.STRING); - - var gtk_settings = Gtk.Settings.get_default (); - var granite_settings = Granite.Settings.get_default (); - - gtk_settings.get_property ("gtk-theme-name", ref theme_value); - - var system_theme = theme_value.get_string (); - - if (system_theme.has_prefix ("io.elementary.")) { - theme_color = theme_value.get_string ().replace ("io.elementary.stylesheet.", ""); - } else { - gtk_settings.set_property ("gtk-icon-theme-name", "elementary"); - } - - if (main_css_provider == null) { - main_css_provider = new Gtk.CssProvider (); - main_css_provider.load_from_resource ("/com/github/subhadeepjasu/ensembles/theme/Application.css"); - Gtk.StyleContext.add_provider_for_display ( - Gdk.Display.get_default (), - main_css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - } - - // Set colors that are complimentary to the accent color for special cases - if (complimentary_css_provider == null) { - complimentary_css_provider = new Gtk.CssProvider (); - complimentary_css_provider.load_from_data (AccentColors.get_complementary (theme_color)); - - Gtk.StyleContext.add_provider_for_display ( - Gdk.Display.get_default (), - complimentary_css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - } - - gtk_settings.gtk_application_prefer_dark_theme = ( - granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK - ); - - granite_settings.notify["prefers-color-scheme"].connect (() => { - gtk_settings.gtk_application_prefer_dark_theme = ( - granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK - ); - }); - } - } -} diff --git a/src/Services/Settings.vala b/src/Settings.vala similarity index 69% rename from src/Services/Settings.vala rename to src/Settings.vala index 2cdbcc7c..d055ce34 100644 --- a/src/Services/Settings.vala +++ b/src/Settings.vala @@ -3,12 +3,24 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -namespace Ensembles.Services { +namespace Ensembles { public class Settings : GLib.Settings { - public Settings () { + private Settings () { Object (schema_id: Constants.APP_ID); } + private static Settings _instance; + + public static Settings instance { + get { + if (_instance == null) { + _instance = new Settings (); + } + + return _instance; + } + } + public string version { owned get { return get_string ("version"); } set { set_string ("version", value); } @@ -68,19 +80,19 @@ namespace Ensembles.Services { set { set_boolean ("autofill", value); } } - /** - * How chord should be interpreted from the keyboard input. - * - * - `SPLIT_LONG`: Determine chord from multiple keys only on left side - * of split point - * - `SPLIT_SHORT`: Determine chord from two fingers only on left side - * of split point - * - `FULL_RANGE`: Determine chord from multiple fingers from any place - * on the keyboard - */ - public Core.Analysers.ChordAnalyser.ChordDetectionMode chord_detection_mode { - get { return get_enum ("chord-detection-mode"); } - set { set_enum ("chord-detection-mode", value); } - } + // /** + // * How chord should be interpreted from the keyboard input. + // * + // * - `SPLIT_LONG`: Determine chord from multiple keys only on left side + // * of split point + // * - `SPLIT_SHORT`: Determine chord from two fingers only on left side + // * of split point + // * - `FULL_RANGE`: Determine chord from multiple fingers from any place + // * on the keyboard + // */ + // public Core.Analysers.ChordAnalyser.ChordDetectionMode chord_detection_mode { + // get { return get_enum ("chord-detection-mode"); } + // set { set_enum ("chord-detection-mode", value); } + // } } } diff --git a/src/Shell/Dialogs/PluginWindow.vala b/src/Shell/Dialogs/PluginWindow.vala deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Shell/Dialogs/PowerDialog.vala b/src/Shell/Dialogs/PowerDialog.vala deleted file mode 100644 index 7e767bae..00000000 --- a/src/Shell/Dialogs/PowerDialog.vala +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Dialog { - public class PowerDialog : Gtk.Window { - private Gtk.Image power_icon; - private Gtk.Label header; - private Gtk.Label message; - private Gtk.Button log_out_button; - private Gtk.Button cancel_button; - private Gtk.Button shutdown_button; - - construct { - build_ui (); - build_events (); - } - - public PowerDialog (Gtk.Window main_window) { - Object ( - modal: true, - transient_for: main_window, - decorated: false - ); - } - - private void build_ui () { - add_css_class ("pseudowindow-actual"); - - var main_grid = new Gtk.Grid () { - row_spacing = 8, - column_spacing = 8, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - main_grid.add_css_class ("pseudowindow"); - main_grid.add_css_class ("opaque"); - - set_child (main_grid); - - power_icon = new Gtk.Image.from_icon_name ("system-shutdown") { - width_request = 48, - height_request = 48, - icon_size = Gtk.IconSize.LARGE - }; - main_grid.attach (power_icon, 0, 0, 1, 2); - - header = new Gtk.Label (_("Are you sure you want to Shut Down?")) { - halign = Gtk.Align.START - }; - header.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - main_grid.attach (header, 1, 0, 4); - - message = new Gtk.Label (_("This will turn off this device")) { - halign = Gtk.Align.START - }; - main_grid.attach (message, 1, 1, 4); - - log_out_button = new Gtk.Button.with_label (_("Log Out Instead…")); - main_grid.attach (log_out_button, 1, 2, 2); - - cancel_button = new Gtk.Button.with_label (_("Cancel")); - main_grid.attach (cancel_button, 3, 2); - - shutdown_button = new Gtk.Button.with_label (_("Shut Down")); - shutdown_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); - main_grid.attach (shutdown_button, 4, 2); - } - - private void build_events () { - cancel_button.clicked.connect (() => { - this.close (); - }); - - log_out_button.clicked.connect (() => { - Application.main_window.close (); - }); - - shutdown_button.clicked.connect (() => { - Application.main_window.close (); - }); - - ((Gtk.Widget) this).realize.connect (() => { - var display = Gdk.Display.get_default (); - var monitor = display.get_monitor_at_surface (get_surface ()); - set_default_size (monitor.geometry.width, monitor.geometry.height); - }); - } - } -} diff --git a/src/Shell/Layouts/AssignablesBoard.vala b/src/Shell/Layouts/AssignablesBoard.vala deleted file mode 100644 index 9efdf056..00000000 --- a/src/Shell/Layouts/AssignablesBoard.vala +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class AssignablesBoard : Gtk.Grid { - construct { - add_css_class ("panel"); - } - - public AssignablesBoard () { - Object ( - hexpand: true, - vexpand: true - ); - } - } -} diff --git a/src/Shell/Layouts/DesktopLayout.vala b/src/Shell/Layouts/DesktopLayout.vala deleted file mode 100644 index 9b9ee985..00000000 --- a/src/Shell/Layouts/DesktopLayout.vala +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class DesktopLayout : Gtk.Grid { - private weak Layouts.AssignablesBoard assignables_board; - private weak Layouts.InfoDisplay info_display; - private weak Layouts.SynthControlPanel synth_control_panel; - private weak Layouts.VoiceNavPanel voice_nav_panel; - private weak Layouts.MixerBoard mixer_board; - private weak Layouts.SamplerPadsPanel sampler_pads_panel; - private weak Layouts.StyleControlPanel style_control_panel; - private weak Layouts.RegistryPanel registry_panel; - private weak Layouts.KeyboardPanel keyboard; - private Gtk.Button start_button; - - private Gtk.CenterBox top_row; - private Gtk.CenterBox middle_row; - private Gtk.Grid bottom_row; - private Gtk.CenterBox bottom_row_box; - private Gtk.Revealer bottom_row_revealer; - - construct { - build_ui (); - } - - public DesktopLayout (Layouts.AssignablesBoard? assignables_board, - Layouts.InfoDisplay? info_display, - Layouts.SynthControlPanel? synth_control_panel, - Layouts.VoiceNavPanel? voice_nav_panel, - Layouts.MixerBoard? mixer_board, - Layouts.SamplerPadsPanel? sampler_pads_panel, - Layouts.StyleControlPanel? style_control_panel, - Layouts.RegistryPanel? registry_panel, - Layouts.KeyboardPanel? keyboard) { - Object ( - width_request: 812, - height_request: 600, - hexpand: true, - vexpand: true - ); - this.assignables_board = assignables_board; - this.info_display = info_display; - this.synth_control_panel = synth_control_panel; - this.voice_nav_panel = voice_nav_panel; - this.mixer_board = mixer_board; - this.sampler_pads_panel = sampler_pads_panel; - this.style_control_panel = style_control_panel; - this.registry_panel = registry_panel; - this.keyboard = keyboard; - } - - private void build_ui () { - top_row = new Gtk.CenterBox () { - hexpand = true, - vexpand = true - }; - attach (top_row, 0, 0); - - middle_row = new Gtk.CenterBox () { - hexpand = true, - vexpand = true - }; - attach (middle_row, 0, 1); - - - bottom_row_revealer = new Gtk.Revealer () { - reveal_child = true, - hexpand = true - }; - attach (bottom_row_revealer, 0, 2); - - bottom_row = new Gtk.Grid () { - hexpand = true - }; - bottom_row_revealer.set_child (bottom_row); - - bottom_row_box = new Gtk.CenterBox (); - bottom_row.attach (bottom_row_box, 0, 0); - - var start_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - start_button_box.add_css_class ("panel"); - bottom_row_box.set_center_widget (start_button_box); - - start_button = new Gtk.Button.from_icon_name ("media-playback-start-symbolic") { - width_request = 64, - height_request = 32 - }; - start_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); - start_button.remove_css_class ("image-button"); - start_button.clicked.connect (() => { - Application.event_bus.style_play_toggle (); - }); - - start_button_box.append (start_button); - start_button_box.append (new Gtk.Label (_("START/STOP")) { opacity = 0.5 }); - } - - public void reparent () { - assignables_board.unparent (); - info_display.unparent (); - synth_control_panel.unparent (); - voice_nav_panel.unparent (); - mixer_board.unparent (); - sampler_pads_panel.unparent (); - style_control_panel.unparent (); - registry_panel.unparent (); - keyboard.unparent (); - - top_row.set_start_widget (assignables_board); - top_row.set_center_widget (info_display); - info_display.fill_screen = false; - top_row.set_end_widget (synth_control_panel); - - middle_row.set_start_widget (voice_nav_panel); - middle_row.set_center_widget (mixer_board); - middle_row.set_end_widget (sampler_pads_panel); - - bottom_row_box.set_start_widget (style_control_panel); - bottom_row_box.set_end_widget (registry_panel); - bottom_row.attach (keyboard, 0, 1); - } - } -} diff --git a/src/Shell/Layouts/Display/AudioPluginPicker.vala b/src/Shell/Layouts/Display/AudioPluginPicker.vala deleted file mode 100644 index 906922d6..00000000 --- a/src/Shell/Layouts/Display/AudioPluginPicker.vala +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.Plugins.AudioPlugins; -using Ensembles.Shell.Widgets.Display; - -namespace Ensembles.Shell.Layouts.Display { - public class AudioPluginPicker : WheelScrollableWidget { - public AudioPlugin.Category category { - get; - private set; - } - private Gtk.ListBox main_list_box; - - public AudioPluginPicker (AudioPlugin.Category category) { - Object ( - width_request: 500, - hexpand: false, - vexpand: true, - orientation: Gtk.Orientation.VERTICAL, - spacing: 8 - ); - this.category = category; - - build_ui (); - build_events (); - populate (Application.arranger_workstation.get_audio_plugins ()); - } - - public void build_ui () { - var plugin_picker_header = new Gtk.Label (_("A U D I O P L U G I N S")) { - halign = Gtk.Align.END, - opacity = 0.5, - margin_end = 14, - margin_top = 24 - }; - plugin_picker_header.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - append (plugin_picker_header); - - var scrollable = new Gtk.ScrolledWindow () { - hexpand = true, - vexpand = true - }; - append (scrollable); - - main_list_box = new Gtk.ListBox () { - selection_mode = Gtk.SelectionMode.NONE - }; - main_list_box.add_css_class ("plugin-list"); - scrollable.set_child (main_list_box); - } - - private void build_events () { - - } - - public void populate (List plugins) { - for (uint16 i = 0; i < plugins.length (); i++) { - if (plugins.nth_data (i).category == category) { - var menu_item = new DSPMenuItem (plugins.nth_data (i), - Application.arranger_workstation.get_main_dsp_rack ()); - main_list_box.insert (menu_item, -1); - } - } - - min_value = 0; - max_value = (int) plugins.length () - 1; - } - } -} diff --git a/src/Shell/Layouts/Display/DSPScreen.vala b/src/Shell/Layouts/Display/DSPScreen.vala deleted file mode 100644 index 9eb76eb8..00000000 --- a/src/Shell/Layouts/Display/DSPScreen.vala +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets.Display; -using Ensembles.Models; -using Ensembles.Core.Plugins.AudioPlugins; -using Ensembles.Core.Racks; - -namespace Ensembles.Shell.Layouts.Display { - public class DSPScreen : DisplayWindow { - private Gtk.Button plugin_picker_button; - private Gtk.Switch dsp_switch; - private Adw.Flap main_flap; - private Gtk.ListBox main_list_box; - private AudioPluginPicker plugin_picker; - - private unowned DSPRack rack; - - public DSPScreen (DSPRack rack) { - base (_("Main DSP Rack"), _("Add Effects to the Rack to apply them globally")); - - this.rack = rack; - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - dsp_switch = new Gtk.Switch () { - valign = Gtk.Align.CENTER, - halign = Gtk.Align.CENTER - }; - dsp_switch.active = true; - add_to_header (dsp_switch); - - plugin_picker_button = new Gtk.Button.from_icon_name ("plugin-add-symbolic") { - width_request = 36, - tooltip_text = _("Add plugin to DSP Rack") - }; - add_to_header (plugin_picker_button); - - main_flap = new Adw.Flap () { - fold_policy = Adw.FlapFoldPolicy.ALWAYS, - flap_position = Gtk.PackType.END - }; - main_flap.add_css_class ("plugin-flap"); - append (main_flap); - - plugin_picker = new AudioPluginPicker (Core.Plugins.AudioPlugins.AudioPlugin.Category.DSP); - main_flap.set_flap (plugin_picker); - - var scrollable = new Gtk.ScrolledWindow () { - hexpand = true, - vexpand = true, - margin_start = 8, - margin_end = 8, - margin_top = 8, - margin_bottom = 8 - }; - scrollable.add_css_class ("can-be-blurred"); - main_flap.set_content (scrollable); - - main_list_box = new Gtk.ListBox () { - selection_mode = Gtk.SelectionMode.NONE - }; - main_list_box.add_css_class ("menu-box"); - scrollable.set_child (main_list_box); - } - - private void build_events () { - dsp_switch.notify["active"].connect (() => { - rack.active = dsp_switch.active; - }); - - plugin_picker_button.clicked.connect (() => { - main_flap.reveal_flap = !main_flap.reveal_flap; - }); - - main_flap.notify.connect ((param) => { - if (param.name == "reveal-flap") { - Idle.add (() => { - if (main_flap.reveal_flap) { - main_flap.get_content ().add_css_class ("blurred"); - } else { - main_flap.get_content ().remove_css_class ("blurred"); - } - - return false; - }); - } - }); - - Application.event_bus.rack_reconnected.connect ((rack, change_index) => { - if (rack.rack_type == AudioPlugin.Category.DSP) { - populate (rack.get_plugins (), change_index); - } - - main_flap.reveal_flap = false; - }); - } - - public void populate (List plugins, int highlight_index) { - while (main_list_box.get_first_child () != null) { - main_list_box.remove (main_list_box.get_first_child ()); - } - - for (uint16 i = 0; i < plugins.length (); i++) { - var menu_item = new DSPInstanceMenuItem (plugins.nth_data (i), this); - main_list_box.insert (menu_item, -1); - - if (highlight_index == i) { - menu_item.capture_attention (); - } - } - - min_value = 0; - max_value = (int) plugins.length () - 1; - } - - public void delete_plugin_item (DSPInstanceMenuItem item) { - unowned AudioPlugin plugin = item.plugin; - main_list_box.remove (item); - rack.remove_data (plugin); - } - } -} diff --git a/src/Shell/Layouts/Display/HomeScreen.vala b/src/Shell/Layouts/Display/HomeScreen.vala deleted file mode 100644 index ebe9549f..00000000 --- a/src/Shell/Layouts/Display/HomeScreen.vala +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts.Display { - public class HomeScreen : Gtk.Box { - private Gtk.Button power_button; - private Gtk.Button style_button; - private Gtk.Button voice_l_button; - private Gtk.Button voice_r1_button; - private Gtk.Button voice_r2_button; - - private Gtk.Button dsp_button; - private Gtk.Label dsp_status; - private Gtk.Button recorder_button; - private Gtk.Label recorder_status; - - private Gtk.Label selected_style_label; - private Gtk.Label selected_voice_l_label; - private Gtk.Label selected_voice_r1_label; - private Gtk.Label selected_voice_r2_label; - - private Gtk.Label tempo_label; - private Gtk.Label measure_label; - private Gtk.Label beat_label; - private Gtk.Label transpose_label; - private Gtk.Label octave_label; - private Gtk.Label chord_label; - private Gtk.Label chord_flat_label; - private Gtk.Label chord_type_label; - - public signal void change_screen (string screen_name); - - public HomeScreen () { - Object ( - orientation: Gtk.Orientation.VERTICAL, - spacing: 0 - ); - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - add_css_class ("homescreen"); - - var links_section = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - height_request = 200 - }; - links_section.add_css_class ("homescreen-links-section"); - append(links_section); - - // Top Links /////////////////////////////////////////////////////////////////////////////////////////////// - - var top_link_panel = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - height_request = 56, - hexpand = true - }; - top_link_panel.add_css_class ("homescreen-link-panel-top"); - links_section.append (top_link_panel); - - if (Application.kiosk_mode) { - power_button = new Gtk.Button.from_icon_name ("system-shutdown-symbolic") { - height_request = 48, - width_request = 32 - }; - power_button.add_css_class ("homescreen-link-panel-top-button"); - top_link_panel.append (power_button); - } - - style_button = new Gtk.Button (); - top_link_panel.append (style_button); - style_button.add_css_class ("homescreen-link-panel-top-button"); - - var style_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - height_request = 48, - hexpand = true - }; - style_button.set_child (style_button_box); - - var style_label = new Gtk.Label (_("Style")) { - halign = Gtk.Align.CENTER - }; - style_button_box.append (style_label); - style_label.add_css_class ("homescreen-link-panel-top-button-header"); - - selected_style_label = new Gtk.Label (_("Undefined")) { - ellipsize = Pango.EllipsizeMode.MIDDLE, - halign = Gtk.Align.CENTER - }; - style_button_box.append (selected_style_label); - selected_style_label.add_css_class ("homescreen-link-panel-top-button-subheader"); - - voice_l_button = new Gtk.Button (); - top_link_panel.append (voice_l_button); - voice_l_button.add_css_class ("homescreen-link-panel-top-button"); - - var voice_l_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - height_request = 48, - hexpand = true - }; - voice_l_button.set_child (voice_l_button_box); - - var voice_l_label = new Gtk.Label (_("Voice L")) { - halign = Gtk.Align.CENTER - }; - voice_l_button_box.append (voice_l_label); - voice_l_label.add_css_class ("homescreen-link-panel-top-button-header"); - - selected_voice_l_label = new Gtk.Label (_("Undefined")) { - ellipsize = Pango.EllipsizeMode.MIDDLE, - halign = Gtk.Align.CENTER - }; - voice_l_button_box.append (selected_voice_l_label); - selected_voice_l_label.add_css_class ("homescreen-link-panel-top-button-subheader"); - - voice_r1_button = new Gtk.Button (); - top_link_panel.append (voice_r1_button); - voice_r1_button.add_css_class ("homescreen-link-panel-top-button"); - - var voice_r1_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - height_request = 48, - hexpand = true - }; - voice_r1_button.set_child (voice_r1_button_box); - - var voice_r1_label = new Gtk.Label (_("Voice R1")) { - halign = Gtk.Align.CENTER - }; - voice_r1_button_box.append (voice_r1_label); - voice_r1_label.add_css_class ("homescreen-link-panel-top-button-header"); - - selected_voice_r1_label = new Gtk.Label (_("Undefined")) { - ellipsize = Pango.EllipsizeMode.MIDDLE, - halign = Gtk.Align.CENTER - }; - voice_r1_button_box.append (selected_voice_r1_label); - selected_voice_r1_label.add_css_class ("homescreen-link-panel-top-button-subheader"); - - voice_r2_button = new Gtk.Button (); - top_link_panel.append (voice_r2_button); - voice_r2_button.add_css_class ("homescreen-link-panel-top-button"); - - var voice_r2_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - height_request = 48, - hexpand = true - }; - voice_r2_button.set_child (voice_r2_button_box); - - var voice_r2_label = new Gtk.Label (_("Voice R2")) { - halign = Gtk.Align.CENTER - }; - voice_r2_button_box.append (voice_r2_label); - voice_r2_label.add_css_class ("homescreen-link-panel-top-button-header"); - - selected_voice_r2_label = new Gtk.Label (_("Undefined")) { - ellipsize = Pango.EllipsizeMode.MIDDLE, - halign = Gtk.Align.CENTER - }; - voice_r2_button_box.append (selected_voice_r2_label); - selected_voice_r2_label.add_css_class ("homescreen-link-panel-top-button-subheader"); - - // Bottom Links //////////////////////////////////////////////////////////////////////////////////////////// - var bottom_links_panel = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - vexpand = true, - hexpand = true, - valign = Gtk.Align.END - }; - links_section.append (bottom_links_panel); - bottom_links_panel.add_css_class ("homescreen-link-panel-bottom"); - - dsp_button = new Gtk.Button () { - valign = Gtk.Align.END, - halign = Gtk.Align.START - }; - dsp_button.add_css_class ("homescreen-link-panel-bottom-button"); - bottom_links_panel.append (dsp_button); - - var dsp_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - dsp_button.set_child (dsp_box); - - dsp_box.append (new Gtk.Separator (Gtk.Orientation.VERTICAL)); - dsp_box.append (new Gtk.Label (_("Main Effect Rack - "))); - - dsp_status = new Gtk.Label (_("0 Effects in Use")); - dsp_status.add_css_class ("homescreen-link-panel-bottom-button-status"); - dsp_box.append (dsp_status); - - recorder_button = new Gtk.Button () { - valign = Gtk.Align.END, - halign = Gtk.Align.START - }; - recorder_button.add_css_class ("homescreen-link-panel-bottom-button"); - bottom_links_panel.append (recorder_button); - - var recorder_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - recorder_button.set_child (recorder_box); - - recorder_box.append (new Gtk.Separator (Gtk.Orientation.VERTICAL)); - recorder_box.append (new Gtk.Label (_("Recorder - "))); - - recorder_status = new Gtk.Label (_("No Project Open")); - recorder_status.add_css_class ("homescreen-link-panel-bottom-button-status"); - recorder_box.append (recorder_status); - - // Bottom Panel //////////////////////////////////////////////////////////////////////////////////////////// - var status_panel = new Gtk.Grid () { - vexpand = true, - hexpand = true, - column_homogeneous = true, - height_request = 175 - }; - append (status_panel); - status_panel.add_css_class ("homescreen-panel-status"); - - var tempo_header = new Gtk.Label(_("Tempo")); - tempo_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (tempo_header, 0, 0); - - var measure_header = new Gtk.Label(_("Measure")); - measure_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (measure_header, 1, 0); - - var beat_header = new Gtk.Label(_("Time Signature")); - beat_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (beat_header, 2, 0); - - var transpose_header = new Gtk.Label(_("Transpose")); - transpose_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (transpose_header, 3, 0); - - var octave_header = new Gtk.Label(_("Octave")); - octave_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (octave_header, 4, 0); - - var chord_header = new Gtk.Label(_("Chord")); - chord_header.add_css_class ("homescreen-panel-status-header"); - status_panel.attach (chord_header, 5, 0); - - var tempo_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 1) { - halign = Gtk.Align.CENTER - }; - status_panel.attach (tempo_box, 0, 1); - - tempo_label = new Gtk.Label ("120"); - tempo_label.add_css_class ("homescreen-panel-status-label"); - tempo_box.append (tempo_label); - - var tempo_unit_label = new Gtk.Label ("BPM") { - margin_bottom = 8 - }; - tempo_unit_label.add_css_class ("homescreen-panel-status-label-small"); - tempo_box.append (tempo_unit_label); - - measure_label = new Gtk.Label("0"); - measure_label.add_css_class ("homescreen-panel-status-label"); - status_panel.attach (measure_label, 1, 1); - - beat_label = new Gtk.Label("4 / 4"); - beat_label.add_css_class ("homescreen-panel-status-label"); - status_panel.attach (beat_label, 2, 1); - - transpose_label = new Gtk.Label("0"); - transpose_label.add_css_class ("homescreen-panel-status-label"); - status_panel.attach (transpose_label, 3, 1); - - octave_label = new Gtk.Label("0"); - octave_label.add_css_class ("homescreen-panel-status-label"); - status_panel.attach (octave_label, 4, 1); - - var chord_grid = new Gtk.Grid () { - halign = Gtk.Align.CENTER - }; - status_panel.attach (chord_grid, 5, 1); - - chord_label = new Gtk.Label(_("C")); - chord_label.add_css_class ("homescreen-panel-status-label"); - chord_grid.attach (chord_label, 0, 0, 1, 2); - - chord_flat_label = new Gtk.Label ("#"); - chord_flat_label.add_css_class ("homescreen-panel-status-label-small"); - chord_grid.attach (chord_flat_label, 1, 0); - - chord_type_label = new Gtk.Label ("m"); - chord_type_label.add_css_class ("homescreen-panel-status-label-small"); - chord_grid.attach (chord_type_label, 1, 1); - } - - private void build_events () { - style_button.clicked.connect (() => { - change_screen ("style"); - }); - - voice_l_button.clicked.connect (() => { - change_screen ("voice-l"); - }); - - voice_r1_button.clicked.connect (() => { - change_screen ("voice-r1"); - }); - - voice_r2_button.clicked.connect (() => { - change_screen ("voice-r2"); - }); - - dsp_button.clicked.connect (() => { - change_screen ("dsp"); - }); - - if (Application.kiosk_mode) { - power_button.clicked.connect (() => { - var power_dialog = new Dialog.PowerDialog (Application.main_window); - power_dialog.present (); - power_dialog.show (); - }); - } - - Application.event_bus.style_change.connect ((style) => { - print ("%s\n", style.name); - selected_style_label.set_text (style.name); - }); - - Application.event_bus.voice_chosen.connect ((position, name) => { - switch (position) { - case VoiceHandPosition.LEFT: - selected_voice_l_label.set_text (name); - break; - case VoiceHandPosition.RIGHT: - selected_voice_r1_label.set_text (name); - break; - case VoiceHandPosition.RIGHT_LAYERED: - selected_voice_r2_label.set_text (name); - break; - } - }); - } - } -} diff --git a/src/Shell/Layouts/Display/PluginScreen.vala b/src/Shell/Layouts/Display/PluginScreen.vala deleted file mode 100644 index c1d6473c..00000000 --- a/src/Shell/Layouts/Display/PluginScreen.vala +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets.Display; -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Shell.Layouts.Display { - /** - * Shows the plugin UI. - */ - public class PluginScreen : DisplayWindow { - public unowned AudioPlugin plugin { get; private set; } - public string? history { get; set; } - - private Gtk.Switch active_switch; - private Widgets.Knob gain_knob; - - public PluginScreen (AudioPlugin plugin) { - var protocol_name = ""; - switch (plugin.protocol) { - case AudioPlugin.Protocol.LV2: - protocol_name += "L V 2"; - break; - case AudioPlugin.Protocol.CARLA: - protocol_name += "C A R L A"; - break; - case AudioPlugin.Protocol.LADSPA: - protocol_name += "L A D S P A"; - break; - case AudioPlugin.Protocol.NATIVE: - protocol_name += "E N S E M B L E S G T K"; - break; - } - - base (_(plugin.name), _(protocol_name)); - this.plugin = plugin; - - build_ui (); - build_events (); - } - - private void build_ui () { - gain_knob = new Widgets.Knob.with_range (-12, 0, 1) { - width_request = 40, - height_request = 40, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER, - tooltip_text = _("Dry / Wet Mix") - }; - gain_knob.add_css_class ("small"); - - gain_knob.value = Utils.Math.convert_gain_to_db (plugin.mix_gain); - gain_knob.add_mark (-12); - gain_knob.add_mark (0); - add_to_header (gain_knob); - - active_switch = new Gtk.Switch () { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER, - margin_end = 8 - }; - active_switch.active = plugin.active; - add_to_header (active_switch); - - var scrollable = new Gtk.ScrolledWindow () { - vexpand = true, - hexpand = true - }; - append (scrollable); - - var plugin_ui = plugin.ui; - if (plugin_ui != null) { - scrollable.set_child (plugin_ui); - } - } - - private void build_events () { - active_switch.notify["active"].connect (() => { - plugin.active = active_switch.active; - }); - - gain_knob.value_changed.connect ((db) => { - plugin.mix_gain = (float) Utils.Math.convert_db_to_gain (db); - }); - } - } -} diff --git a/src/Shell/Layouts/Display/StyleScreen.vala b/src/Shell/Layouts/Display/StyleScreen.vala deleted file mode 100644 index 96e55a1c..00000000 --- a/src/Shell/Layouts/Display/StyleScreen.vala +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets.Display; -using Ensembles.Models; - -namespace Ensembles.Shell.Layouts.Display { - /** - * Shows a list of styles. - */ - public class StyleScreen : DisplayWindow { - private Gtk.ListBox main_list_box; - - public StyleScreen () { - base (_("Style"), _("Pick a Rhythm to accompany you")); - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - var scrollable = new Gtk.ScrolledWindow () { - hexpand = true, - vexpand = true, - margin_start = 8, - margin_end = 8, - margin_top = 8, - margin_bottom = 8 - }; - append (scrollable); - - main_list_box = new Gtk.ListBox () { - selection_mode = Gtk.SelectionMode.SINGLE - }; - main_list_box.add_css_class ("menu-box"); - scrollable.set_child (main_list_box); - } - - public void build_events () { - main_list_box.row_activated.connect ((item) => { - var style_item = (StyleMenuItem) item; - - Application.event_bus.style_change (style_item.style); - }); - - Application.event_bus.arranger_ready.connect (() => { - Timeout.add (1000, () => { - Idle.add (() => { - populate (Application.arranger_workstation.get_styles ()); - var row_to_select = main_list_box.get_row_at_index (0); - main_list_box.select_row (row_to_select); - Application.event_bus.style_change (((StyleMenuItem) row_to_select).style); - return false; - }); - return false; - }); - }); - } - - public void populate (Style[] styles) { - Console.log ("Populating style list…"); - - var temp_category = ""; - for (uint16 i = 0; i < styles.length; i++) { - var show_category = false; - if (temp_category != styles[i].genre) { - temp_category = styles[i].genre; - show_category = true; - } - - var menu_item = new StyleMenuItem (styles[i], show_category); - main_list_box.insert (menu_item, -1); - } - - min_value = 0; - max_value = styles.length - 1; - } - - public void scroll_to_selected_row () { - var selected_item = main_list_box.get_selected_row (); - if (selected_item != null) { - selected_item.grab_focus (); - - // var adj = main_list_box.get_adjustment (); - // if (adj != null) { - // int height, _htemp; - // height = selected_item.get_allocated_height (); - - // Timeout.add (200, () => { - // adj.set_value (_selected_index * height); - // return false; - // }); - // } - } - } - } -} diff --git a/src/Shell/Layouts/Display/VoiceScreen.vala b/src/Shell/Layouts/Display/VoiceScreen.vala deleted file mode 100644 index 5abcb600..00000000 --- a/src/Shell/Layouts/Display/VoiceScreen.vala +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets.Display; -using Ensembles.Models; -using Ensembles.Core.Plugins.AudioPlugins; -using Ensembles.Core.Racks; - -namespace Ensembles.Shell.Layouts.Display { - /** - * Shows a list of voices from SoundFont and Voice plugins - */ - public class VoiceScreen : DisplayWindow { - public VoiceHandPosition hand_position { get; private set; } - private Gtk.ListBox main_list_box; - - private uint16 last_voice_index = 0; - private uint16 plugin_start_index = 0; - - public VoiceScreen (VoiceHandPosition hand_position) { - var title_by_position = ""; - var subtitle_by_position = ""; - switch (hand_position) { - case VoiceHandPosition.LEFT: - title_by_position = _("Left (Split)"); - subtitle_by_position = _("Pick a Voice to play on the left hand side of split"); - break; - case VoiceHandPosition.RIGHT: - title_by_position = _("Right 1 (Main)"); - subtitle_by_position = _("Pick a Voice to play"); - break; - case VoiceHandPosition.RIGHT_LAYERED: - title_by_position = _("Right 2 (Layered)"); - subtitle_by_position = _("Pick a Voice to play on another layer"); - break; - } - - base ( - _("Voice - %s").printf (title_by_position), - subtitle_by_position - ); - this.hand_position = hand_position; - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - var scrollable = new Gtk.ScrolledWindow () { - hexpand = true, - vexpand = true - }; - append (scrollable); - - main_list_box = new Gtk.ListBox () { - selection_mode = Gtk.SelectionMode.SINGLE - }; - main_list_box.add_css_class ("menu-box"); - scrollable.set_child (main_list_box); - } - - public void build_events () { - main_list_box.row_selected.connect ((item) => { - var voice_item = (VoiceMenuItem) item; - if (voice_item.is_plugin) { - Application.event_bus.voice_chosen (hand_position, voice_item.plugin.name, 0, 0); - Application.arranger_workstation.get_voice_rack (hand_position).active = true; - Application.arranger_workstation.get_voice_rack (hand_position) - .set_plugin_active (item.get_index () - plugin_start_index, true); - } else { - Application.arranger_workstation.get_voice_rack (hand_position).active = false; - Application.event_bus.voice_chosen ( - hand_position, voice_item.voice.name, voice_item.voice.bank, voice_item.voice.preset - ); - } - }); - Application.event_bus.arranger_ready.connect (() => { - populate (Application.arranger_workstation.get_voices ()); - populate_plugins (Application.arranger_workstation.get_voice_rack (hand_position).get_plugins ()); - }); - } - - public void populate (Voice[] voices) { - var temp_category = ""; - for (uint16 i = 0; i < voices.length; i++) { - var show_category = false; - if (temp_category != voices[i].category) { - temp_category = voices[i].category; - show_category = true; - } - - var menu_item = new VoiceMenuItem ( - last_voice_index++, - voices[i], - null, - show_category - ); - main_list_box.insert (menu_item, -1); - } - - plugin_start_index = last_voice_index; - } - - public void populate_plugins (List plugins) { - var temp_category = AudioPlugin.Protocol.NATIVE; - for (uint16 i = 0; i < plugins.length (); i++) { - if (plugins.nth_data (i).category == AudioPlugin.Category.VOICE) { - var show_category = false; - if (temp_category != plugins.nth_data (i).protocol) { - temp_category = plugins.nth_data (i).protocol; - show_category = true; - } - - var menu_item = new VoiceMenuItem ( - last_voice_index++, - Voice (), - plugins.nth_data (i), - show_category - ); - main_list_box.insert (menu_item, -1); - } - } - } - - public void scroll_to_selected_row () { - var selected_item = main_list_box.get_selected_row (); - if (selected_item != null) { - selected_item.grab_focus (); - - // var adj = main_list_box.get_adjustment (); - // if (adj != null) { - // int height, _htemp; - // height = selected_item.get_allocated_height (); - - // Timeout.add (200, () => { - // adj.set_value (_selected_index * height); - // return false; - // }); - // } - } - } - } -} diff --git a/src/Shell/Layouts/InfoDisplay.vala b/src/Shell/Layouts/InfoDisplay.vala deleted file mode 100644 index cf0c9418..00000000 --- a/src/Shell/Layouts/InfoDisplay.vala +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Layouts.Display; - -namespace Ensembles.Shell.Layouts { - public class InfoDisplay : Gtk.Box { - private Gtk.Overlay main_overlay; - private Gtk.Box splash_screen; - private Gtk.Label splash_screen_label; - private Gtk.Stack main_stack; - - private bool _fill_screen; - public bool fill_screen { - get { - return _fill_screen; - } - set { - _fill_screen = value; - if (value) { - remove_css_class ("panel"); - main_overlay.add_css_class ("fill"); - } else { - add_css_class ("panel"); - main_overlay.remove_css_class ("fill"); - } - } - } - - // Screens - private HomeScreen home_screen; - private StyleScreen style_screen; - private VoiceScreen voice_l_screen; - private VoiceScreen voice_r1_screen; - private VoiceScreen voice_r2_screen; - private DSPScreen dsp_screen; - private PluginScreen plugin_screen; - - construct { - build_ui (); - build_events (); - } - - public InfoDisplay () { - Object ( - hexpand: true, - vexpand: true, - width_request: 480, - height_request: 360 - ); - } - - private void build_ui () { - add_css_class ("panel"); - - main_overlay = new Gtk.Overlay () { - hexpand = true, - vexpand = true, - overflow = Gtk.Overflow.HIDDEN - }; - main_overlay.add_css_class ("display"); - append (main_overlay); - - splash_screen = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - splash_screen.add_css_class ("splash-screen-background"); - main_overlay.add_overlay (splash_screen); - - var splash_banner = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - hexpand = true, - vexpand = true - }; - splash_banner.add_css_class ("ensembles-logo-splash"); - splash_screen.append (splash_banner); - - splash_screen_label = new Gtk.Label (_("Initializing…")) { - xalign = 0, - margin_start = 8, - margin_bottom = 8, - margin_end = 8, - margin_top = 8, - opacity = 0.5 - }; - splash_screen_label.add_css_class ("splash-screen-label"); - splash_screen.append (splash_screen_label); - - main_stack = new Gtk.Stack () { - transition_type = Gtk.StackTransitionType.OVER_UP_DOWN - }; - main_stack.add_css_class ("display-stack"); - main_stack.add_css_class ("fade-black"); - main_overlay.set_child (main_stack); - - home_screen = new HomeScreen (); - main_stack.add_named (home_screen, "home"); - - style_screen = new StyleScreen (); - main_stack.add_named (style_screen, "style"); - - voice_l_screen = new VoiceScreen (Ensembles.VoiceHandPosition.LEFT); - main_stack.add_named (voice_l_screen, "voice-l"); - - voice_r1_screen = new VoiceScreen (Ensembles.VoiceHandPosition.RIGHT); - main_stack.add_named (voice_r1_screen, "voice-r1"); - - voice_r2_screen = new VoiceScreen (Ensembles.VoiceHandPosition.RIGHT_LAYERED); - main_stack.add_named (voice_r2_screen, "voice-r2"); - } - - private void build_events () { - Application.event_bus.arranger_ready.connect (() => { - splash_screen.add_css_class ("fade-black"); - - Timeout.add (1000, () => { - main_overlay.remove_overlay (splash_screen); - if (splash_screen != null) { - splash_screen.unref (); - } - - Timeout.add (200, () => { - main_stack.remove_css_class ("fade-black"); - return false; - }); - - Timeout.add (400, () => { - dsp_screen = new DSPScreen (Application.arranger_workstation.get_main_dsp_rack ()); - dsp_screen.close.connect (navigate_to_home); - main_stack.add_named (dsp_screen, "dsp"); - return false; - }); - return false; - }); - - }); - - home_screen.change_screen.connect ((screen_name) => { - main_stack.set_visible_child_name (screen_name); - }); - - Application.event_bus.send_initial_status.connect (update_status); - - style_screen.close.connect (navigate_to_home); - voice_l_screen.close.connect (navigate_to_home); - voice_r1_screen.close.connect (navigate_to_home); - voice_r2_screen.close.connect (navigate_to_home); - - Application.event_bus.show_plugin_ui.connect (show_plugin_screen); - } - - public void navigate_to_home () { - main_stack.set_visible_child_name ("home"); - } - - public void show_plugin_screen (Core.Plugins.AudioPlugins.AudioPlugin plugin) { - if (plugin_screen != null) { - main_stack.remove (plugin_screen); - plugin_screen = null; - } - - plugin_screen = new PluginScreen (plugin) { - history = main_stack.get_visible_child_name () - }; - plugin_screen.close.connect (() => { - main_stack.set_visible_child_name (plugin_screen.history); - }); - main_stack.add_named (plugin_screen, "plugin"); - main_stack.set_visible_child_name ("plugin"); - } - - public void update_status (string status) { - Idle.add (() => { - splash_screen_label.set_text (status); - return false; - }); - } - } -} diff --git a/src/Shell/Layouts/KeyboardPanel.vala b/src/Shell/Layouts/KeyboardPanel.vala deleted file mode 100644 index 7077daa9..00000000 --- a/src/Shell/Layouts/KeyboardPanel.vala +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets; - -namespace Ensembles.Shell.Layouts { - public class KeyboardPanel : Gtk.Grid { - private Gtk.Overlay keyboard_info_bar; - private Keyboard keyboard; - - public KeyboardPanel () { - Object ( - hexpand: true, - vexpand: true, - height_request: 128 - ); - } - - construct { - add_css_class ("keyboard"); - build_ui (); - build_events (); - } - - private void build_ui () { - keyboard_info_bar = new Gtk.Overlay () { - hexpand = true, - height_request = 32 - }; - keyboard_info_bar.add_css_class ("keyboard-info-bar"); - attach (keyboard_info_bar, 0, 0); - - var keyboard_button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8) { - halign = Gtk.Align.END - }; - keyboard_info_bar.set_child (keyboard_button_box); - - var zoom_in_button = new Gtk.Button.from_icon_name ("zoom-in-symbolic"); - zoom_in_button.clicked.connect (() => { - keyboard.zoom_level += 48; - }); - keyboard_button_box.append (zoom_in_button); - - var zoom_out_button = new Gtk.Button.from_icon_name ("zoom-out-symbolic"); - zoom_out_button.clicked.connect (() => { - keyboard.zoom_level -= 48; - }); - keyboard_button_box.append (zoom_out_button); - - var zoom_reset_button = new Gtk.Button.from_icon_name ("zoom-fit-best-symbolic"); - zoom_reset_button.clicked.connect (() => { - keyboard.zoom_level = 0; - }); - keyboard_button_box.append (zoom_reset_button); - - var keyboard_scrollable = new Gtk.ScrolledWindow () { - hexpand = true, - vexpand = true, - kinetic_scrolling = false, - has_frame = false, - - }; - - keyboard_scrollable.set_placement (Gtk.CornerType.BOTTOM_LEFT); - attach (keyboard_scrollable, 0, 1); - - keyboard = new Keyboard (5) { - octave_offset = 3 - }; - keyboard_scrollable.set_child (keyboard); - } - - private void build_events () { - keyboard.key_event.connect ((event) => { - Application.event_bus.synth_send_event (event); - }); - Application.event_bus.synth_received_note.connect ((note, on) => { - keyboard.set_key_illumination (note, on); - }); - } - } -} diff --git a/src/Shell/Layouts/KioskLayout.vala b/src/Shell/Layouts/KioskLayout.vala deleted file mode 100644 index 14ba6e97..00000000 --- a/src/Shell/Layouts/KioskLayout.vala +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - namespace Ensembles.Shell.Layouts { - public class KioskLayout : Gtk.Grid { - private unowned InfoDisplay info_display; - private unowned MixerBoard mixer_board; - - construct { - add_css_class ("panel"); - } - - public KioskLayout (InfoDisplay info_display, MixerBoard mixer_board) { - Object ( - hexpand: true, - vexpand: true - ); - - this.info_display = info_display; - this.mixer_board = mixer_board; - - build_ui (); - } - - private void build_ui () { - attach (info_display, 0, 0); - attach (mixer_board, 0, 1); - } - } -} diff --git a/src/Shell/Layouts/MixerBoard.vala b/src/Shell/Layouts/MixerBoard.vala deleted file mode 100644 index 5ecd19f2..00000000 --- a/src/Shell/Layouts/MixerBoard.vala +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class MixerBoard : Gtk.Grid { - construct { - add_css_class ("panel"); - } - } -} diff --git a/src/Shell/Layouts/MobileLayout.vala b/src/Shell/Layouts/MobileLayout.vala deleted file mode 100644 index 027534be..00000000 --- a/src/Shell/Layouts/MobileLayout.vala +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class MobileLayout : Gtk.Grid { - private weak Layouts.AssignablesBoard assignables_board; - private weak Layouts.InfoDisplay info_display; - private weak Layouts.SynthControlPanel synth_control_panel; - private weak Layouts.VoiceNavPanel voice_nav_panel; - private weak Layouts.MixerBoard mixer_board; - private weak Layouts.SamplerPadsPanel sampler_pads_panel; - private weak Layouts.StyleControlPanel style_control_panel; - private weak Layouts.RegistryPanel registry_panel; - private weak Layouts.KeyboardPanel keyboard; - - private Gtk.Grid infoview; - private Gtk.Grid keyboardview; - private Gtk.Box style_registry_box; - private Gtk.Box style_controller_socket; - private Gtk.Box registry_socket; - private Gtk.Button start_button; - - private Gtk.ScrolledWindow scrolled_window; - private Adw.Flap flap; - private Gtk.Stack main_stack; - - private Gtk.ListBox menu_box; - - construct { - build_ui (); - build_events (); - } - - public MobileLayout (Layouts.AssignablesBoard? assignables_board, - Layouts.InfoDisplay? info_display, - Layouts.SynthControlPanel? synth_control_panel, - Layouts.VoiceNavPanel? voice_nav_panel, - Layouts.MixerBoard? mixer_board, - Layouts.SamplerPadsPanel? sampler_pads_panel, - Layouts.StyleControlPanel? style_control_panel, - Layouts.RegistryPanel? registry_panel, - Layouts.KeyboardPanel? keyboard) { - Object ( - width_request: 812, - height_request: 375 - ); - this.assignables_board = assignables_board; - this.info_display = info_display; - this.synth_control_panel = synth_control_panel; - this.voice_nav_panel = voice_nav_panel; - this.mixer_board = mixer_board; - this.sampler_pads_panel = sampler_pads_panel; - this.style_control_panel = style_control_panel; - this.registry_panel = registry_panel; - this.keyboard = keyboard; - } - - private void build_ui () { - flap = new Adw.Flap (); - attach (flap, 0, 0); - - // Make menu - menu_box = new Gtk.ListBox () { - width_request = 200 - }; - flap.set_flap (menu_box); - menu_box.add_css_class ("adw-listbox"); - - var info_entry = new Adw.ActionRow () { - title = "Info Display", - subtitle = "View interactive infomation display", - name = "info" - }; - menu_box.append (info_entry); - - var keyboard_entry = new Adw.ActionRow () { - title = "Keyboard", - subtitle = "Show the keys, style control buttons and registry buttons", - name = "keyboard" - }; - menu_box.append (keyboard_entry); - - main_stack = new Gtk.Stack () { - width_request = 800, - transition_type = Gtk.StackTransitionType.SLIDE_UP_DOWN, - transition_duration = 300 - }; - flap.set_content (main_stack); - - // Make Content - infoview = new Gtk.Grid (); - main_stack.add_named (infoview, "info-view"); - - keyboardview = new Gtk.Grid (); - main_stack.add_named (keyboardview, "keyboard-view"); - - scrolled_window = new Gtk.ScrolledWindow () { - height_request = 62, - vscrollbar_policy = Gtk.PolicyType.NEVER - }; - keyboardview.attach (scrolled_window, 0, 0); - style_registry_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - scrolled_window.set_child (style_registry_box); - - style_controller_socket = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - style_registry_box.append (style_controller_socket); - - var start_button_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - start_button_box.add_css_class ("panel"); - style_registry_box.append (start_button_box); - - start_button = new Gtk.Button.from_icon_name ("media-playback-start-symbolic") { - width_request = 64, - height_request = 32 - }; - start_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); - start_button.remove_css_class ("image-button"); - start_button.clicked.connect (() => { - Application.event_bus.style_play_toggle (); - }); - - start_button_box.append (start_button); - start_button_box.append (new Gtk.Label (_("START/STOP")) { opacity = 0.5 }); - - registry_socket = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - style_registry_box.append (registry_socket); - } - - public void reparent () { - assignables_board.unparent (); - info_display.unparent (); - synth_control_panel.unparent (); - voice_nav_panel.unparent (); - mixer_board.unparent (); - sampler_pads_panel.unparent (); - style_control_panel.unparent (); - registry_panel.unparent (); - keyboard.unparent (); - - infoview.attach (info_display, 0, 0); - info_display.fill_screen = true; - - style_controller_socket.append (style_control_panel); - registry_socket.append (registry_panel); - keyboardview.attach (keyboard, 0, 1); - } - - private void build_events () { - menu_box.row_selected.connect ((row) => { - main_stack.set_visible_child_name (row.name + "-view"); - }); - - Application.event_bus.show_menu.connect ((show) => { - flap.set_reveal_flap (show); - return !show; - }); - - flap.notify.connect ((param) => { - if (param.name == "reveal-flap") { - Application.event_bus.menu_shown (flap.reveal_flap); - Idle.add (() => { - if (flap.reveal_flap && flap.folded) { - main_stack.add_css_class ("dimmed"); - } else { - main_stack.remove_css_class ("dimmed"); - } - return false; - }); - } - }); - } - } -} diff --git a/src/Shell/Layouts/PluginView.vala b/src/Shell/Layouts/PluginView.vala deleted file mode 100644 index eb772f0f..00000000 --- a/src/Shell/Layouts/PluginView.vala +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class PluginView : Gtk.Box { - public weak Display.DisplayWindow plugin_ui { get; set; } - - public void reparent () { - plugin_ui.unparent (); - append (plugin_ui); - } - } -} diff --git a/src/Shell/Layouts/RegistryPanel.vala b/src/Shell/Layouts/RegistryPanel.vala deleted file mode 100644 index 354355c1..00000000 --- a/src/Shell/Layouts/RegistryPanel.vala +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class RegistryPanel : Gtk.Grid { - construct { - add_css_class ("panel"); - } - } -} diff --git a/src/Shell/Layouts/SamplerPadsPanel.vala b/src/Shell/Layouts/SamplerPadsPanel.vala deleted file mode 100644 index 3c724d51..00000000 --- a/src/Shell/Layouts/SamplerPadsPanel.vala +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class SamplerPadsPanel : Gtk.Grid { - construct { - add_css_class ("panel"); - } - } -} diff --git a/src/Shell/Layouts/StyleControlPanel.vala b/src/Shell/Layouts/StyleControlPanel.vala deleted file mode 100644 index 76750612..00000000 --- a/src/Shell/Layouts/StyleControlPanel.vala +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Shell.Layouts { - public class StyleControlPanel : Gtk.Box { - private Gtk.Button intro_1_button; - private Gtk.Button intro_2_button; - private Gtk.Button intro_3_button; - private Gtk.Button break_button; - private Gtk.Button variation_a_button; - private Gtk.Button variation_b_button; - private Gtk.Button variation_c_button; - private Gtk.Button variation_d_button; - private Gtk.Button ending_1_button; - private Gtk.Button ending_2_button; - private Gtk.Button ending_3_button; - private Gtk.Button sync_start_button; - - private StylePartType current_part = StylePartType.VARIATION_A; - private StylePartType next_part = StylePartType.VARIATION_A; - - public StyleControlPanel () { - Object ( - orientation: Gtk.Orientation.HORIZONTAL, - spacing: 4, - hexpand: true - ); - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - add_css_class ("panel"); - - var intro_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - append (intro_box); - - var intro_button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - hexpand = true, - homogeneous = true - }; - intro_button_box.add_css_class (Granite.STYLE_CLASS_LINKED); - intro_box.append (intro_button_box); - intro_box.append (new Gtk.Label (_("INTRO")) { opacity = 0.5 } ); - - var variation_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - append (variation_box); - - var variation_button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - hexpand = true, - homogeneous = true - }; - variation_button_box.add_css_class (Granite.STYLE_CLASS_LINKED); - variation_box.append (variation_button_box); - variation_box.append (new Gtk.Label (_("VARIATION/FILL-IN")) { opacity = 0.5 } ); - - var break_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - append (break_box); - - break_button = new Gtk.Button.from_icon_name ("style-break-symbolic") { - tooltip_text = "Break", - has_tooltip = true, - hexpand = true, - height_request = 32 - }; - break_button.remove_css_class ("image-button"); - break_box.append (break_button); - break_box.append (new Gtk.Label (_("BREAK")) { opacity = 0.5 } ); - - var ending_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - append (ending_box); - - var ending_button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - hexpand = true, - homogeneous = true - }; - ending_button_box.add_css_class (Granite.STYLE_CLASS_LINKED); - ending_box.append (ending_button_box); - ending_box.append (new Gtk.Label (_("ENDING")) { opacity = 0.5 } ); - - intro_1_button = new Gtk.Button.with_label (_("1")) { - height_request = 32 - }; - intro_button_box.append (intro_1_button); - intro_2_button = new Gtk.Button.with_label (_("2")) { - height_request = 32 - }; - intro_button_box.append (intro_2_button); - intro_3_button = new Gtk.Button.with_label (_("3")) { - height_request = 32 - }; - intro_button_box.append (intro_3_button); - - variation_a_button = new Gtk.Button.with_label (_("A")) { - height_request = 32 - }; - variation_button_box.append (variation_a_button); - variation_b_button = new Gtk.Button.with_label (_("B")) { - height_request = 32 - }; - variation_button_box.append (variation_b_button); - variation_c_button = new Gtk.Button.with_label (_("C")) { - height_request = 32 - }; - variation_button_box.append (variation_c_button); - variation_d_button = new Gtk.Button.with_label (_("D")) { - height_request = 32 - }; - variation_button_box.append (variation_d_button); - - ending_1_button = new Gtk.Button.with_label (_("1")) { - height_request = 32 - }; - ending_button_box.append (ending_1_button); - ending_2_button = new Gtk.Button.with_label (_("2")) { - height_request = 32 - }; - ending_button_box.append (ending_2_button); - ending_3_button = new Gtk.Button.with_label (_("3")) { - height_request = 32 - }; - ending_button_box.append (ending_3_button); - - var sync_start_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 2); - append (sync_start_box); - sync_start_button = new Gtk.Button.from_icon_name ("style-sync-start-symbolic") { - tooltip_text = "Sync Start / Stop", - has_tooltip = true, - hexpand = true, - height_request = 32 - }; - sync_start_button.remove_css_class ("image-button"); - sync_start_box.append (sync_start_button); - sync_start_box.append (new Gtk.Label (_("SYNC")) { opacity = 0.5 } ); - - highlight_part (); - } - - private void build_events () { - intro_1_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.INTRO_1); - }); - - intro_2_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.INTRO_2); - }); - - intro_3_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.INTRO_3); - }); - - variation_a_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.VARIATION_A); - }); - - variation_b_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.VARIATION_B); - }); - - variation_c_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.VARIATION_C); - }); - - variation_d_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.VARIATION_D); - }); - - ending_1_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.ENDING_1); - }); - - ending_2_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.ENDING_2); - }); - - ending_3_button.clicked.connect (() => { - Application.event_bus.style_set_part (StylePartType.ENDING_3); - }); - - Application.event_bus.style_current_part_changed.connect ((part) => { - current_part = part; - highlight_part (); - }); - - Application.event_bus.style_next_part_changed.connect ((part) => { - next_part = part; - highlight_part (); - }); - - sync_start_button.clicked.connect (() => { - Application.event_bus.style_sync (); - }); - - Application.event_bus.style_sync_changed.connect ((active) => { - if (active) { - sync_start_button.add_css_class ("pulse"); - } else { - sync_start_button.remove_css_class ("pulse"); - } - }); - - break_button.clicked.connect (() => { - Application.event_bus.style_break (); - }); - - Application.event_bus.style_break_changed.connect ((active) => { - if (active) { - break_button.add_css_class ("pulse"); - } else { - break_button.remove_css_class ("pulse"); - } - }); - } - - private void highlight_part () { - switch (current_part) { - case StylePartType.INTRO_1: - intro_1_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.INTRO_2: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.INTRO_3: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.ENDING_1: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.ENDING_2: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.ENDING_3: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.VARIATION_A: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.VARIATION_B: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.VARIATION_C: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.VARIATION_D: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.FILL_A: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.add_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.FILL_B: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.add_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.FILL_C: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.add_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.remove_css_class ("pulse-fill"); - break; - case StylePartType.FILL_D: - intro_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - intro_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_1_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_2_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - ending_3_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_a_button.remove_css_class ("pulse-fill"); - variation_b_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_b_button.remove_css_class ("pulse-fill"); - variation_c_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_c_button.remove_css_class ("pulse-fill"); - variation_d_button.remove_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - variation_d_button.add_css_class ("pulse-fill"); - break; - default: - break; - } - - if (current_part != next_part) { - switch (next_part) { - case StylePartType.INTRO_1: - intro_1_button.add_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.INTRO_2: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.add_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.INTRO_3: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.add_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.ENDING_1: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.add_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.ENDING_2: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.add_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.ENDING_3: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.add_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.VARIATION_A: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.add_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.VARIATION_B: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.add_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.VARIATION_C: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.add_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - break; - case StylePartType.VARIATION_D: - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.add_css_class ("pulse"); - break; - default: - break; - } - } else { - intro_1_button.remove_css_class ("pulse"); - intro_2_button.remove_css_class ("pulse"); - intro_3_button.remove_css_class ("pulse"); - ending_1_button.remove_css_class ("pulse"); - ending_2_button.remove_css_class ("pulse"); - ending_3_button.remove_css_class ("pulse"); - variation_a_button.remove_css_class ("pulse"); - variation_b_button.remove_css_class ("pulse"); - variation_c_button.remove_css_class ("pulse"); - variation_d_button.remove_css_class ("pulse"); - } - } - } -} diff --git a/src/Shell/Layouts/SynthControlPanel.vala b/src/Shell/Layouts/SynthControlPanel.vala deleted file mode 100644 index 9f6e77d7..00000000 --- a/src/Shell/Layouts/SynthControlPanel.vala +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class SynthControlPanel : Gtk.Grid { - construct { - add_css_class ("panel"); - } - - public SynthControlPanel () { - Object ( - hexpand: true, - vexpand: true - ); - } - } -} diff --git a/src/Shell/Layouts/VoiceNavPanel.vala b/src/Shell/Layouts/VoiceNavPanel.vala deleted file mode 100644 index 9bf37e0f..00000000 --- a/src/Shell/Layouts/VoiceNavPanel.vala +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Layouts { - public class VoiceNavPanel : Gtk.Grid { - construct { - add_css_class ("panel"); - } - } -} diff --git a/src/Shell/MainWindow.vala b/src/Shell/MainWindow.vala deleted file mode 100644 index 8aa5d5d6..00000000 --- a/src/Shell/MainWindow.vala +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - namespace Ensembles.Shell { - public class MainWindow : Gtk.ApplicationWindow { - // Event Handling - private Gtk.EventControllerKey event_controller_key; - - // Headerbar - private Gtk.HeaderBar headerbar; - - // Responsive UI - private Adw.Squeezer squeezer; - private Gtk.ToggleButton flap_button; - private bool flap_revealed = true; - - // Various major layouts - private Layouts.DesktopLayout desktop_layout; - private Layouts.MobileLayout mobile_layout; - private Layouts.KioskLayout kiosk_layout; - - // Sub-layouts - private Layouts.AssignablesBoard assignables_board; - private Layouts.InfoDisplay info_display; - private Layouts.SynthControlPanel synth_control_panel; - private Layouts.VoiceNavPanel voice_nav_panel; - private Layouts.MixerBoard mixer_board; - private Layouts.SamplerPadsPanel sampler_pads_panel; - private Layouts.StyleControlPanel style_control_panel; - private Layouts.RegistryPanel registry_panel; - private Layouts.KeyboardPanel keyboard; - - // Headerbar - private Widgets.BeatVisualization beat_visualization; - - public MainWindow (Ensembles.Application? ensembles_app) { - Object ( - application: ensembles_app, - icon_name: Constants.APP_ID, - title: "Ensembles", - default_height: 700 - ); - } - - construct { - build_ui (); - build_events (); - } - - private void build_ui () { - if (Application.kiosk_mode) { - decorated = false; - fullscreened = true; - - info_display = new Layouts.InfoDisplay (); - info_display.fill_screen = true; - mixer_board = new Layouts.MixerBoard (); - - kiosk_layout = new Layouts.KioskLayout (info_display, mixer_board); - set_child (kiosk_layout); - return; - } - - // Make headerbar - headerbar = new Gtk.HeaderBar () { - show_title_buttons = true, - }; - - set_titlebar (headerbar); - - flap_button = new Gtk.ToggleButton () { - visible = false - }; - flap_button.set_icon_name ("view-continuous-symbolic"); - flap_button.remove_css_class ("image-button"); - flap_button.clicked.connect (() => { - flap_revealed = Application.event_bus.show_menu (flap_revealed); - }); - headerbar.pack_start (flap_button); - - beat_visualization = new Widgets.BeatVisualization (); - headerbar.pack_start (beat_visualization); - - squeezer = new Adw.Squeezer () { - orientation = Gtk.Orientation.VERTICAL, - transition_type = Adw.SqueezerTransitionType.CROSSFADE, - transition_duration = 400 - }; - set_child (squeezer); - - assignables_board = new Layouts.AssignablesBoard (); - info_display = new Layouts.InfoDisplay (); - synth_control_panel = new Layouts.SynthControlPanel (); - voice_nav_panel = new Layouts.VoiceNavPanel (); - mixer_board = new Layouts.MixerBoard (); - sampler_pads_panel = new Layouts.SamplerPadsPanel (); - style_control_panel = new Layouts.StyleControlPanel (); - registry_panel = new Layouts.RegistryPanel (); - keyboard = new Layouts.KeyboardPanel (); - - desktop_layout = new Layouts.DesktopLayout (assignables_board, - info_display, - synth_control_panel, - voice_nav_panel, - mixer_board, - sampler_pads_panel, - style_control_panel, - registry_panel, - keyboard); - squeezer.add (desktop_layout); - desktop_layout.reparent (); - - - mobile_layout = new Layouts.MobileLayout (assignables_board, - info_display, - synth_control_panel, - voice_nav_panel, - mixer_board, - sampler_pads_panel, - style_control_panel, - registry_panel, - keyboard); - squeezer.add (mobile_layout); - } - - public void show_ui () { - present (); - show (); - } - - private void build_events () { - event_controller_key = new Gtk.EventControllerKey (); - ((Gtk.Widget)this).add_controller (event_controller_key); - - event_controller_key.key_pressed.connect ((keyval, keycode, state) => { - Console.log ("key: %u".printf (keyval)); - - return false; - }); - - Application.event_bus.arranger_ready.connect (() => { - Console.log ("Arranger Workstation Initialized!", Console.LogLevel.SUCCESS); - }); - - notify["default-height"].connect (() => { - if (!Application.kiosk_mode) { - flap_button.visible = squeezer.get_visible_child () == mobile_layout; - - if (squeezer.get_visible_child () == desktop_layout) { - desktop_layout.reparent (); - } else { - mobile_layout.reparent (); - } - } - - Application.event_bus.size_change (); - }); - - notify["default-width"].connect (() => { - Application.event_bus.size_change (); - }); - - notify["maximized"].connect (() => { - fullscreen (); - Timeout.add (100, () => { - if (!Application.kiosk_mode) { - flap_button.visible = squeezer.get_visible_child () == mobile_layout; - - if (squeezer.get_visible_child () == desktop_layout) { - desktop_layout.reparent (); - } else { - mobile_layout.reparent (); - } - } - - Application.event_bus.size_change (); - return false; - }); - }); - - Application.event_bus.menu_shown.connect ((shown) => { - flap_revealed = !shown; - flap_button.active = shown; - }); - - ((Gtk.Widget) this).realize.connect (() => { - if (Application.kiosk_mode) { - var display = Gdk.Display.get_default (); - var monitor = display.get_monitor_at_surface (get_surface ()); - set_default_size (monitor.geometry.width, monitor.geometry.height); - kiosk_layout.width_request = monitor.geometry.width; - kiosk_layout.height_request = monitor.geometry.height; - } - }); - } - } - } diff --git a/src/Shell/Plugins/AudioPlugins/Widgets/AudioPluginControl.vala b/src/Shell/Plugins/AudioPlugins/Widgets/AudioPluginControl.vala deleted file mode 100644 index e3a58b85..00000000 --- a/src/Shell/Plugins/AudioPlugins/Widgets/AudioPluginControl.vala +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Shell.Plugins.AudioPlugins.Widgets { - public class AudioPluginControl : Gtk.Box { - private Gtk.IconSize widget_size; - private float* variable; - private unowned Port port; - - private Gtk.Label control_label; - - public AudioPluginControl (Port port, float* variable, Gtk.IconSize widget_size = Gtk.IconSize.NORMAL) { - Object ( - margin_start: 8, - margin_bottom: 8, - margin_top: 8, - margin_end: 8, - halign: Gtk.Align.CENTER, - orientation: Gtk.Orientation.VERTICAL - ); - - this.widget_size = widget_size; - this.variable = variable; - this.port = port; - - build_ui (); - } - - private void build_ui () { - add_css_class (Granite.STYLE_CLASS_CARD); - - control_label = new Gtk.Label (port.name) { - margin_top = 16, - margin_start = 16, - margin_end = 16 - }; - control_label.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - append (control_label); - - if (widget_size == Gtk.IconSize.LARGE) { - var knob = new Shell.Widgets.Knob () { - width_request = 150, - height_request = 150, - margin_start = 16, - margin_end = 16, - margin_top = 16, - margin_bottom = 16, - draw_value = true - }; - - append (knob); - - if (port is Core.Plugins.AudioPlugins.Lv2.LV2ControlPort) { - var lv2_control_port = (Core.Plugins.AudioPlugins.Lv2.LV2ControlPort) port; - knob.adjustment.lower = lv2_control_port.min_value; - knob.adjustment.upper = lv2_control_port.max_value; - knob.adjustment.step_increment = lv2_control_port.step; - knob.value = *variable; - - knob.add_mark (lv2_control_port.min_value); - knob.add_mark (lv2_control_port.default_value); - knob.add_mark (lv2_control_port.max_value); - } - - knob.value_changed.connect ((value) => { - *variable = (float) value; - }); - } else { - var scale = new Gtk.Scale (Gtk.Orientation.VERTICAL, null) { - height_request = 150, - margin_start = 16, - margin_end = 16, - margin_top = 16, - margin_bottom = 16, - inverted = true - }; - - append (scale); - - if (port is Core.Plugins.AudioPlugins.Lv2.LV2ControlPort) { - var lv2_control_port = (Core.Plugins.AudioPlugins.Lv2.LV2ControlPort) port; - scale.adjustment.lower = lv2_control_port.min_value; - scale.adjustment.upper = lv2_control_port.max_value; - scale.adjustment.step_increment = lv2_control_port.step; - scale.adjustment.value = *variable; - - scale.add_mark ( - lv2_control_port.min_value, Gtk.PositionType.RIGHT, - null - ); - scale.add_mark ( - lv2_control_port.default_value, - Gtk.PositionType.RIGHT, - null - ); - scale.add_mark ( - lv2_control_port.max_value, - Gtk.PositionType.RIGHT, - null - ); - } - - scale.value_changed.connect ((range) => { - *variable = (float) range.get_value (); - }); - } - } - } -} diff --git a/src/Shell/Widgets/BeatVisualization.vala b/src/Shell/Widgets/BeatVisualization.vala deleted file mode 100644 index 9308a001..00000000 --- a/src/Shell/Widgets/BeatVisualization.vala +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Widgets { - public class BeatVisualization : Gtk.Box { - Gtk.Fixed beat_counter_visual; - private uint beat_count = 0; - private uint8 tempo = 120; - private uint8 beats_per_bar = 4; - private uint8 beat_duration = 4; - - construct { - build_ui (); - } - - private void build_ui () { - beat_counter_visual = new Gtk.Fixed () { - width_request = 108, - height_request = 32, - valign = Gtk.Align.CENTER - }; - - beat_counter_visual.add_css_class ("beat-counter-0"); - append (beat_counter_visual); - - Application.event_bus.beat.connect ((measure, time_sig_n, time_sig_d) => { - beats_per_bar = time_sig_n; - beat_duration = time_sig_d; - beat (measure); - }); - - Application.event_bus.beat_reset.connect (() => { - beat_count = 0; - }); - } - - private void beat (bool measure) { - if (measure) { - beat_count = 1; - } - - if (beat_count < 5) { - set_beat_graphic (beat_count); - Timeout.add (120000 / (tempo * beat_duration), () => { - set_beat_graphic (0); - return false; - }); - } else { - beat_count = 1; - } - - beat_count++; - } - - private void set_beat_graphic (uint val) { - Idle.add (() => { - switch (val) { - case 0: - beat_counter_visual.add_css_class ("beat-counter-0"); - beat_counter_visual.remove_css_class ("beat-counter-1"); - beat_counter_visual.remove_css_class ("beat-counter-2"); - beat_counter_visual.remove_css_class ("beat-counter-3"); - beat_counter_visual.remove_css_class ("beat-counter-4"); - break; - case 1: - beat_counter_visual.remove_css_class ("beat-counter-0"); - beat_counter_visual.add_css_class ("beat-counter-1"); - beat_counter_visual.remove_css_class ("beat-counter-2"); - beat_counter_visual.remove_css_class ("beat-counter-3"); - beat_counter_visual.remove_css_class ("beat-counter-4"); - break; - case 2: - beat_counter_visual.remove_css_class ("beat-counter-0"); - beat_counter_visual.remove_css_class ("beat-counter-1"); - beat_counter_visual.add_css_class ("beat-counter-2"); - beat_counter_visual.remove_css_class ("beat-counter-3"); - beat_counter_visual.remove_css_class ("beat-counter-4"); - break; - case 3: - beat_counter_visual.remove_css_class ("beat-counter-0"); - beat_counter_visual.remove_css_class ("beat-counter-1"); - beat_counter_visual.remove_css_class ("beat-counter-2"); - beat_counter_visual.add_css_class ("beat-counter-3"); - beat_counter_visual.remove_css_class ("beat-counter-4"); - break; - case 4: - beat_counter_visual.remove_css_class ("beat-counter-0"); - beat_counter_visual.remove_css_class ("beat-counter-1"); - beat_counter_visual.remove_css_class ("beat-counter-2"); - beat_counter_visual.remove_css_class ("beat-counter-3"); - beat_counter_visual.add_css_class ("beat-counter-4"); - break; - } - - return false; - }); - } - } -} diff --git a/src/Shell/Widgets/Display/DSPInstanceMenuItem.vala b/src/Shell/Widgets/Display/DSPInstanceMenuItem.vala deleted file mode 100644 index c37ecc9b..00000000 --- a/src/Shell/Widgets/Display/DSPInstanceMenuItem.vala +++ /dev/null @@ -1,129 +0,0 @@ -/* -* Copyright 2020-2023 Subhadeep Jasu -* SPDX-License-Identifier: GPL-3.0-or-later -*/ - -using Ensembles.Models; -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Shell.Widgets.Display { - public class DSPInstanceMenuItem : Gtk.ListBoxRow { - public unowned AudioPlugin plugin { get; set; } - protected unowned Layouts.Display.DSPScreen rack_shell { get; set; } - public bool show_category { get; set; } - public Knob gain_knob; - public Gtk.CheckButton active_switch; - public Gtk.Button show_ui_button; - public Gtk.Button delete_instance_button; - - public DSPInstanceMenuItem (AudioPlugin plugin, Layouts.Display.DSPScreen rack_shell) { - Object ( - plugin: plugin, - rack_shell: rack_shell - ); - - build_ui (); - build_events (); - } - - private void build_ui () { - add_css_class ("menu-item"); - add_css_class ("p-8"); - - var menu_item_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); - set_child (menu_item_box); - - active_switch = new Gtk.CheckButton () { - valign = Gtk.Align.CENTER, - halign = Gtk.Align.CENTER, - margin_end = 16 - }; - active_switch.add_css_class ("audio-switch"); - active_switch.active = plugin.active; - menu_item_box.append (active_switch); - - var plugin_name_label = new Gtk.Label (plugin.name) { - halign = Gtk.Align.START, - hexpand = true - }; - plugin_name_label.add_css_class ("menu-item-name"); - menu_item_box.append (plugin_name_label); - - gain_knob = new Shell.Widgets.Knob.with_range (-12, 0, 1) { - width_request = 40, - height_request = 40, - tooltip_text = _("Dry / Wet Mix") - }; - gain_knob.add_css_class ("small"); - gain_knob.value = Utils.Math.convert_gain_to_db (plugin.mix_gain); - gain_knob.add_mark (-12); - gain_knob.add_mark (0); - menu_item_box.append (gain_knob); - - var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - homogeneous = true, - height_request = 36, - width_request = 80 - }; - button_box.add_css_class (Granite.STYLE_CLASS_LINKED); - menu_item_box.append (button_box); - - if (plugin.ui != null) { - show_ui_button = new Gtk.Button.from_icon_name ( - "preferences-other-symbolic" - ) { - tooltip_text = _("Show Plugin UI") - }; - button_box.append (show_ui_button); - } - - delete_instance_button = new Gtk.Button.from_icon_name ( - "edit-delete-symbolic" - ) { - tooltip_text = _("Remove Plugin from Rack") - }; - button_box.append (delete_instance_button); - } - - private void build_events () { - gain_knob.value_changed.connect ((db) => { - plugin.mix_gain = (float) Utils.Math.convert_db_to_gain (db); - }); - - active_switch.notify["active"].connect (() => { - plugin.active = active_switch.active; - }); - - if (plugin.ui != null) { - show_ui_button.clicked.connect (() => { - Application.event_bus.show_plugin_ui (plugin); - }); - } - - delete_instance_button.clicked.connect (() => { - rack_shell.delete_plugin_item (this); - }); - - plugin.notify["active"].connect (() => { - active_switch.active = plugin.active; - }); - - plugin.notify["mix-gain"].connect (() => { - gain_knob.value = Utils.Math.convert_gain_to_db (plugin.mix_gain); - }); - } - - public void capture_attention () { - Timeout.add (100, () => { - add_css_class ("capture-attention"); - - Timeout.add_seconds (1, () => { - remove_css_class ("capture-attention"); - return false; - }); - - return false; - }); - } - } -} diff --git a/src/Shell/Widgets/Display/DSPMenuItem.vala b/src/Shell/Widgets/Display/DSPMenuItem.vala deleted file mode 100644 index 678385f1..00000000 --- a/src/Shell/Widgets/Display/DSPMenuItem.vala +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Shell.Widgets.Display { - public class DSPMenuItem : Gtk.ListBoxRow { - public unowned AudioPlugin plugin { get; set; } - - private Gtk.Button insert_button; - - public DSPMenuItem (AudioPlugin plugin, Core.Racks.DSPRack dsp_rack) { - Object ( - plugin: plugin, - height_request: 68 - ); - - build_ui (); - - insert_button.clicked.connect (() => { - try { - dsp_rack.append (plugin.duplicate ()); - } catch (PluginError e) { - Console.log ("Failed to add plugin %s with error %s".printf (plugin.name, e.message), - Console.LogLevel.WARNING); - } - }); - } - - private void build_ui () { - add_css_class ("plugin-item"); - - var menu_item_grid = new Gtk.Grid (); - set_child (menu_item_grid); - - var plugin_name_label = new Gtk.Label (plugin.name) { - halign = Gtk.Align.START, - hexpand = true - }; - plugin_name_label.add_css_class ("plugin-item-name"); - menu_item_grid.attach (plugin_name_label, 0, 0); - - var extra_info_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 4); - extra_info_box.add_css_class ("plugin-item-info"); - menu_item_grid.attach (extra_info_box, 0, 1); - - var extra_info_labels = new string[0]; - if (plugin.author_name != null && plugin.author_name.length > 0) { - extra_info_labels.resize (1); - if (plugin.author_name.length > 32) { - extra_info_labels[0] = plugin.author_name.substring (0, 32) + "…"; - } else { - extra_info_labels[0] = plugin.author_name; - } - } - - if (plugin.author_homepage != null && plugin.author_homepage.length > 0) { - extra_info_labels.resize (extra_info_labels.length + 1); - - if (plugin.author_homepage.length > 36) { - extra_info_labels[extra_info_labels.length - 1] = - plugin.author_homepage.substring (0, 36) + "…"; - } else { - extra_info_labels[extra_info_labels.length - 1] = plugin.author_homepage; - } - - } - - if (extra_info_labels.length > 0) { - extra_info_box.append ( - new Gtk.Label (string.joinv (" ⏺ ", extra_info_labels)) { - opacity = 0.5 - } - ); - } - - var plugin_protocol_icon = ""; - switch (plugin.protocol) { - case AudioPlugin.Protocol.LV2: - plugin_protocol_icon = "lv2"; - break; - case AudioPlugin.Protocol.CARLA: - plugin_protocol_icon = "carla"; - break; - case AudioPlugin.Protocol.LADSPA: - plugin_protocol_icon = "ladspa"; - break; - case AudioPlugin.Protocol.NATIVE: - plugin_protocol_icon = "native"; - break; - } - - if (plugin_protocol_icon.length > 0) { - plugin_protocol_icon = - "/com/github/subhadeepjasu/ensembles/icons/scalable/emblems/plugin-audio-" + - plugin_protocol_icon + "-symbolic.svg"; - - var icon = new Gtk.Image.from_resource (plugin_protocol_icon); - icon.add_css_class ("plugin-item-protocol"); - extra_info_box.append (icon); - } - - insert_button = new Gtk.Button.from_icon_name ("insert-object-symbolic") { - valign = Gtk.Align.START - }; - insert_button.add_css_class ("plugin-item-insert-button"); - menu_item_grid.attach (insert_button, 1, 0, 1, 2); - } - } -} diff --git a/src/Shell/Widgets/Display/DisplayWindow.vala b/src/Shell/Widgets/Display/DisplayWindow.vala deleted file mode 100644 index 1c31f7a6..00000000 --- a/src/Shell/Widgets/Display/DisplayWindow.vala +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Shell.Widgets.Display; - -namespace Ensembles.Shell.Layouts.Display { - /** - * Display Window is a window that may contain other widgets - * that are to be displayed inside the info display of Ensembles - */ - public class DisplayWindow : WheelScrollableWidget { - private Gtk.Button close_button; - private Gtk.Box header_bar; - private Gtk.Box window_title_box; - private Gtk.Label title_label; - private Gtk.Label subtitle_label; - private Gtk.Box header_container; - - private string _title; - public string title { - get { - return _title; - } - set { - _title = value; - if (title_label != null) { - title_label.set_text (value); - } - } - } - - private string _subtitle; - public string subtitle { - get { - return _subtitle; - } - set { - _subtitle = value; - if (subtitle_label != null) { - subtitle_label.set_text (value); - } - } - } - - private Gtk.Widget _header_addon_widget; - public Gtk.Widget header_addon_widget { - get { - return _header_addon_widget; - } - set { - _header_addon_widget = value; - } - } - - public signal void close (); - - construct { - build_ui (); - } - - public DisplayWindow (string title = "", string subtitle = "") { - Object ( - title: title, - subtitle: subtitle - ); - } - - private void build_ui () { - add_css_class ("display-window-background"); - orientation = Gtk.Orientation.VERTICAL; - - header_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - spacing = 16 - }; - append (header_bar); - header_bar.add_css_class ("display-window-header-bar"); - - close_button = new Gtk.Button.from_icon_name ("application-exit-symbolic") { - halign = Gtk.Align.START, - valign = Gtk.Align.CENTER, - width_request = 36, - height_request = 36 - }; - close_button.add_css_class ("accented"); - close_button.clicked.connect (() => { close (); }); - header_bar.append (close_button); - - window_title_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - halign = Gtk.Align.START, - valign = Gtk.Align.CENTER - }; - - title_label = new Gtk.Label (title) { - xalign = 0 - }; - title_label.add_css_class ("title"); - window_title_box.append (title_label); - - subtitle_label = new Gtk.Label (subtitle) { - xalign = 0 - }; - subtitle_label.add_css_class ("subtitle"); - window_title_box.append (subtitle_label); - - if (Application.kiosk_mode) { - header_bar.append (window_title_box); - } else { - var window_handle = new Gtk.WindowHandle () { - hexpand = true - }; - header_bar.append (window_handle); - window_handle.set_child (window_title_box); - } - - header_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); - header_bar.append (header_container); - } - - public void set_child (Gtk.Widget widget) { - append (widget); - } - - public void add_to_header (Gtk.Widget widget) { - header_container.append (widget); - } - } -} diff --git a/src/Shell/Widgets/Display/StyleMenuItem.vala b/src/Shell/Widgets/Display/StyleMenuItem.vala deleted file mode 100644 index 9f0c95a5..00000000 --- a/src/Shell/Widgets/Display/StyleMenuItem.vala +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles.Shell.Widgets.Display { - public class StyleMenuItem : Gtk.ListBoxRow { - public Style style { get; set; } - public bool show_category { get; set; } - - public StyleMenuItem (Style style, bool show_category = false) { - Object ( - style: style, - show_category: show_category - ); - - build_ui (); - } - - private void build_ui () { - add_css_class ("menu-item"); - - var menu_item_grid = new Gtk.Grid (); - set_child (menu_item_grid); - - var style_name_label = new Gtk.Label (style.name) { - halign = Gtk.Align.START, - hexpand = true - }; - style_name_label.add_css_class ("menu-item-name"); - menu_item_grid.attach (style_name_label, 0, 0, 1, 2); - - var tempo_label = new Gtk.Label (style.time_signature_n.to_string () + - "/" + - style.time_signature_d.to_string () + - "\t" + - (((double)style.tempo / 100.0 >= 1) ? "" : " ") + - "♩ = " + style.tempo.to_string ()) { - halign = Gtk.Align.END - }; - tempo_label.add_css_class ("menu-item-description"); - menu_item_grid.attach (tempo_label, 1, 1, 1, 1); - - var category_label = new Gtk.Label (""); - if (show_category) { - category_label.set_text (style.genre); - category_label.add_css_class ("menu-item-category"); - } - - menu_item_grid.attach (category_label, 1, 0, 2, 1); - - if (style.copyright_notice != null && style.copyright_notice != "") { - var copyright_button = new Gtk.Button.from_icon_name ("text-x-copying-symbolic") { - margin_top = 6, - margin_start = 4, - margin_end = 4, - tooltip_text = style.copyright_notice - }; - copyright_button.add_css_class ("menu-item-icon"); - menu_item_grid.attach (copyright_button, 2, 1, 1, 1); - } - } - } -} diff --git a/src/Shell/Widgets/Display/VoiceMenuItem.vala b/src/Shell/Widgets/Display/VoiceMenuItem.vala deleted file mode 100644 index 618a3958..00000000 --- a/src/Shell/Widgets/Display/VoiceMenuItem.vala +++ /dev/null @@ -1,108 +0,0 @@ -/* -* Copyright 2020-2023 Subhadeep Jasu -* SPDX-License-Identifier: GPL-3.0-or-later -*/ - -using Ensembles.Models; -using Ensembles.Core.Plugins.AudioPlugins; - -namespace Ensembles.Shell.Widgets.Display { - public class VoiceMenuItem : Gtk.ListBoxRow { - public uint16 index { get; protected set; } - - /** Whether this voice item is a plugin or the SoundFont */ - public bool is_plugin { get; protected set; } - - // If the voice is a plugin - public unowned AudioPlugin plugin { get; protected set; } - protected unowned Layouts.Display.VoiceScreen rack_shell { get; protected set; } - public Gtk.Button show_ui_button; - - // If the voice is from the SoundFont - public Voice voice { get; protected set; } - - public bool show_category { get; set; } - - public VoiceMenuItem ( - uint16 index, - Voice voice, - AudioPlugin? plugin = null, - bool show_category = false - ) { - Object ( - index: index, - voice: voice, - plugin: plugin, - is_plugin: plugin != null, - show_category: show_category - ); - - build_ui (); - } - - private void build_ui () { - add_css_class ("menu-item"); - - var menu_item_grid = new Gtk.Grid () { - column_spacing = 16, - row_spacing = 0 - }; - set_child (menu_item_grid); - - if (show_category) { - var category_label = new Gtk.Label ("") { - xalign = 0 - }; - var protocol_name = ""; - if (is_plugin) { - switch (plugin.protocol) { - case AudioPlugin.Protocol.LV2: - protocol_name = "LV2"; - break; - case AudioPlugin.Protocol.CARLA: - protocol_name = "Carla"; - break; - case AudioPlugin.Protocol.LADSPA: - protocol_name = "LADSPA"; - break; - case AudioPlugin.Protocol.NATIVE: - protocol_name = "GTK"; - break; - } - } - - category_label.set_text ( - is_plugin ? protocol_name.up () + " PLUGINS" : voice.category.up () - ); - category_label.add_css_class ("menu-item-category"); - menu_item_grid.attach (category_label, 0, 0, 3, 1); - } - - var index_label = new Gtk.Label ("%03d".printf (index)) { - width_chars = 3, - xalign = 0 - }; - index_label.add_css_class ("menu-item-index"); - menu_item_grid.attach (index_label, 0, 1); - - var voice_name_label = new Gtk.Label (is_plugin ? plugin.name : voice.name) { - halign = Gtk.Align.START, - hexpand = true, - height_request = 48 - }; - voice_name_label.add_css_class ("menu-item-name"); - menu_item_grid.attach (voice_name_label, 1, 1); - - if (is_plugin && plugin.ui != null) { - show_ui_button = new Gtk.Button.from_icon_name ("preferences-other-symbolic") { - margin_top = 6, - margin_start = 4, - margin_end = 4, - width_request = 80, - tooltip_text = _("Show Plugin UI") - }; - menu_item_grid.attach (show_ui_button, 2, 1, 1, 1); - } - } - } -} diff --git a/src/Shell/Widgets/Display/WheelScrollableWidget.vala b/src/Shell/Widgets/Display/WheelScrollableWidget.vala deleted file mode 100644 index 4f71b800..00000000 --- a/src/Shell/Widgets/Display/WheelScrollableWidget.vala +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - namespace Ensembles.Shell.Widgets.Display { - /** - * Widget that responds to the Ensembles Scroll Wheel widget - */ - public abstract class WheelScrollableWidget : Gtk.Box { - public int scroll_wheel_location; - public int max_value = -1; - public int min_value = -1; - public signal void wheel_scrolled_absolute (int value); - public signal void wheel_scrolled_relative (bool direction, int amount); - - public void scroll_wheel_scroll (bool direction, int amount) { - if (max_value != -1 && min_value != -1) { - if (direction) { - if (scroll_wheel_location + amount < max_value) { - scroll_wheel_location += amount; - } else if (scroll_wheel_location != max_value) { - scroll_wheel_location = max_value; - } - } else { - if (scroll_wheel_location - amount > min_value) { - scroll_wheel_location -= amount; - } else if (scroll_wheel_location != min_value) { - scroll_wheel_location = min_value; - } - } - - wheel_scrolled_absolute (scroll_wheel_location); - } else { - wheel_scrolled_relative (direction, amount); - } - } - } -} diff --git a/src/Shell/Widgets/Key.vala b/src/Shell/Widgets/Key.vala deleted file mode 100644 index a34270ad..00000000 --- a/src/Shell/Widgets/Key.vala +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Widgets { - public class Key : Gtk.Box { - public uint8 index { get; protected set; } - public bool is_black { get; protected set; } - private Gtk.GestureDrag motion_controller; - private Gtk.GestureClick click_gesture; - - private bool _active; - public bool active { - get { - return _active; - } - set { - _active = value; - if (value) { - add_css_class ("activated"); - } else { - remove_css_class ("activated"); - } - } - } - - public signal void pressed (uint8 index); - public signal void released (uint8 index); - public signal void motion (uint8 index, double x, double y); - - public Key (uint8 index, bool is_black) { - Object ( - index: index, - is_black: is_black - ); - - if (is_black) { - add_css_class ("black"); - } - } - - construct { - build_ui (); - build_event (); - } - - private void build_ui () { - add_css_class ("key"); - } - - private void build_event () { - motion_controller = new Gtk.GestureDrag (); - add_controller (motion_controller); - - click_gesture = new Gtk.GestureClick (); - click_gesture.pressed.connect ((n_press, x, y) => { - pressed (index); - }); - click_gesture.released.connect (() => { - released (index); - }); - - motion_controller.drag_update.connect ((x, y) => { - if (active) { - this.motion (index, x / get_allocated_width (), y / get_allocated_height ()); - } - }); - add_controller (click_gesture); - } - - public bool inside (Octave parent, double x, double y) { - double _x, _y; - parent.translate_coordinates (this, x, y, out _x, out _y); - return contains (_x, _y); - } - } -} diff --git a/src/Shell/Widgets/Keyboard.vala b/src/Shell/Widgets/Keyboard.vala deleted file mode 100644 index cc2c0f66..00000000 --- a/src/Shell/Widgets/Keyboard.vala +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Widgets { - public class Keyboard : Gtk.Widget, Gtk.Accessible { - public uint8 n_octaves { get; protected set; } - private Octave[] octaves; - private bool[] key_pressed; - - private double[] motion_x; - private double[] motion_y; - - private bool update = true; - private int width; - private int height; - - public uint8 motion_x_control = MIDI.Control.EXPLICIT_PITCH; - public uint8 motion_y_control = MIDI.Control.CUT_OFF; - public bool motion_control_enabled = false; - - private int control_x = 64; - private int previous_control_y = 64; - private int control_y = 40; - - private uint8 _zoom_level; - public uint8 zoom_level { - get { - return _zoom_level; - } - set { - _zoom_level = value.clamp (0, 255); - if (_zoom_level == 0) { - width_request = -1; - } else { - width_request = value * 16 + 1000; - } - } - } - - public int8 octave_offset { get; set; } - - public signal void key_event (Fluid.MIDIEvent midi_event); - - public Keyboard (uint8 n_octaves) { - Object ( - accessible_role: Gtk.AccessibleRole.TABLE, - name: "keyboard", - css_name: "keyboard", - layout_manager: new Gtk.BoxLayout (Gtk.Orientation.HORIZONTAL), - height_request: 100, - n_octaves: n_octaves - ); - - build_ui (); - } - - ~Keyboard () { - update = false; - } - - construct { - build_events (); - } - - private void build_ui () { - octaves = new Octave[n_octaves]; - key_pressed = new bool[n_octaves * 12]; - motion_x = new double[n_octaves]; - motion_y = new double[n_octaves]; - for (uint8 i = 0; i < n_octaves; i++) { - var octave = new Octave (this, i); - octave.key_pressed.connect (handle_key_press); - octave.key_released.connect (handle_key_release); - octave.key_motion.connect (handle_key_motion); - octave.set_parent (this); - octaves[i] = (owned) octave; - - motion_x[i] = 0; - motion_y[i] = 0; - } - - Timeout.add (80, () => { - Idle.add (() => { - if (width != get_allocated_width () || height != get_allocated_height ()) { - for (uint8 i = 0; i < n_octaves; i++) { - octaves[i].draw_keys (); - } - - width = get_allocated_width (); - height = get_allocated_height (); - } - - return false; - }, Priority.LOW); - return update; - }, Priority.LOW); - } - - private void build_events () { - this.destroy.connect (() => { - update = false; - }); - } - - private void handle_key_press (uint8 key_index) { - var event = new Fluid.MIDIEvent (); - event.set_channel (17); // Channel 17 handles user key events - event.set_type (MIDI.EventType.NOTE_ON); - event.set_key (key_index + 12 * octave_offset); - event.set_velocity (100); - - key_event (event); - - key_pressed[key_index] = true; - } - - private void handle_key_release (uint8 key_index) { - var event = new Fluid.MIDIEvent (); - event.set_channel (17); // Channel 17 handles user key events - event.set_type (MIDI.EventType.NOTE_OFF); - event.set_key (key_index + 12 * octave_offset); - - key_event (event); - - previous_control_y = control_y; - key_pressed[key_index] = false; - - if (motion_control_enabled) { - var any_pressed = false; - for (int i = 0; i < key_pressed.length; i++) { - any_pressed = any_pressed || key_pressed[i]; - } - - if (!any_pressed) { - var event_x = new Fluid.MIDIEvent (); - event_x.set_channel (17); - event_x.set_type (MIDI.EventType.CONTROL_CHANGE); - event_x.set_control (motion_x_control); - event_x.set_value (64); - key_event (event_x); - } - } - } - - private void handle_key_motion (uint8 octave_index, double x, double y) { - if (motion_control_enabled) { - motion_x[octave_index] = x; - motion_y[octave_index] = y; - - double avg_x = 0; - double avg_y = 0; - uint8 n = (uint8) octaves.length; - - for (uint8 i = 0; i < n; i++) { - avg_x += motion_x[i]; - avg_y += motion_y[i]; - } - - var event_x = new Fluid.MIDIEvent (); - event_x.set_channel (17); // Channel 17 handles user key events - event_x.set_type (MIDI.EventType.CONTROL_CHANGE); - event_x.set_control (motion_x_control); - control_x = (64 + (int) (127 * avg_x / n)); - event_x.set_value (control_x); - if (control_x > 127) { - control_x = 127; - } else if (control_x < 0) { - control_x = 0; - } - - key_event (event_x); - - var event_y = new Fluid.MIDIEvent (); - event_y.set_channel (17); // Channel 17 handles user key events - event_y.set_type (MIDI.EventType.CONTROL_CHANGE); - event_y.set_control (motion_y_control); - control_y = previous_control_y + (int) (127 * avg_y / n); - if (control_y > 127) { - control_y = 127; - } else if (control_y < 0) { - control_y = 0; - } - - event_y.set_value (control_y); - - key_event (event_y); - } - } - - public void set_key_illumination (uint8 key_index, bool active) { - uint8 octave_index = (key_index / 12) - octave_offset; - octaves[octave_index].set_key_illumination (key_index - (octave_offset * 12), active); - } - } -} diff --git a/src/Shell/Widgets/Knob.vala b/src/Shell/Widgets/Knob.vala deleted file mode 100644 index 1b477af3..00000000 --- a/src/Shell/Widgets/Knob.vala +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Widgets { - /** - * A `Knob` is a rotary control used to select a numeric value - */ - public class Knob : Gtk.Widget, Gtk.Accessible { - /** - * The adjustment that is controlled by the knob. - */ - public Gtk.Adjustment adjustment { get; set; } - /** - * Current value of the knob. - */ - public double value { - get { - return adjustment.value; - } - set { - pointing_angle = Utils.Math.map_range_unclamped ( - value, - adjustment.lower, - adjustment.upper, - pointing_angle_lower, - pointing_angle_lower + pointing_angle_upper - ); - - if (pointing_angle < pointing_angle_lower) { - pointing_angle = pointing_angle_lower; - } else if (pointing_angle > pointing_angle_upper + pointing_angle_lower) { - pointing_angle = pointing_angle_upper + pointing_angle_lower; - } - - adjustment.value = value; - } - } - - // Knob UI - private Gtk.BinLayout bin_layout; - protected Gtk.Box knob_socket_graphic; - protected Gtk.Box knob_cover; - protected Gtk.DrawingArea knob_meter; - protected Gtk.Box knob_background; - - protected List marks; - - private Gtk.GestureRotate touch_rotation_gesture; - private Gtk.GestureDrag drag_gesture; - private Gtk.EventControllerScroll wheel_gesture; - - /** - * The current angle in degrees towards which the knob is pointing. - */ - public double pointing_angle { get; private set; } - /** - * The angle in degrees which the knob will point towards - * when `value` is minimum. - */ - public double pointing_angle_lower { get; protected set; } - /** - * The angle in degrees which the knob will point towards - * when `value` is maximum. - */ - public double pointing_angle_upper { get; protected set; } - private double current_deg; - private double previous_deg; - - /** - * Number of decimal places that are displayed in the value. - */ - public uint8 digits { get; set; } - /** - * Whether the current value is displayed as a string inside the knob. - */ - public bool draw_value { get; set; } - - private uint radius = 0; - - public signal void value_changed (double value); - - /** - * Creates a new `Knob` widget. - * - * @param adjustment the [class@Gtk.Adjustment] which sets the range of - * the knob, or null to create a new adjustment. - */ - public Knob (Gtk.Adjustment? adjustment = null) { - Object ( - name: "knob", - accessible_role: Gtk.AccessibleRole.SPIN_BUTTON - ); - - if (adjustment != null) { - this.adjustment.lower = adjustment.lower; - this.adjustment.upper = adjustment.upper; - this.adjustment.step_increment = adjustment.step_increment; - } - - pointing_angle = pointing_angle_lower; - } - - /** - * Creates a new `Knob` widget with a range from min to max. - * - * Let's the user input a number between min and max (including min and - * max) with the increment step. step must be nonzero; it’s the distance - * the meter moves to adjust the knob value. - * - * @param min minimum value - * @param max maximum value - * @param step increment (tick size) - */ - public Knob.with_range (double min, double max, double step) { - Object ( - name: "knob", - accessible_role: Gtk.AccessibleRole.SPIN_BUTTON - ); - this.adjustment.lower = min; - this.adjustment.upper = max; - this.adjustment.step_increment = step; - pointing_angle = pointing_angle_lower; - } - - construct { - adjustment = new Gtk.Adjustment (0, 0, 100, - 1, 0, 0); - marks = new List (); - pointing_angle_upper = 275; - pointing_angle_lower = 135; - build_layout (); - realize.connect (() => { - build_ui (); - }); - build_events (); - } - - private void build_layout () { - bin_layout = new Gtk.BinLayout (); - set_layout_manager (bin_layout); - } - - private void build_ui () { - add_css_class ("knob"); - - var width = get_allocated_width () | width_request; - var height = get_allocated_height () | height_request; - - var diameter = width < height ? width : height; - - radius = diameter / 2; - - if (knob_background == null) { - knob_background = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - knob_background.add_css_class ("knob-background"); - knob_background.set_parent (this); - } - knob_background.width_request = diameter; - knob_background.height_request = diameter; - - if (knob_cover == null) { - knob_cover = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - knob_cover.add_css_class ("knob-cover"); - knob_cover.set_parent (this); - } - - knob_cover.width_request = diameter; - knob_cover.height_request = diameter; - - if (knob_meter == null) { - knob_meter = new Gtk.DrawingArea () { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER, - width_request = diameter, - height_request = diameter - }; - knob_meter.set_parent (this); - - knob_meter.set_draw_func (draw_meter); - } - - knob_meter.width_request = diameter; - knob_meter.height_request = diameter; - } - - protected void draw_meter (Gtk.DrawingArea meter, Cairo.Context ctx, int width, int height) { - var gb = Utils.Math.map_range_unclamped ( - adjustment.value, - adjustment.lower, - adjustment.upper, - 0, - 1 - ); - // Draw meter - ctx.arc (radius + 0.2, radius, radius - 7, - pointing_angle_lower * (Math.PI / 180.0), - pointing_angle * (Math.PI / 180.0)); - ctx.set_line_width (2); - ctx.set_source_rgba (1 - gb, gb, gb, 1); - ctx.stroke (); - - // Draw marks - foreach (var mark in marks) { - var mark_angle = Utils.Math.map_range_unclamped ( - mark, - adjustment.lower, - adjustment.upper, - pointing_angle_lower, - pointing_angle_lower + pointing_angle_upper - ); - ctx.arc ( - radius + 0.2, radius, radius - 2, - (mark_angle - 1) * (Math.PI / 180.0), - (mark_angle + 1) * (Math.PI / 180.0) - ); - - ctx.set_source_rgba (1, 1, 1, adjustment.value == mark ? 1 : 0.3); - ctx.stroke (); - } - - if (draw_value) { - string text = (adjustment.step_increment >= 1 ? "%.lf" : "%.1lf").printf (adjustment.value); - ctx.select_font_face ("Michroma", Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL); - ctx.set_font_size (Math.fmax (10, radius / 3)); - - Cairo.TextExtents extents; - ctx.text_extents (text, out extents); - ctx.move_to (radius - (extents.width / 2), radius + (extents.height / 2)); - ctx.set_source_rgb (0.8, 0.8, 0.8); - ctx.show_text (text); - } - } - - private void build_events () { - drag_gesture = new Gtk.GestureDrag () { - propagation_phase = Gtk.PropagationPhase.CAPTURE, - name = "drag-rotation-capture" - }; - add_controller (drag_gesture); - - drag_gesture.drag_begin.connect ((x, y) => { - previous_deg = Math.atan2 (x - radius, y - radius) * (180 / Math.PI); - }); - - drag_gesture.drag_update.connect ((x, y) => { - double start_x; - double start_y; - drag_gesture.get_start_point (out start_x, out start_y); - - double relative_x = start_x + x; - double relative_y = start_y + y; - - current_deg = Math.atan2 (relative_x - radius, relative_y - radius) * (180 / Math.PI); - - var delta_deg = previous_deg - current_deg; - - if (delta_deg < 270 && delta_deg > -270) { - pointing_angle += delta_deg; - - if (pointing_angle < pointing_angle_lower) { - pointing_angle = pointing_angle_lower; - } else if (pointing_angle > pointing_angle_upper + pointing_angle_lower) { - pointing_angle = pointing_angle_upper + pointing_angle_lower; - } - - adjustment.value = Utils.Math.map_range_unclamped ( - pointing_angle, - pointing_angle_lower, - pointing_angle_lower + pointing_angle_upper, - adjustment.lower, - adjustment.upper - ); - value_changed (adjustment.value); - } - - previous_deg = current_deg; - }); - - touch_rotation_gesture = new Gtk.GestureRotate (); - add_controller (touch_rotation_gesture); - - wheel_gesture = new Gtk.EventControllerScroll (Gtk.EventControllerScrollFlags.VERTICAL); - add_controller (wheel_gesture); - - wheel_gesture.scroll.connect ((dx, dy) => { - var value = adjustment.value - adjustment.step_increment * dy; - pointing_angle = Utils.Math.map_range_unclamped ( - value, - adjustment.lower, - adjustment.upper, - pointing_angle_lower, - pointing_angle_lower + pointing_angle_upper - ); - - if (value > adjustment.upper) { - value = adjustment.upper; - } else if (value < adjustment.lower) { - value = adjustment.lower; - } - - if (pointing_angle < pointing_angle_lower) { - pointing_angle = pointing_angle_lower; - } else if (pointing_angle > pointing_angle_upper + pointing_angle_lower) { - pointing_angle = pointing_angle_upper + pointing_angle_lower; - } - - adjustment.value = value; - value_changed (value); - return true; - }); - - touch_rotation_gesture.angle_changed.connect ((angle, angle_delta) => { - pointing_angle += angle_delta; - - if (pointing_angle < pointing_angle_lower) { - pointing_angle = pointing_angle_lower; - } else if (pointing_angle > pointing_angle_upper + pointing_angle_lower) { - pointing_angle = pointing_angle_upper + pointing_angle_lower; - } - - adjustment.value = Utils.Math.map_range_unclamped ( - pointing_angle, - pointing_angle_lower, - pointing_angle_lower + pointing_angle_upper, - adjustment.lower, - adjustment.upper - ); - value_changed (adjustment.value); - }); - - adjustment.value_changed.connect (() => { - Idle.add (() => { - knob_meter.queue_draw (); - return false; - }); - }); - } - - /** - * Adds a mark at value. - * - * A mark is indicated visually by drawing a tick mark outside the knob. - * - * @param value the value at which the mark is placed, must be between - * the lower and upper limits of the scales’ adjustment - */ - public void add_mark (double value) { - marks.append (value); - } - - /** - * Removes any marks that have been added. - */ - public void clear_marks () { - foreach (var mark in marks) { - marks.remove (mark); - } - } - } -} diff --git a/src/Shell/Widgets/Octave.vala b/src/Shell/Widgets/Octave.vala deleted file mode 100644 index 4d96285d..00000000 --- a/src/Shell/Widgets/Octave.vala +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Shell.Widgets { - public class Octave : Gtk.Widget, Gtk.Accessible { - public uint8 index { get; protected set; } - public unowned Keyboard keyboard { get; protected set; } - private const uint8[] BLACK_KEYS = { 1, 3, 6, 8, 10 }; - private const uint8[] WHITE_KEYS = { 0, 2, 4, 5, 7, 9, 11 }; - private const double[] BLACK_KEY_OFFSETS = { 0.932, 2.758, 5.56, 7.38, 9.24 }; - - Gtk.Box white_key_box; - private Key[] keys = new Key[12]; - - private double[] motion_x = new double[12]; - private double[] motion_y = new double[12]; - - public signal void key_pressed (uint8 index); - public signal void key_released (uint8 index); - public signal void key_motion (uint8 index, double x, double y); - - public Octave (Keyboard keyboard, uint8 index) { - Object ( - index: index, - name: "octave", - accessible_role: Gtk.AccessibleRole.TABLE, - keyboard: keyboard, - accessible_role: Gtk.AccessibleRole.TABLE, - layout_manager: new Gtk.BinLayout (), - width_request: 200, - height_request: 100, - hexpand: true, - vexpand: true - ); - - for (uint8 i = 0; i < 12; i++) { - motion_x[i] = 0; - motion_y[i] = 0; - } - - build_ui (); - } - - private void build_ui () { - white_key_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { - hexpand = true, - vexpand = true, - homogeneous = true - }; - white_key_box.set_parent (this); - - keys = new Key[12]; - // Arrange all the white keys - for (uint8 i = 0; i < 7; i++) { - var key = new Key (WHITE_KEYS[i], false); - key.pressed.connect (handle_key_press); - key.released.connect (handle_key_release); - key.motion.connect (handle_key_motion); - white_key_box.append (key); - keys[WHITE_KEYS[i]] = (owned) key; - } - - // Arrange all the black keys - for (uint8 i = 0; i < 5; i++) { - var key = new Key (BLACK_KEYS[i], true); - key.pressed.connect (handle_key_press); - key.released.connect (handle_key_release); - key.motion.connect (handle_key_motion); - key.set_parent (this); - keys[BLACK_KEYS[i]] = (owned) key; - } - } - - public void draw_keys () { - int w_max = get_allocated_width (); - double offset = w_max * 0.09; - int h_max = get_allocated_height (); - int black_key_width = w_max / 10; - int black_key_height = (int) (h_max / 1.5); - - for (uint8 i = 0; i < 5; i++) { - int left, right, bottom; - box_to_margins ( - (int) (BLACK_KEY_OFFSETS[i] * offset), - 0, - black_key_width, - black_key_height, - w_max, - h_max, - out left, - out right, - out bottom - ); - keys[BLACK_KEYS[i]].margin_start = left; - keys[BLACK_KEYS[i]].margin_end = right; - keys[BLACK_KEYS[i]].margin_bottom = bottom; - } - } - - /** - * Calculate margins based on the given box and parent box dimensions - */ - private void box_to_margins ( - int x, int y, int width, int height, int w_max, int h_max, - out int left, out int right, out int bottom - ) { - left = x; - right = w_max - (x + width); - bottom = h_max - (y + height); - } - - private void handle_key_press (uint8 key_index) { - key_pressed (index * 12 + key_index); - } - - private void handle_key_release (uint8 key_index) { - key_released (index * 12 + key_index); - } - - private void handle_key_motion (uint8 key_index, double x, double y) { - motion_x[key_index] = x; - motion_y[key_index] = y; - - double avg_x = 0; - double avg_y = 0; - - for (uint8 i = 0; i < 12; i++) { - avg_x += motion_x[key_index]; - avg_y += motion_y[key_index]; - } - - key_motion (index, avg_x / 12, avg_y / 12); - } - - public void set_key_illumination (uint8 key_index, bool active) { - uint8 actual_key_index = key_index - (index * 12); - keys[actual_key_index].active = active; - } - } -} diff --git a/src/Utils/AccentColors.vala b/src/Utils/AccentColors.vala deleted file mode 100644 index 572e82ec..00000000 --- a/src/Utils/AccentColors.vala +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - public class AccentColors { - private const string COMPLIMENTARY_ACCENT_COLORS_TEMPLATE = - " - @define-color accent_color_complimentary %s; - @define-color accent_color_complimentary_alternate %s; - "; - - private static string complimentary_accent_colors_strawberry - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@ORANGE_500"); - private static string complimentary_accent_colors_orange - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BLUEBERRY_500", "@MINT_500"); - private static string complimentary_accent_colors_banana - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@ORANGE_500"); - private static string complimentary_accent_colors_lime - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@BUBBLEGUM_500"); - private static string complimentary_accent_colors_mint - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@SILVER_500"); - private static string complimentary_accent_colors_blueberry - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@GRAPE_500", "@MINT_500"); - private static string complimentary_accent_colors_bubblegum - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@GRAPE_500"); - private static string complimentary_accent_colors_cocoa - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@BANANA_500"); - private static string complimentary_accent_colors_grape - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@STRAWBERRY_300", "@BUBBLEGUM_500"); - private static string complimentary_accent_colors_silver - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BLUEBERRY_300", "@STRAWBERRY_300"); - private static string complimentary_accent_colors_slate - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@BANANA_500"); - - public static uint8[]? get_complementary (string theme_color) { - complimentary_accent_colors_strawberry - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@ORANGE_500"); - complimentary_accent_colors_orange - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BLUEBERRY_500", "@MINT_500"); - complimentary_accent_colors_banana - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@ORANGE_500"); - complimentary_accent_colors_lime - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@BUBBLEGUM_500"); - complimentary_accent_colors_mint - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BANANA_500", "@SILVER_500"); - complimentary_accent_colors_blueberry - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@GRAPE_500", "@MINT_500"); - complimentary_accent_colors_bubblegum - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@GRAPE_500"); - complimentary_accent_colors_cocoa - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@BANANA_500"); - complimentary_accent_colors_grape - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@STRAWBERRY_300", "@BUBBLEGUM_500"); - complimentary_accent_colors_silver - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@BLUEBERRY_300", "@STRAWBERRY_300"); - complimentary_accent_colors_slate - = COMPLIMENTARY_ACCENT_COLORS_TEMPLATE.printf ("@MINT_500", "@BANANA_500"); - - switch (theme_color) { - case "strawberry": - return complimentary_accent_colors_strawberry.data; - case "orange": - return complimentary_accent_colors_orange.data; - case "banana": - return complimentary_accent_colors_banana.data; - case "lime": - return complimentary_accent_colors_lime.data; - case "mint": - return complimentary_accent_colors_mint.data; - case "blueberry": - return complimentary_accent_colors_blueberry.data; - case "grape": - return complimentary_accent_colors_grape.data; - case "bubblegum": - return complimentary_accent_colors_bubblegum.data; - case "cocoa": - return complimentary_accent_colors_cocoa.data; - case "silver": - return complimentary_accent_colors_silver.data; - case "slate": - case "black": - return complimentary_accent_colors_slate.data; - } - - return complimentary_accent_colors_blueberry.data; - } - } -} diff --git a/src/Utils/Console.vala b/src/Utils/Console.vala deleted file mode 100644 index dc4ffcf5..00000000 --- a/src/Utils/Console.vala +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - public class Console { - private const string RED = "\x1B[31m"; - private const string GRN = "\x1B[32m"; - private const string YEL = "\x1B[33m"; - private const string BLU = "\x1B[34m"; - private const string MAG = "\x1B[35m"; - private const string CYN = "\x1B[36m"; - private const string WHT = "\x1B[37m"; - private const string BOLD = "\x1B[1m"; - private const string RESET = "\x1B[0m"; - - public static void get_console_header () { - print (MAG); - print ("███████ ███ ██ ███████ ███████ ███ ███ ██████ ██ ███████ ███████\n"); - print ("██ ████ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██\n"); - print ("█████ ██ ██ ██ ███████ █████ ██ ████ ██ ██████ ██ █████ ███████\n"); - print ("██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n"); - print ("███████ ██ ████ ███████ ███████ ██ ██ ██████ ███████ ███████ ███████\n"); - print (RED); - print ("============================================================================\n"); - print (YEL); - print (_("VERSION: %s, DISPLAY VERSION: %s | (c) SUBHADEEP JASU 2020 - 2023\n"), - Constants.VERSION, Constants.DISPLAYVER); - print (RED); - print ("----------------------------------------------------------------------------\n"); - print (RESET); - } - - public enum LogLevel { - SUCCESS, - TRACE, - WARNING, - ERROR, - } - - public static void log (T object, LogLevel log_level = LogLevel.TRACE) { - DateTime date_time = new DateTime.now_utc (); - string message = ""; - if (typeof (T) == Type.STRING) { - message = (string) object; - } else if (typeof (T) == typeof (Error)) { - message = ((Error) object).domain.to_string () - .replace ("-quark", "") - .replace ("-", " ") - .up (); - message += ": " + ((Error) object).message; - } - - switch (log_level) { - case SUCCESS: - if (Application.verbose) { - print ("%s▎%s%sSUCCESS %s[%s%s%s]: %s\n", GRN, WHT, BOLD, - RESET, BLU, date_time.to_string (), RESET, message); - } - break; - case TRACE: - if (Application.verbose) { - print ("%s▎%s%sTRACE %s[%s%s%s]: %s\n", CYN, WHT, BOLD, RESET, BLU, date_time.to_string (), - RESET, message); - } - break; - case WARNING: - if (Application.verbose) { - print ("%s▎%s%sWARNING %s[%s%s%s]: %s%s%s\n", YEL, WHT, BOLD, RESET, BLU, date_time.to_string (), - RESET, YEL, message, RESET); - } - break; - case ERROR: - if (Application.verbose) { - print ("%s▎%s%sERROR %s[%s%s%s]: %s%s%s\n", RED, WHT, BOLD, RESET, BLU, date_time.to_string (), - RESET, RED, message, RESET); - } - GLib.log (Constants.APP_NAME, LogLevelFlags.LEVEL_ERROR, message); - break; - } - } - } -} diff --git a/src/Utils/DisplayTheme.vala b/src/Utils/DisplayTheme.vala deleted file mode 100644 index 00b6a5db..00000000 --- a/src/Utils/DisplayTheme.vala +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - // public class Utils { - // static string display_theme_path = ""; - // static Gtk.CssProvider display_theme_provider; - // public static string set_display_theme (string name) { - // display_theme_path = Application.user_config_dir + "/display_themes/"; - // // Update the stylesheets first - // if (DirUtils.create_with_parents (Application.user_config_dir, 2000) != -1) { - // if (DirUtils.create_with_parents (display_theme_path, 2000) != -1) { - // create_file ("DisplayUnit", "Default", "css"); - // create_file ("DisplayUnitElementaryLight", "elementary Light", "css"); - // create_file ("DisplayUnitElementaryDark", "elementary Dark", "css"); - // create_file ("DisplayUnitAurora", "Aurora", "css"); - // } - // } - // // Attempt to set the given theme - // if (display_theme_provider == null) { - // display_theme_provider = new Gtk.CssProvider (); - // } else { - // Gtk.StyleContext.remove_provider_for_display (Gdk.Display.get_default (), display_theme_provider); - // } - // try { - // display_theme_provider.load_from_path (display_theme_path + name + ".css"); - // Gtk.StyleContext.add_provider_for_display ( - // Gdk.Display.get_default (), display_theme_provider, - // Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - // ); - // } catch (Error e) { - // warning (e.message); - // try { - // display_theme_provider.load_from_path (display_theme_path + "Default.css"); - // Gtk.StyleContext.add_provider_for_display ( - // Gdk.Display.get_default (), display_theme_provider, - // Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - // ); - // return "Default"; - // } catch (Error e1) { - // warning (e1.message); - // try { - // display_theme_provider.load_from_path (display_theme_path + "Elementary Light.css"); - // Gtk.StyleContext.add_provider_for_display ( - // Gdk.Display.get_default (), display_theme_provider, - // Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - // ); - // return "Elementary Light"; - // } catch (Error e2) { - // warning (e2.message); - // try { - // display_theme_provider.load_from_path (display_theme_path + "Elementary Dark.css"); - // Gtk.StyleContext.add_provider_for_display ( - // Gdk.Display.get_default (), display_theme_provider, - // Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - // ); - // return "Elementary Dark"; - // } catch (Error e3) { - // warning (e3.message); - // try { - // display_theme_provider.load_from_path (display_theme_path + "Aurora.css"); - // Gtk.StyleContext.add_provider_for_display ( - // Gdk.Display.get_default (), display_theme_provider, - // Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - // ); - // return "Aurora"; - // } catch (Error e4) { - // warning ("Failed to load any of the default Display Themes: %s", e4.message); - // } - // } - // } - // } - // } - // return name; - // } - // } -} diff --git a/src/Utils/ErrorDomains.vala b/src/Utils/ErrorDomains.vala deleted file mode 100644 index 8165a597..00000000 --- a/src/Utils/ErrorDomains.vala +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - protected errordomain FluidError { - INVALID_SF - } - - protected errordomain StyleError { - INVALID_FILE, - INVALID_LAYOUT, - } - - protected errordomain PluginError { - UNSUPPORTED_FEATURE, - INVALID_CATEGORY - } -} diff --git a/src/Utils/MIDI.vala b/src/Utils/MIDI.vala deleted file mode 100644 index 57800f4b..00000000 --- a/src/Utils/MIDI.vala +++ /dev/null @@ -1,85 +0,0 @@ -namespace Ensembles.MIDI { - public enum EventType { - /** This event is sent when a note is released (ended). */ - NOTE_OFF = 0x80, - /** This event is sent when a note is depressed (started). */ - NOTE_ON = 0x90, - /** - * Polyphonic Key Pressure (Aftertouch). - * This event is most often sent by pressing down on the key after it - * "bottoms out". - */ - KEY_PRESSURE = 0xA0, - /** This event is sent when a controller value changes. - * Controllers include devices such as pedals and levers. - * Certain controller numbers are reserved for specific purposes. - */ - CONTROL_CHANGE = 0xB0, - /** This event is sent when the patch number changes. */ - PROGRAM_CHANGE = 0xC0, - /** - * Channel Pressure (After-touch). - * This event is most often sent by pressing down on the key after it - * "bottoms out". This event is different from polyphonic after-touch. - * Use this event to send the single greatest pressure value (of all - * the current depressed keys). - */ - CHANNEL_PRESSURE = 0xD0, - /** - * This event is sent to indicate a change in the pitch wheel. - */ - PITCH_BEND = 0xE0, - /** System Exclusive. */ - SYSEX = 0xF0, - /** - * Song Position Pointer. - * This is an internal 14 bit register that holds the number of MIDI - * beats (1 beat= six MIDI clocks) since the start of the song. - */ - SONG_POSITION = 0xF2, - /** - * Song Select. - * The Song Select specifies which sequence or song is to be played. - */ - SONG_SELECT = 0xF3, - /** End of Exclusive (SysEx). - * Used to terminate a System Exclusive. - */ - EOE = 0xF7, - /** - * Timing Clock. - * Sent 24 times per quarter note when synchronisation is required. - */ - CLOCK_TIMER = 0xF8, - /** - * Play the current sequence. - */ - PLAY = 0xFA, - /** Continue at the point the sequence was paused. */ - RESUME = 0xFB, - /** Pause the current sequence. */ - PAUSE = 0xFC, - /** Active Sensing. */ - ACTIVE_SENSING = 0xFE, - /** - * Reset all receivers in the system to power-up status. - * This should be used sparingly, preferably under manual control. - * In particular, it should not be sent on power-up. - */ - RESET = 0xFF - } - - public enum Control { - MODULATION = 0x01, - EXPLICIT_PITCH = 0x03, - GAIN = 0x07, - PAN = 0x0A, - EXPRESSION = 0x0B, - PITCH = 0x42, - RESONANCE = 0x47, - CUT_OFF = 0x4A, - EXPLICIT_BANK_SELECT = 0x55, - REVERB = 0x5B, - CHORUS = 0x5D - } -} diff --git a/src/Utils/Math.vala b/src/Utils/Math.vala deleted file mode 100644 index d21905e9..00000000 --- a/src/Utils/Math.vala +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles.Utils { - public class Math { - /** - * Returns a value mapped from one range into another. - * - * @param value the value in input range - * @param in_range_min input range min - * @param in_range_max input range max - * @param out_range_min output range min - * @param out_range_max output range max - * @return mapped value in output range - */ - public static double map_range_unclamped (double value, - double in_range_min, double in_range_max, - double out_range_min, double out_range_max) { - return out_range_min + ( - (out_range_max - out_range_min) / (in_range_max - in_range_min) - ) * (value - in_range_min); - } - - /** - * Returns a value mapped from one range into another. - * - * @param value the value in input range - * @param in_range_min input range min - * @param in_range_max input range max - * @param out_range_min output range min - * @param out_range_max output range max - * @return mapped value in output range - */ - public static float map_range_unclampedf (float value, - float in_range_min, float in_range_max, - float out_range_min, float out_range_max) { - return out_range_min + ( - (out_range_max - out_range_min) / (in_range_max - in_range_min) - ) * (value - in_range_min); - } - - public static double convert_db_to_gain (double db) { - return GLib.Math.pow (10, db / 20); - } - - public static double convert_gain_to_db (double gain) { - return 20 * GLib.Math.log10 (gain); - } - } -} diff --git a/src/Utils/StyleMIDIModifiers.vala b/src/Utils/StyleMIDIModifiers.vala deleted file mode 100644 index 346907e5..00000000 --- a/src/Utils/StyleMIDIModifiers.vala +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -using Ensembles.Models; - -namespace Ensembles { - public class StyleMIDIModifers { - public static int modify_key_by_chord (int key, Chord? chord, - ChordType style_scale_type, bool alt_channels_active) { - if (style_scale_type == ChordType.MAJOR) { - switch (chord.type) { - case ChordType.MAJOR: - return key + chord.root; - case ChordType.MINOR: - if ( - !alt_channels_active && ((key - 4) % 12 == 0 || (key - 9) % 12 == 0 || (key - 11) % 12 == 0) - ) { - return (key + chord.root - 1); - } else { - return (key + chord.root); - } - case ChordType.DIMINISHED: - if ((key - 4) % 12 == 0 || (key - 7) % 12 == 0) { - return (key + chord.root - 1); - } else { - return (key + chord.root); - } - case ChordType.SUSPENDED_2: - if ((key - 4) % 12 == 0) { - return (key + chord.root - 2); - } else { - return (key + chord.root); - } - case ChordType.SUSPENDED_4: - if ((key - 4) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.AUGMENTED: - if ((key - 2) % 12 == 0 || (key - 7) % 12 == 0) { - return (key + chord.root + 1); - } else if ((key - 5) % 12 == 0 || (key - 9) % 12 == 0) { - return (key + chord.root - 1); - } else { - return (key + chord.root); - } - case ChordType.SIXTH: - if ((key - 4) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root); - } - - return (key + chord.root + 5); - } else { - return (key + chord.root); - } - case ChordType.SEVENTH: - if ((key - 4) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root); - } - - return (key + chord.root + 6); - } else { - return (key + chord.root); - } - case ChordType.MAJOR_7TH: - if ((key - 4) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root); - } - - return (key + chord.root - 5); - } else { - return (key + chord.root); - } - case ChordType.MINOR_7TH: - if ((key - 4) % 12 == 0) { - if (Random.boolean ()) { - return (key + chord.root + 6); - } - - return (key + chord.root - 1); - } else { - return (key + chord.root); - } - case ChordType.ADD_9TH: - if ((key - 4) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root); - } - - return (key + chord.root - 2); - } else { - return (key + chord.root); - } - case ChordType.NINTH: - if ((key - 4) % 12 == 0) { - if (Random.boolean ()) { - return (key + chord.root - 2); - } - - return (key + chord.root); - } else if ((key - 7) % 12 == 0) { - if (Random.boolean ()) { - return (key + chord.root + 3); - } - return (key + chord.root); - } else { - return (key + chord.root); - } - } - } else if (style_scale_type == ChordType.MINOR) { - switch (chord.type) { - case ChordType.MINOR: - return (key + chord.root); - case ChordType.MAJOR: - if ( - !alt_channels_active && ((key - 3) % 12 == 0 || (key - 8) % 12 == 0 || (key - 10) % 12 == 0) - ) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.DIMINISHED: - if ((key - 7) % 12 == 0) { - return (key + chord.root - 1); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.SUSPENDED_2: - if ((key - 3) % 12 == 0) { - return (key + chord.root - 1); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.SUSPENDED_4: - if ((key - 3) % 12 == 0) { - return (key + chord.root + 2); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.AUGMENTED: - if ((key - 7) % 12 == 0) { - return (key + chord.root - 1); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.SIXTH: - if ((key - 3) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root + 1); - } - - return (key + chord.root + 6); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.SEVENTH: - if ((key - 3) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root + 1); - } - - return (key + chord.root + 7); - } else if ((key - 8) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.MAJOR_7TH: - if ((key - 3) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root + 1); - } - - return (key + chord.root + 8); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.MINOR_7TH: - if ((key - 3) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root); - } - - return (key + chord.root + 7); - } else if ((key - 8) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.ADD_9TH: - if ((key - 3) % 12 == 0) { - if (Random.int_range (0, 3) > 2) { - return (key + chord.root + 1); - } - - return (key + chord.root - 2); - } else if ((key - 8) % 12 == 0 || (key - 10) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - case ChordType.NINTH: - if ((key - 3) % 12 == 0) { - if (Random.boolean ()) { - return (key + chord.root - 1); - } - return (key + chord.root + 1); - } else if ((key - 7) % 12 == 0) { - if (Random.boolean ()) { - return (key + chord.root + 3); - } - - return (key + chord.root); - } else if ((key - 8) % 12 == 0) { - return (key + chord.root + 1); - } else { - return (key + chord.root); - } - } - } - return 0; - } - } - } diff --git a/src/meson.build b/src/meson.build index 463f5e23..6ee8d3ef 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,104 +16,5 @@ config_header = configure_file ( sources = files ( 'Main.vala', 'Application.vala', - - # Shell - 'Shell/MainWindow.vala', - - 'Shell/Layouts/DesktopLayout.vala', - 'Shell/Layouts/MobileLayout.vala', - 'Shell/Layouts/KioskLayout.vala', - 'Shell/Layouts/InfoDisplay.vala', - 'Shell/Layouts/KeyboardPanel.vala', - 'Shell/Layouts/MixerBoard.vala', - 'Shell/Layouts/AssignablesBoard.vala', - 'Shell/Layouts/RegistryPanel.vala', - 'Shell/Layouts/SamplerPadsPanel.vala', - 'Shell/Layouts/StyleControlPanel.vala', - 'Shell/Layouts/SynthControlPanel.vala', - 'Shell/Layouts/VoiceNavPanel.vala', - 'Shell/Layouts/PluginView.vala', - - 'Shell/Layouts/Display/HomeScreen.vala', - 'Shell/Layouts/Display/StyleScreen.vala', - 'Shell/Layouts/Display/VoiceScreen.vala', - 'Shell/Layouts/Display/DSPScreen.vala', - 'Shell/Layouts/Display/AudioPluginPicker.vala', - 'Shell/Layouts/Display/PluginScreen.vala', - - 'Shell/Widgets/BeatVisualization.vala', - 'Shell/Widgets/Knob.vala', - 'Shell/Widgets/Key.vala', - 'Shell/Widgets/Octave.vala', - 'Shell/Widgets/Keyboard.vala', - - 'Shell/Widgets/Display/WheelScrollableWidget.vala', - 'Shell/Widgets/Display/DisplayWindow.vala', - 'Shell/Widgets/Display/VoiceMenuItem.vala', - 'Shell/Widgets/Display/StyleMenuItem.vala', - 'Shell/Widgets/Display/DSPMenuItem.vala', - 'Shell/Widgets/Display/DSPInstanceMenuItem.vala', - - 'Shell/Plugins/AudioPlugins/Widgets/AudioPluginControl.vala', - - 'Shell/Dialogs/PowerDialog.vala', - - # Core - 'Core/ArrangerWorkstation.vala', - - 'Core/AudioEngine/Synthesizer.vala', - 'Core/AudioEngine/SynthProvider.vala', - 'Core/AudioEngine/SynthSettingsPresets.vala', - - 'Core/Analysers/ChordAnalyser.vala', - 'Core/Analysers/StyleAnalyser.vala', - 'Core/Analysers/VoiceAnalyser.vala', - - 'Core/MIDIPlayers/StyleEngine.vala', - - 'Core/FileLoaders/StyleFileLoader.vala', - - 'Core/Racks/Rack.vala', - 'Core/Racks/DSPRack.vala', - 'Core/Racks/VoiceRack.vala', - - # Services - 'Services/EventBus.vala', - 'Services/Settings.vala', - 'Services/Theme.vala', - - # Utilities - 'Utils/Console.vala', - 'Utils/ErrorDomains.vala', - 'Utils/AccentColors.vala', - 'Utils/StyleMIDIModifiers.vala', - 'Utils/MIDI.vala', - 'Utils/DisplayTheme.vala', - 'Utils/Math.vala', - - # Models - 'Models/Chord.vala', - 'Models/Registry.vala', - 'Models/Voice.vala', - 'Models/Style.vala', - 'Models/StylePart.vala', - - # Plugins - 'Core/Plugins/Plugin.vala', - 'Core/Plugins/PluginManager.vala', - - # Audio Plugins - 'Core/Plugins/AudioPlugins/AudioPlugin.vala', - 'Core/Plugins/AudioPlugins/Port.vala', - - # LV2 Plugins - 'Core/Plugins/AudioPlugins/Lv2/LV2Manager.vala', - 'Core/Plugins/AudioPlugins/Lv2/LV2Plugin.vala', - 'Core/Plugins/AudioPlugins/Lv2/LV2SyMap.vala', - 'Core/Plugins/AudioPlugins/Lv2/LV2EvBuf.vala', - 'Core/Plugins/AudioPlugins/Lv2/LV2Worker.vala', - 'Core/Plugins/AudioPlugins/Lv2/LV2PortAnalyser.vala', - 'Core/Plugins/AudioPlugins/Lv2/Ports/LV2Port.vala', - 'Core/Plugins/AudioPlugins/Lv2/Ports/LV2ControlPort.vala', - 'Core/Plugins/AudioPlugins/Lv2/Ports/LV2AtomPort.vala' + 'Settings.vala' ) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core new file mode 160000 index 00000000..6e059940 --- /dev/null +++ b/subprojects/ens-aw-core @@ -0,0 +1 @@ +Subproject commit 6e059940e61d1f0982d178bc77cbb2cd54cd35b6 diff --git a/subprojects/ens-aw-core.wrap b/subprojects/ens-aw-core.wrap new file mode 100644 index 00000000..3701fa64 --- /dev/null +++ b/subprojects/ens-aw-core.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://github.com/ensemblesaw/arranger-workstation-core +revision = make-working-library + diff --git a/subprojects/zix.wrap b/subprojects/zix.wrap deleted file mode 100644 index 4ba71df3..00000000 --- a/subprojects/zix.wrap +++ /dev/null @@ -1,4 +0,0 @@ -[wrap-git] -url = https://github.com/drobilla/zix -depth = 1 -revision = main From ecf9dc713e501daa46b8fce6d4351e3458e2cc3f Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Fri, 16 Jun 2023 23:46:45 +0530 Subject: [PATCH 02/37] change wrap location --- subprojects/ens-aw-core.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/ens-aw-core.wrap b/subprojects/ens-aw-core.wrap index 3701fa64..38403b1d 100644 --- a/subprojects/ens-aw-core.wrap +++ b/subprojects/ens-aw-core.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://github.com/ensemblesaw/arranger-workstation-core -revision = make-working-library +revision = main From ac9c7aaa7e5f5e16ec14435c8d6b1d240bfbe0b9 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Fri, 16 Jun 2023 23:48:22 +0530 Subject: [PATCH 03/37] lint --- src/Application.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application.vala b/src/Application.vala index 56c0f1fd..f19a79ef 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -93,7 +93,7 @@ namespace Ensembles { } if (verbose || raw_midi_input || kiosk_mode) { - Console.get_console_header (Constants.VERSION, Constants.DISPLAYVER); + Console.print_greetings (Constants.VERSION, Constants.DISPLAYVER); } if (raw_midi_input) { From 5a9143278065324282742f88af4aed00e08acfcc Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Fri, 16 Jun 2023 23:52:46 +0530 Subject: [PATCH 04/37] Remove subproject directory --- subprojects/ens-aw-core | 1 - 1 file changed, 1 deletion(-) delete mode 160000 subprojects/ens-aw-core diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core deleted file mode 160000 index 6e059940..00000000 --- a/subprojects/ens-aw-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6e059940e61d1f0982d178bc77cbb2cd54cd35b6 From e575a77f18ead34833d63478d80beeba97566f3f Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 00:01:47 +0530 Subject: [PATCH 05/37] Add subproject folders to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 00a18a74..ea487f8c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ null.d *~ .~lock* xtleak.kcg.* +subprojects/ens-aw-core/ From 22c94c9f1c52e9e44a1b7a739d8b283c0db4693c Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 12:12:16 +0530 Subject: [PATCH 06/37] Add Tui shell module --- .gitignore | 1 + subprojects/ens-tui-shell.wrap | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 subprojects/ens-tui-shell.wrap diff --git a/.gitignore b/.gitignore index ea487f8c..85c4b29a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ null.d .~lock* xtleak.kcg.* subprojects/ens-aw-core/ +subprojects/ens-tui-shell/ diff --git a/subprojects/ens-tui-shell.wrap b/subprojects/ens-tui-shell.wrap new file mode 100644 index 00000000..f00ab078 --- /dev/null +++ b/subprojects/ens-tui-shell.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/ensemblesaw/tui-shell +revision = main From 6b1415ed5af6a8ce2a43443965786909b21552bf Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 13:09:02 +0530 Subject: [PATCH 07/37] Use initialize function to initialize aw core --- meson.build | 3 ++- src/Application.vala | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index aeb82f2b..5ec14cce 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,8 @@ dependencies = [ dependency ('x11'), dependency ('gtk4'), dependency ('glib-2.0'), - dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']) + dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']), + dependency ('ens-tui-shell-0', fallback: ['ens-tui-shell', 'ens_tui_shell_dep']) ] # Set up the profile diff --git a/src/Application.vala b/src/Application.vala index f19a79ef..d9b65736 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -60,7 +60,8 @@ namespace Ensembles { Console.log ("Initializing Arranger Workstation"); aw_core = AWCore.instance .load_soundfont_from_path (Constants.SF2DATADIR) - .load_style_from_path (Constants.PKGDATADIR); + .load_style_from_path (Constants.PKGDATADIR) + .initialize (); if (Settings.instance.version != Constants.VERSION) { Settings.instance.version = Constants.VERSION; @@ -93,15 +94,15 @@ namespace Ensembles { } if (verbose || raw_midi_input || kiosk_mode) { - Console.print_greetings (Constants.VERSION, Constants.DISPLAYVER); + Console.greet (Constants.VERSION, Constants.DISPLAYVER); } if (raw_midi_input) { - print ("Raw MIDI Input Enabled! You can now enable midi input and connect your DAW\n"); + Console.log ("Raw MIDI Input Enabled! You can now enable midi input and connect your DAW\n"); } if (kiosk_mode) { - print ("Starting Ensembles in Kiosk Mode\n"); + Console.log ("Starting Ensembles in Kiosk Mode\n"); } if (arg_file != null && arg_file[0] != null) { From 2b7a591d8b4bb33d97f01995609965f8cc2c51b0 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 21:13:30 +0530 Subject: [PATCH 08/37] Use new aw builder --- src/Application.vala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index d9b65736..62b581e3 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -59,9 +59,14 @@ namespace Ensembles { Console.log ("Initializing Arranger Workstation"); aw_core = AWCore.instance + .use_driver ("alsa") .load_soundfont_from_path (Constants.SF2DATADIR) - .load_style_from_path (Constants.PKGDATADIR) - .initialize (); + .load_style_from_path (Constants.PKGDATADIR + "/StyleFiles") + .load_style_from_path (Environment.get_user_special_dir ( + GLib.UserDirectory.DOCUMENTS) + + "/ensembles" + + "/styles") + .build_synth_engine (); if (Settings.instance.version != Constants.VERSION) { Settings.instance.version = Constants.VERSION; From bb868ccb8ec11e623b5b490ff4b156df726bb198 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 21:53:51 +0530 Subject: [PATCH 09/37] LINT --- src/Application.vala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 62b581e3..812796aa 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -60,13 +60,14 @@ namespace Ensembles { Console.log ("Initializing Arranger Workstation"); aw_core = AWCore.instance .use_driver ("alsa") - .load_soundfont_from_path (Constants.SF2DATADIR) - .load_style_from_path (Constants.PKGDATADIR + "/StyleFiles") - .load_style_from_path (Environment.get_user_special_dir ( + .add_soundfont (Constants.SF2DATADIR) + .add_style_search_path (Constants.PKGDATADIR + "/StyleFiles") + .add_style_search_path (Environment.get_user_special_dir ( GLib.UserDirectory.DOCUMENTS) + "/ensembles" + "/styles") .build_synth_engine (); + aw_core.load_data_async (); if (Settings.instance.version != Constants.VERSION) { Settings.instance.version = Constants.VERSION; From 6a3842b6b4ba21a2018cbc767db08d5bb3b2bfe1 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 17 Jun 2023 22:08:20 +0530 Subject: [PATCH 10/37] Use VAPIs from subproject --- meson.build | 1 + vapi/fluidsynth.vapi | 896 -------------------------------------- vapi/libpipewire-0.3.vapi | 27 -- vapi/lilv-0.vapi | 274 ------------ vapi/lv2.vapi | 536 ----------------------- vapi/suil-0.vapi | 91 ---- vapi/zix-0.vapi | 138 ------ 7 files changed, 1 insertion(+), 1962 deletions(-) delete mode 100644 vapi/fluidsynth.vapi delete mode 100644 vapi/libpipewire-0.3.vapi delete mode 100644 vapi/lilv-0.vapi delete mode 100644 vapi/lv2.vapi delete mode 100644 vapi/suil-0.vapi delete mode 100644 vapi/zix-0.vapi diff --git a/meson.build b/meson.build index 5ec14cce..3d5dec5d 100644 --- a/meson.build +++ b/meson.build @@ -29,6 +29,7 @@ add_project_arguments ( add_project_arguments ( ['--vapidir', join_paths (meson.current_source_dir (), 'vapi')], + ['--vapidir', join_paths (meson.current_source_dir (), 'subprojects', 'ens-aw-core', 'vapi')], language: 'vala' ) diff --git a/vapi/fluidsynth.vapi b/vapi/fluidsynth.vapi deleted file mode 100644 index 15b49121..00000000 --- a/vapi/fluidsynth.vapi +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - * FluidSynth - A Software Synthesizer - * - * Copyright (C) 2003 Peter Hanappe and others. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - * --- - */ - - - /** - * FluidSynth - */ -[CCode(cheader_filename="fluidsynth.h", cprefix="FLUID_", lower_case_cprefix="fluid_")] -namespace Fluid { - /** - * Value that indicates success, used by most libfluidsynth functions. - * - * @since 1.1.0 - */ - const int OK; - /** - * Value that indicates failure, used by most libfluidsynth functions. - * - * @since 1.1.0 - */ - const int FAILED; - /** - * String constant of libfluidsynth version. - */ - const string VERSION; - /** - * libfluidsynth major version integer constant. - */ - const int VERSION_MAJOR; - /** - * Value that indicates failure, used by most libfluidsynth functions. - */ - const int VERSION_MICRO; - /** - * libfluidsynth micro version integer constant. - */ - const int VERSION_MINOR; - /** - * libfluidsynth minor version integer constant. - */ - - /** - * Wrapper for `free()` that satisfies at least C90 requirements. - * - * **Warning**: - * Calling {@link Fluid.free} on memory that is advised to be freed with - * `fluid_free()` results in undefined behaviour! (cf.: "Potential Errors - * Passing CRT Objects Across DLL Boundaries" found in MS Docs) - * - * @since 2.0.7 - * @param ptr Pointer to memory region that should be freed - */ - void free (void* ptr); - /** - * Check if a file is a MIDI file. - * - * The current implementation only checks for the "MThd" header in the - * file. It is useful only to distinguish between SoundFont and MIDI files. - * - * @param filename Path to the file to check - * @return TRUE if it could be a MIDI file, FALSE otherwise - */ - bool is_midifile (string filename); - /** - * Check if a file is a SoundFont file. - * - * If fluidsynth was built with DLS support, this function will also - * identify DLS files. - * - * **Note:** This function only checks whether header(s) in the RIFF chunk - * are present. A call to {@link Fluid.Synth.sfload} might still fail. - * - * @param filename Path to the file to check - * @return TRUE if it could be a SF2, SF3 or DLS file, FALSE otherwise - */ - bool is_soundfont (string filename); - /** - * Get FluidSynth runtime version. - * - * @param major Location to store major number - * @param minor Location to store minor number - * @param micro Location to store micro number - */ - void version (out int major, out int minor, out int micro); - /** - * Get FluidSynth runtime version as a string. - * - * @return FluidSynth version string, which is internal and - * should not be modified or freed. - */ - string version_str (); - - [CCode (cprefix = "HINT_")] - namespace Hint { - /** - * Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field of - * the FLUID_PortRangeHint should be considered meaningful. - * - * The value in this field should be considered the (inclusive) upper - * bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also - * specified then the value of UpperBound should be multiplied by - * the sample rate. - */ - public const int BOUNDED_ABOVE; - /** - * Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field of - * the FLUID_PortRangeHint should be considered meaningful. - * - * The value in this field should be considered the (inclusive) lower - * bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also specified - * then the value of LowerBound should be multiplied by the sample rate. - */ - public const int BOUNDED_BELOW; - /** - * Setting is a list of string options. - */ - public const int OPTIONLIST; - /** - * Hint FLUID_HINT_TOGGLED indicates that the data item should be - * considered a Boolean toggle. - * - * Data less than or equal to zero should be considered ‘off’ or - * ‘false,’ and data above zero should be considered ‘on’ or ‘true.’ - * FLUID_HINT_TOGGLED may not be used in conjunction with any other hint. - */ - public const int TOGGLED; - } - - /** - * Settings type. - * - * Each setting has a defined type: numeric (double), integer, string or a - * set of values. The type of each setting can be retrieved using the - * function {@link Fluid.Settings.get_type} - */ - [CCode (cname = "enum fluid_types_enum", has_type_id = false, cprefix = "FLUID_")] - public enum Types { - /** Undefined type */ - NO_TYPE, - /** Numeric (double) */ - NUM_TYPE, - /** Integer */ - INT_TYPE, - /** String */ - STR_TYPE, - /** Set of values */ - SET_TYPE - } - - /** Chorus modulation waveform type. */ - [CCode (cname = "enum fluid_chorus_mod", has_type_id = false, cprefix = "FLUID_CHORUS_")] - public enum ChorusMod { - /** Sine wave chorus modulation. */ - SINE, - /** Triangle wave chorus modulation. */ - TRIANGLE - } - - /** - *Specifies optional settings to use for the custom IIR filter. - * - * Can be bitwise ORed. - */ - [Flags] - [CCode (cname = "enum fluid_iir_filter_flags", has_type_id = false, cprefix = "FLUID_IIR_")] - public enum IIRFilterFlags { - /** - *The Soundfont spec requires the filter Q to be interpreted in dB. - * - * If this flag is set the filter Q is instead assumed to be in - * a linear range */ - Q_LINEAR, - /** If this flag the filter is switched off if - * Q == 0 (prior to any transformation) */ - Q_ZERO_OFF, - /** - * The Soundfont spec requires to correct the gain of the - * filter depending on the filter's Q. - * - * If this flag is set the filter gain will not be corrected. - */ - NO_GAIN_AMP - } - - /** - * Specifies the type of filter to use for the custom IIR filter. - */ - [CCode (cname = "enum fluid_iir_filter_type", has_type_id = false, cprefix = "FLUID_IIR_")] - public enum IIRFilterTypes { - /** Custom IIR filter is not operating. */ - DISABLED, - /** Custom IIR filter is operating as low-pass filter. */ - LOWPASS, - /** Custom IIR filter is operating as high-pass filter. */ - HIGHPASS, - LAST - } - - [CCode (cname = "enum fluid_gen_type", has_type_id = false, cprefix = "GEN_")] - public enum GenType { - STARTADDROFS, - ENDADDROFS, - STARTLOOPADDROFS, - ENDLOOPADDROFS, - STARTADDRCOARSEOFS, - MODLFOTOPITCH, - VIBLFOTOPITCH, - MODENVTOPITCH, - FILTERFC, - FILTERQ, - MODLFOTOFILTERFC, - MODENVTOFILTERFC, - ENDADDRCOARSEOFS, - MODLFOTOVOL, - UNUSED1, - CHORUSSEND, - REVERBSEND, - PAN, - UNUSED2, - UNUSED3, - UNUSED4, - MODLFODELAY, - MODLFOFREQ, - VIBLFODELAY, - VIBLFOFREQ, - MODENVDELAY, - MODENVATTACK, - MODENVHOLD, - MODENVDECAY, - MODENVSUSTAIN, - MODENVRELEASE, - KEYTOMODENVHOLD, - KEYTOMODENVDECAY, - VOLENVDELAY, - VOLENVATTACK, - VOLENVHOLD, - VOLENVDECAY, - VOLENVSUSTAIN, - VOLENVRELEASE, - KEYTOVOLENVHOLD, - KEYTOVOLENVDECAY, - INSTRUMENT, - RESERVED1, - KEYRANGE, - VELRANGE, - STARTLOOPADDRCOARSEOFS, - KEYNUM, - VELOCITY, - ATTENUATION, - RESERVED2, - ENDLOOPADDRCOARSEOFS, - COARSETUNE, - FINETUNE, - SAMPLEID, - SAMPLEMODE, - RESERVED3, - SCALETUNE, - EXCLUSIVECLASS, - OVERRIDEROOTKEY, - PITCH, - CUSTOM_BALANCE, - CUSTOM_FILTERFC, - CUSTOM_FILTERQ, - LAST - } - - [CCode (cname = "enum fluid_midi_channel_type", has_type_id = false, cprefix = "CHANNEL_TYPE_")] - public enum MIDIChannelType { - MELODIC, - DRUM - } - - [CCode (cname = "enum fluid_channel_mode_flags", has_type_id = false, cprefix = "FLUID_CHANNEL_")] - public enum ChannelModeFlags { - POLY_OFF, - OMNI_OFF - } - - [CCode (cname = "enum fluid_basic_channel_modes", has_type_id = false, cprefix = "FLUID_CHANNEL_MODE_")] - public enum BasicChannelModes { - MASK, - OMNION_POLY, - OMNION_MONO, - OMNIOFF_POLY, - OMNIOFF_MONO, - LAST - } - - [CCode (cname = "enum fluid_channel_legato_mode", has_type_id = false, cprefix = "FLUID_CHANNEL_LEGATO_MODE_")] - public enum ChannelLegatoMode { - RETRIGGER, - MULTI_RETRIGGER, - LAST - } - - [CCode (cname = "enum fluid_channel_portamento_mode", has_type_id = false, cprefix = "FLUID_CHANNEL_PORTAMENTO_MODE_")] - public enum ChannelPortamentoMode { - EACH_NOTE, - LEGATO_ONLY, - STACCATO_ONLY, - LAST - } - - [CCode (cname = "enum fluid_channel_breath_flags", has_type_id = false, cprefix = "FLUID_CHANNEL_BREATH_")] - public enum ChannelBreathFlags { - POLY, - MONO, - SYNC - } - - [CCode (cname = "enum fluid_player_set_tempo_type", has_type_id = false, cprefix = "FLUID_PLAYER_TEMPO_")] - public enum TempoType { - INTERNAL, - EXTERNAL_BPM, - EXTERNAL_MIDI, - NBR - } - - [CCode (cname = "enum fluid_player_status", has_type_id = false, cprefix = "FLUID_PLAYER_")] - public enum PlayerStatus { - READY, - PLAYING, - STOPPING, - DONE - } - - [CCode (cname = "enum fluid_midi_router_rule_type ", has_type_id = false, cprefix = "FLUID_MIDI_ROUTER_RULE_")] - public enum MIDIRouterRuleType { - NOTE, - CC, - PROG_CHANGE, - PITCH_BEND, - CHANNEL_PRESSURE, - KEY_PRESSURE - } - - [SimpleType] - [CCode (cname = "fluid_audio_func_t", has_target = false)] - public delegate int handle_audio_func_t (void* data, int len, [CCode (array_length_pos = 2.1)] float*[] fx, [CCode (cname = "out", array_length_pos = 3.1)] float*[] aout); - - [SimpleType] - [CCode (cname = "handle_midi_event_func_t", has_target = false)] - public delegate int handle_midi_event_func_t (void* data, MIDIEvent? event); - - [SimpleType] - [CCode (cname = "handle_midi_tick_func_t", has_target = false)] - public delegate int handle_midi_tick_func_t (void* data, int tick); - - /** - * SoundFont synthesizer. - * - * You have to load a SoundFont in order to hear any sound. For that you use - * the {@link sfload} function. - * - * You can use the audio driver functions to open the audio device and - * create a background audio thread. - * - * The API for sending MIDI events is probably - * what you expect: {@link noteon}, {@link noteoff}, ... - */ - [Compact] - [CCode (cname = "fluid_synth_t", cprefix = "fluid_synth_", free_function = "delete_fluid_synth", has_type_id = false)] - public class Synth { - [CCode (cname = "new_fluid_synth")] - public Synth (Settings? settings); - - public Settings get_settings (); - /** - * Get a textual representation of the last error. - * - * @return Pointer to string of last error message. Valid until the - * same calling thread calls another FluidSynth function which fails. - * String is internal and should not be modified or freed. - * - * @deprecated - */ - public string error (); - /** Get the synth CPU load value. - * - * @return Estimated CPU load value in percent (0-100) */ - public double get_cpu_load (); - - // Audio Rendering - - /** - * Synthesize floating point audio to stereo audio channels - * (implements the default interface {@link handle_audio_func_t}). - * - * Synthesize and mix audio to a given number of planar audio buffers. - * Therefore pass `aout.length = N*2` float buffers - * to `out` in order to render the synthesized audio to `N` stereo channels. - * Each float buffer must be able to hold `len` elements. - * - * `aout` contains an array of planar buffers for normal, dry, stereo - * audio (alternating left and right). Like: - * {{{ - * aout[0] = left_buffer_audio_channel_0 - * aout[1] = right_buffer_audio_channel_0 - * aout[2] = left_buffer_audio_channel_1 - * aout[3] = right_buffer_audio_channel_1 - * ... - * aout[ (i * 2 + 0) % aout.length ] = left_buffer_audio_channel_i - * aout[ (i * 2 + 1) % aout.length ] = right_buffer_audio_channel_i - * }}} - * - * for zero-based channel index `i`. The buffer layout of `fx` used for - * storing effects like reverb and chorus looks similar: - * - * {{{ - * fx[0] = left_buffer_channel_of_reverb_unit_0 - * fx[1] = right_buffer_channel_of_reverb_unit_0 - * fx[2] = left_buffer_channel_of_chorus_unit_0 - * fx[3] = right_buffer_channel_of_chorus_unit_0 - * fx[4] = left_buffer_channel_of_reverb_unit_1 - * fx[5] = right_buffer_channel_of_reverb_unit_1 - * fx[6] = left_buffer_channel_of_chorus_unit_1 - * fx[7] = right_buffer_channel_of_chorus_unit_1 - * fx[8] = left_buffer_channel_of_reverb_unit_2 - * ... - * fx[ ((k * synth.count_effects_channels() + j) * 2 + 0) % fx.length ] = left_buffer_for_effect_channel_j_of_unit_k - * fx[ ((k * synth.count_effects_channels() + j) * 2 + 1) % fx.length ] = right_buffer_for_effect_channel_j_of_unit_k - * }}} - * - * where `0 <= k < synth.count_effects_groups()` is a zero-based index - * denoting the effects unit and `0 <= j < synth.count_effects_channels()` - * is a zero-based index denoting the effect channel within unit `k`. - * - * Any playing voice is assigned to audio channels based on the MIDI - * channel it's playing on: Let chan be the zero-based MIDI channel index - * an arbitrary voice is playing on. To determine the audio channel and - * effects unit it is going to be rendered to use: - * - * `i = chan % synth.count_audio_groups()` - * - * `k = chan % synth.count_effects_groups()` - * - * **Note:** The owner of the sample buffers must zero them out before - * calling this function, because any synthesized audio is mixed - * (i.e. added) to the buffers. E.g. if {@link Fluid.Synth.process} is called - * from a custom audio driver process function {@link Fluid.AudioDriver.with_audio_callback}), - * the audio driver takes care of zeroing the buffers. - * - * **Note:** No matter how many buffers you pass in, {@link Fluid.Synth.process} - * will always render all audio channels to the buffers in out and all - * effects channels to the buffers in `fx`, provided that `aout.length > 0` - * and `fx.length > 0` respectively. - * If `aout.length/2 < synth.count_audio_channels()` it will wrap around. - * Same is true for effects audio if - * `fx.length/2 < (synth.count_effects_channels() * synth.count_effects_groups()). - * See usage examples below. - * - * **Note:** Should only be called from synthesis thread. - * - * @see Fluid.AudioDriver.with_audio_callback - * @param len Count of audio frames to synthesize and store in every - * single buffer provided by out and fx. Zero value is permitted, - * the function does nothing and return {@link FLUID.OK}. - * @param fx Array of buffers to store effects audio to. Buffers may - * alias with buffers of `out`. Individual NULL buffers are permitted - * and will cause to skip mixing any audio into that buffer. - * @param aout Array of buffers to store (dry) audio to. Buffers may - * alias with buffers of `fx`. Individual NULL buffers are permitted and - * will cause to skip mixing any audio into that buffer - * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise, - * * `fx == NULL` while `fx.length > 0`, or `out == NULL` while `nout > 0`. - * * `nfx` or `aout.length` not multiple of 2. - * * `len < 0` - * * `fx.length` or `aout.length` exceed the range explained above. - */ - public int process (int len, [CCode (array_length_pos = 1.1)] float*[] fx, [CCode (cname = "out", array_length_pos = 2.1)] float*[] aout); - - // Effect - Chorus - public int chorus_on (int fx_group, bool on); - public int get_chorus_group_depth (int fx_group, out double depth_ms); - public int get_chorus_group_level (int fx_group, out double level); - public int get_chorus_group_nr (int fx_group, out int nr); - public int get_chorus_group_speed (int fx_group, out double speed); - public int get_chorus_group_type (int fx_group, out ChorusMod type); - public int set_chorus_group_depth (int fx_group, double depth_ms); - public int set_chorus_group_level (int fx_group, double level); - public int set_chorus_group_nr (int fx_group, int nr); - public int set_chorus_group_speed (int fx_group, double speed); - public int set_chorus_group_type (int fx_group, ChorusMod type); - - // Effect - Reverb - public int get_reverb_group_damp (int fx_group, out double damping); - public int get_reverb_group_level (int fx_group, out double level); - public int get_reverb_group_roomsize (int fx_group, out double roomsize); - public int get_reverb_group_width (int fx_group, out double width); - public int reverb_on (int fx_group, bool on); - public int set_reverb_group_damp (int fx_group, double damping); - public int set_reverb_group_level (int fx_group, double level); - public int set_reverb_group_roomsize (int fx_group, double roomsize); - public int set_reverb_group_width (int fx_group, double width); - - // Effect - IIR Filter - public int set_custom_filter (IIRFilterTypes type, IIRFilterFlags flags); - - // Effect - LADSPA - public LADSPAFx get_ladspa_fx (); - - // MIDI Channel Messages - public int all_notes_off (int chan); - public int all_sounds_off (int chan); - public int bank_select (int chan, int bank); - /** - * Send a MIDI controller event on a MIDI channel. - * - * @param chan MIDI channel number (0 to MIDI channel count - 1) - * @param num MIDI controller number (0-127) - * @param val MIDI controller value (0-127) - * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise - */ - public int cc (int chan, int num, int val); - public int channel_pressure (int chan, int val); - public int get_cc (int chan, int num, out int pval); - public float get_gen (int chan, GenType param); - public int get_pitch_bend (int chan, out int ppitch_bend); - public int get_pitch_wheel_sens (int chan, out int pval); - public int get_program (int chan, out int sfont_id, out int back_num, out int preset_num); - public int key_pressure (int chan, int key, int val); - public int noteoff (int chan, int key); - public int noteon (int chan, int key, int vel); - public int pitch_bend (int chan, int val); - public int pitch_wheel_sens (int chan, int val); - public int program_change (int chan, int program); - public int program_reset (); - /** - * Select an instrument on a MIDI channel by SoundFont ID, bank and program numbers. - * - * @param chan MIDI channel number (0 to MIDI channel count - 1) - * @param sfont_id ID of a loaded SoundFont - * @param bank_num MIDI bank number - * @param preset_num MIDI program number - * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise - */ - public int program_select (int chan, int sfont_id, int bank_num, int preset_num); - public int program_select_by_sfont_name (int chan, string sfont_name, int bank_num, int preset_num); - public int set_gen (int chan, GenType param, float value); - public int sfont_select (int chan, int sfont_id); - public int sysex (uint8[] data, int len, char* response, out int response_len, out bool handled, int dryrun); - public int system_reset (); - public int unset_program (int chan); - - // MIDI Channel Setup - public int get_breath_mode (int chan, out ChannelBreathFlags breathmode); - public int get_legato_mode (int chan, out ChannelLegatoMode legatomode); - public int get_portamento_mode (int chan, out ChannelPortamentoMode portamentomode); - public int set_channel_type (int chan, MIDIChannelType type); - public int reset_basic_channel (int chan); - public int set_basic_channel (int chan, BasicChannelModes mode, int val); - public int set_breath_mode (int chan, ChannelBreathFlags breathmode); - public int set_legato_mode (int chan, ChannelLegatoMode legatomode); - public int set_portamento_mode (int chan, ChannelPortamentoMode portamentomode); - - // MIDI Tuning - public int activate_tuning (int chan, int bank, int prog, bool apply); - public int deactivate_tuning (int chan, bool apply); - public bool tuning_iteration_next (out int bank, out int prog); - public void tuning_iteration_start (); - - // Soundfont Management - /** - * Load a SoundFont file (filename is interpreted by SoundFont loaders). - * - * The newly loaded SoundFont will be put on top of the SoundFont stack. - * Presets are searched starting from the SoundFont on the top of the - * stack, working the way down the stack until a preset is found. - * - * **Note:** Since FluidSynth 2.2.0 `filename` is treated as an UTF8 - * encoded string on Windows. FluidSynth will convert it to wide-char - * internally and then pass it to `_wfopen()`. Before `FluidSynth 2.2.0`, - * filename was treated as ANSI string on Windows. All other platforms - * directly pass it to `fopen()` without any conversion - * (usually, UTF8 is accepted). - * - * @param filename File to load - * @param reset_presets TRUE to re-assign presets for all MIDI channels - * (equivalent to calling {@link Fluid.Synth.program_reset}) - * @return SoundFont ID on success, {@link Fluid.FAILED} on error - */ - public int sfload (string filename, bool reset_presets); - public int add_sfont (SoundFont? sfont); - public unowned Preset get_channel_preset (int chan); - public int get_bank_offset (int sfont_id); - public unowned SoundFont? get_sfont (uint num); - public unowned SoundFont? get_sfont_by_id (int id); - public unowned SoundFont? get_sfont_by_name (string name); - public int remove_sfont (SoundFont? sfont); - public int set_bank_offset (int sfont_id, int offset); - public int sfcount (); - public int sfreload (int id); - public int sfunload (int id, bool reset_presets); - - public int handle_midi_event (MIDIEvent? event); - - // Synthesis Parameters - /** Get the internal synthesis buffer size value. */ - public int get_internal_bufsize (); - } - - /** - * Functions for settings management. - */ - [Compact] - [CCode (cname = "fluid_settings_t", cprefix = "fluid_settings_", free_function = "delete_fluid_settings", has_type_id = false)] - public class Settings { - [CCode (cname = "new_fluid_settings")] - public Settings (); - public int copystr (string name, out string str, int len); - public int dupstr (string name, out string str); - public void foreach (void* data, foreach_t func); - public void foreach_option (string name, void* data, foreach_option_t func); - public int get_hints (string name, out int hints); - public Types get_type (string name); - public int getint (string name, out int val); - public int getint_default (string name, out int val); - public int getint_range (string name, out int min, out int max); - public int getnum (string name, out double val); - public int getnum_default (string name, out double val); - public int getnum_range (string name, out double min, out double max); - public int getstr_default (string name, out string def); - public bool is_realtime (string name); - public string option_concat (string name, string separator); - public int option_count (string name); - public int setint (string name, int val); - public int setnum (string name, double val); - public int setstr (string name, string str); - public bool str_equal (string name, string s); - - [SimpleType] - [CCode (has_target = false)] - public delegate void foreach_option_t (void* data, string name, string option); - - [SimpleType] - [CCode (has_target = false)] - public delegate void foreach_t (void* data, string name, int type); - } - - [Compact] - [CCode (cname = "fluid_sfont_t", cprefix = "fluid_sfont_", free_function = "delete_fluid_sfont", has_type_id = false)] - public class SoundFont { - public unowned string get_name (); - public unowned Preset get_preset (int bank, int prenum); - public void iteration_start (); - public unowned Preset? iteration_next (); - } - - [Compact] - [CCode (cname = "fluid_preset_t", cprefix = "fluid_preset_", free_function = "delete_fluid_preset", has_type_id = false)] - public class Preset { - public int get_banknum (); - public unowned void* get_data (); - public unowned string get_name (); - public int get_num (); - public unowned SoundFont get_sfont (); - public int set_data (void* data); - } - - /** - * Functions for managing audio drivers. - */ - [Compact] - [CCode (cname = "fluid_audio_driver_t", cprefix = "fluid_audio_", free_function = "delete_fluid_audio_driver", has_type_id = false)] - public class AudioDriver { - /** - * Create a new audio driver. - * - * Creates a new audio driver for a given `synth` instance with a defined - * set of configuration `settings`. The `settings` instance must be the same - * that you have passed to {@link Fluid.AudioDriver.AudioDriver} when - * creating the `synth` instance. Otherwise the behaviour is undefined - * - * **Note:** As soon as an audio driver is created, the `synth` starts - * rendering audio. This means that all necessary initialization and - * sound-setup should have been completed before calling this function. - * Thus, of all object types in use (synth, midi player, sequencer, etc.) - * the audio driver should always be the last one to be created and the - * first one to be deleted! Also refer to the order of object creation - * in the code examples. - * - * @param settings Configuration settings used to select and create the audio driver. - * @param synth Synthesizer instance for which the audio driver is created for. - */ - [CCode (cname = "new_fluid_audio_driver")] - public AudioDriver (Settings? settings, Synth? synth); - /** - * Create a new audio driver. - * - * Like {@link Fluid.AudioDriver.AudioDriver} but allows for custom audio - * processing before audio is sent to audio driver. It is the - * responsibility of the callback func to render the audio into the - * buffers. If func uses a {@link Fluid.Synth} synth, the settings instance must - * be the same that you have passed to {@link Fluid.Synth.Synth} when - * creating the synth instance. Otherwise the behaviour is undefined. - * - * **Note:** Not as efficient as {@link Fluid.AudioDriver.AudioDriver}. - * As soon as an audio driver is created, a new thread is spawned starting - * to make callbacks to func. This means that all necessary sound-setup - * should be completed after this point, thus of all object types in use - * (synth, midi player, sequencer, etc.) the audio driver should always - * be the last one to be created and the first one to be deleted! - * Also refer to the order of object creation in the code examples. - * - * @param settings Configuration settings used to select and create the audio driver. - * @param func Function called to fill audio buffers for audio playback - * @param User defined data pointer to pass to `func` - */ - [CCode (cname = "new_fluid_audio_driver2")] - public AudioDriver.with_audio_callback (Settings? settings, handle_audio_func_t func, void* data); - } - - /** - * Parse standard MIDI files and emit MIDI events. - */ - [Compact] - [CCode (cname = "fluid_player_t", cprefix = "fluid_player_", free_function = "delete_fluid_player", has_type_id = false)] - public class Player { - [CCode (cname = "new_fluid_player")] - public Player (Synth? synth); - - public int bpm { - get { - return get_bpm (); - } - } - - public int midi_tempo { - get { - return get_midi_tempo (); - } - } - - public int current_tick { - get { - return get_current_tick (); - } - } - - public int total_ticks { - get { - return get_total_ticks (); - } - } - - public int loop { - set { - set_loop (value); - } - } - - public int add (string midifile); - public int add_mem (void* buffer, size_t len); - public int get_bpm (); - public int get_current_tick (); - public int get_midi_tempo (); - public PlayerStatus get_status (); - public int get_total_ticks (); - public int join (); - public int play (); - public int seek (int ticks); - public int set_loop (int loop); - public int set_playback_callback (handle_midi_event_func_t handler, void* handler_data); - public int set_tempo (TempoType tempo_type, double tempo); - public int set_tick_callback (handle_midi_tick_func_t handler, void* handler_data); - public int stop (); - } - - /** - * Functions to create, modify, query and delete MIDI events. - */ - [Compact] - [CCode (cname = "fluid_midi_event_t", cprefix = "fluid_midi_event_", free_function = "delete_fluid_midi_event", has_type_id = false)] - public class MIDIEvent { - [CCode (cname = "new_fluid_midi_event")] - public MIDIEvent (); - - public int get_channel (); - public int get_control (); - public int get_key (); - public int get_lyrics (void** data, out int size); - public int get_pitch (); - public int get_program (); - public int get_text (void** data, out int size); - public int get_type (); - public int get_value (); - public int get_velocity (); - - public int set_channel (int chan); - public int set_control (int v); - public int set_key (int v); - public int set_lyrics (void* data, int size, bool dynamic); - public int set_pitch (int val); - public int set_program (int val); - public int set_text (void* data, int size, bool dynamic); - public int set_sysex (void* data, int size, bool dynamic); - public int set_type (int type); - public int set_value (int v); - public int set_velocity (int v); - } - - /** - * Functions for managing MIDI drivers. - */ - [Compact] - [CCode (cname = "fluid_midi_driver_t", cprefix = "fluid_midi_driver_", free_function = "delete_fluid_midi_driver", has_type_id = false)] - public class MIDIDriver { - [CCode (cname = "new_fluid_midi_driver")] - public MIDIDriver (); - } - - /** - * Rule based transformation and filtering of MIDI events. - */ - [Compact] - [CCode (cname = "fluid_midi_router_t", cprefix = "fluid_midi_router_", free_function = "delete_fluid_midi_router", has_type_id = false)] - public class MIDIRouter { - [CCode (cname = "new_fluid_midi_router")] - public MIDIRouter (Settings settings, handle_midi_event_func_t handler, void* event_handler_data); - - [CCode (has_target = false)] - public int dump_postrouter (void* data, MIDIEvent event); - [CCode (has_target = false)] - public int dump_prerouter (void* data, MIDIEvent event); - public int add_rule (MIDIRouterRule rule, MIDIRouterRuleType type); - public int clear_rules (); - [CCode (has_target = false)] - public int handle_midi_event (MIDIEvent event); - public int set_default_rules (); - } - - /** - * MIDI ROuter Rule - */ - [Compact] - [CCode (cname = "fluid_midi_router_rule_t", cprefix = "fluid_midi_router_rule_", free_function = "delete_fluid_midi_router_rule", has_type_id = false)] - public class MIDIRouterRule { - [CCode (cname = "new_fluid_midi_router_rule")] - public MIDIRouterRule (); - - public void set_chan (int min, int max, float mul, int add); - public void set_param1 (int min, int max, float mul, int add); - public void set_param2 (int min, int max, float mul, int add); - } - - /** - * Functions for configuring the LADSPA effects unit. - */ - [Compact] - [CCode (cname = "fluid_ladpsa_fx_t", cprefix = "fluid_ladpsa_", has_type_id = false)] - public class LADSPAFx { - public int activate (); - public int add_buffer (string name); - public int add_effect (string effect_name, string lib_name, string plugin_name); - public bool buffer_exists (string name); - public int check (char* err, int err_size); - public int deactivate (); - public bool effect_can_mix (string name); - public int effect_link (string effect_name, string port_name, string name); - public bool effect_port_exists (string effect_name, string port_name); - public int effect_set_control (string effect_name, string port_name, float val); - public int effect_set_mix (string name, int mix, float gain); - public bool host_port_exists (string name); - public bool is_active (); - public int reset (); - } -} diff --git a/vapi/libpipewire-0.3.vapi b/vapi/libpipewire-0.3.vapi deleted file mode 100644 index 0f84a79e..00000000 --- a/vapi/libpipewire-0.3.vapi +++ /dev/null @@ -1,27 +0,0 @@ -[CCode(cheader_filename="pipewire/pipewire.h", cprefix = "pw_", lower_case_cprefix="pw_")] -namespace Pipewire { - void init (int* argc = null, string** argv = null); - void deinit (); - string get_application_name (); - string get_prgname (); - string get_user_name (); - string get_host_name (); - string get_client_name (); - bool in_valgrind (); - bool check_option (string option, string value); - SPADirection direction_reverse (SPADirection direction); - int set_domain (string domain); - string get_domain (); - - [CCode (cname = "enum spa_direction", has_type_id = false, cprefix = "SPA_DIRECTION_")] - public enum SPADirection { - INPUT, - OUTPUT - } - - - [CCode (cprefix = "pw_debug_")] - namespace Debug { - bool is_category_enabled (string name); - } -} diff --git a/vapi/lilv-0.vapi b/vapi/lilv-0.vapi deleted file mode 100644 index 463a7ac4..00000000 --- a/vapi/lilv-0.vapi +++ /dev/null @@ -1,274 +0,0 @@ -/* - Copyright 2007-2011 David Robillard - Copyright 2011 Artem Popov - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// vala port of lv2jack.c - -[CCode(cheader_filename="lilv/lilv.h", cprefix="Lilv", lower_case_cprefix="lilv_")] -namespace Lilv { - - [CCode (cname = "LilvUISupportedFunc", has_target = false)] - public delegate uint UISupportedFunc (string container_type_uri, string ui_type_uri); - - [CCode (cprefix = "LILV")] - namespace NS { - public const string DOAP; - public const string FOAF; - public const string LILV; - public const string LV2; - public const string RDF; - public const string RDFS; - public const string XSD; - } - - [CCode (cprefix = "LILV")] - namespace URI { - public const string AUDIO_PORT; - public const string CONTROL_PORT; - public const string EVENT_PORT; - public const string INPUT_PORT; - public const string MIDI_EVENT; - public const string OUTPUT_PORT; - public const string PORT; - } - - [CCode (cprefix = "LILV")] - namespace OPTION { - public const string FILTER_LANG; - public const string DYN_MANIFEST; - } - - public static unowned string uri_to_path(string uri); - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class Plugin { - public bool verify(); - public unowned Node get_uri(); - public unowned Node get_bundle_uri(); - public unowned Nodes get_data_uris(); - public unowned Node get_library_uri(); - public Node get_name(); - public unowned PluginClass get_class(); - public Nodes get_value(Node predicate); - public bool has_feature(Node feature_uri); - public Nodes get_supported_features(); - public Nodes get_required_features(); - public Nodes get_optional_features(); - public uint32 get_num_ports(); - public void get_port_ranges_float(ref float[] min_values, ref float[] max_values, ref float[] def_values); - public uint32 get_num_ports_of_class(Node class_1, ...); - public bool has_latency(); - public uint32 get_latency_port_index(); - public unowned Port get_port_by_index(uint32 index); - public unowned Port get_port_by_symbol(Node symbol); - public Node? get_author_name(); - public Node? get_author_email(); - public Node? get_author_homepage(); - public bool is_replaced(); - - public Instance? instantiate(double sample_rate, - [CCode (array_length = false, array_null_terminated = true)] LV2.Feature*[] features); - public UIs get_uis(); - - // port methods - [CCode (cname = "lilv_port_get_value")] - public Nodes port_get_value(Port port, Node predicate); - [CCode (cname = "lilv_port_get_properties")] - public Nodes port_get_properties(Port port); - [CCode (cname = "lilv_port_has_property")] - public bool port_has_property(Port port, Node property_uri); - [CCode (cname = "lilv_port_supports_event")] - public bool port_supports_event(Port port, Node event_uri); - [CCode (cname = "lilv_port_get_symbol")] - public unowned Node port_get_symbol(Port port); - [CCode (cname = "lilv_port_get_name")] - public Node port_get_name(Port port); - [CCode (cname = "lilv_port_get_classes")] - public unowned Nodes port_get_classes(Port port); - [CCode (cname = "lilv_port_is_a")] - public bool port_is_a(Port port, Node port_class); - [CCode (cname = "lilv_port_get_range")] - public void port_get_range(Port port, out Node deflt, out Node min, out Node max); - [CCode (cname = "lilv_port_get_scale_points")] - public ScalePoints port_get_scale_points(Port port); - } - - [Compact] - [CCode (free_function = "")] - public class PluginClass { - [CCode (cname = "lilv_plugin_class_get_parent_uri")] - public unowned Node get_parent_uri(); - [CCode (cname = "lilv_plugin_class_get_uri")] - public unowned Node get_uri(); - [CCode (cname = "lilv_plugin_class_get_label")] - public unowned Node get_label(); - [CCode (cname = "lilv_plugin_class_get_children")] - public PluginClasses get_children(); - } - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class Port { - } - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class ScalePoint { - public unowned Node get_label(); - public unowned Node get_value(); - } - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class UI { - public unowned Node get_uri(); - public unowned Nodes get_classes(); - public bool is_a(Node class_uri); - public uint is_supported(UISupportedFunc supported_func, Node container_type, out Node ui_type); - public unowned Node get_bundle_uri(); - public unowned Node get_binary_uri(); - } - - [Compact] - [CCode (free_function = "lilv_node_free")] - public class Node { - [CCode(cname="lilv_new_uri")] - public Node.uri(World world, string uri); - [CCode(cname="lilv_new_string")] - public Node.string(World world, string str); - [CCode(cname="lilv_new_int")] - public Node.int(World world, int val); - [CCode(cname="lilv_new_float")] - public Node.float(World world, float val); - [CCode(cname="lilv_new_bool")] - public Node.bool(World world, bool val); - [CCode(cname="lilv_file_uri_parse")] - public static string file_uri_parse (string uri, [CCode (array_length = false, array_null_terminated = true)] string[]? hostname = null); - - public Node duplicate(); - public bool equals(Node other); - public string get_turtle_token(); - - public bool is_uri(); - public unowned string as_uri(); - public bool is_blank(); - public unowned string as_blank(); - public bool is_literal(); - public bool is_string(); - public unowned string as_string(); - public bool is_float(); - public float as_float(); - public bool is_int(); - public int as_int(); - public bool is_bool(); - public bool as_bool(); - } - - [Compact] - [CCode (free_function = "lilv_world_free")] - public class World { - public World(); - public void set_option(string uri, Node value); - public void load_all(); - public void load_bundle(Node bundle_uri); - public unowned PluginClass get_plugin_class(); - public unowned PluginClasses get_plugin_classes(); - public unowned Plugins get_all_plugins(); - public Nodes find_nodes(Node subject, Node predicate, Node object); - } - - [Compact] - [CCode (free_function = "lilv_instance_free")] - public class Instance { - public unowned string get_uri(); - public void connect_port(uint32 port_index, void* data_location); - public void activate(); - public void run(uint32 sample_count); - public void deactivate(); - public void* get_extension_data(string uri); - public unowned LV2.Descriptor get_descriptor(); - public unowned LV2.Handle get_handle(); - } - - // Collections - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class Iter { - } - - [Compact] - [CCode (free_function = "lilv_plugin_classes_free")] - public class PluginClasses { - public uint size(); - public Iter begin(); - public unowned PluginClass? get(Iter i); - public Iter next(Iter i); - public bool is_end(Iter i); - public unowned PluginClass? get_by_uri(Node uri); - } - - [Compact] - [Immutable] - [CCode (free_function = "")] - public class Plugins { - public uint size(); - public Iter begin(); - public unowned Plugin? get(Iter i); - public Iter next(Iter i); - public bool is_end(Iter i); - public unowned Plugin? get_by_uri(Node uri); - } - - [Compact] - [CCode (free_function = "lilv_scale_points_free")] - public class ScalePoints { - public uint size(); - public Iter begin(); - public unowned ScalePoint? get(Iter i); - public Iter next(Iter i); - public bool is_end(Iter i); - } - - [Compact] - [CCode (free_function = "lilv_uis_free")] - public class UIs { - public uint size(); - public Iter begin(); - public unowned UI? get(Iter i); - public Iter next(Iter i); - public bool is_end(Iter i); - public unowned UI? get_by_uri(Node uri); - } - - [Compact] - [CCode (free_function = "lilv_nodes_free")] - public class Nodes { - public uint size(); - public Iter begin(); - public unowned Node? get(Iter i); - public Iter next(Iter i); - public bool is_end(Iter i); - public Node? get_first(); // unowned? - public bool contains(Node value); - } -} diff --git a/vapi/lv2.vapi b/vapi/lv2.vapi deleted file mode 100644 index 90443248..00000000 --- a/vapi/lv2.vapi +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notices: - * - * --- - * - Copyright 2006-2012 Steve Harris, David Robillard. - Copyright 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -// LV2 Core //////////////////////////////////////////////////////////////////// -[CCode(cheader_filename="lv2.h", cprefix="LV2_", lower_case_cprefix="lv2_")] -namespace LV2 { - [CCode(cname="LV2_Feature", has_destroy_function=false, has_copy_function=false)] - public struct Feature { - string URI; - void* data; - } - - public struct Descriptor { - string URI; - } - - [SimpleType] - public struct Handle { - } - - public class Core { - public const string URI; - public const string PREFIX; - - public const string _AllpassPlugin; - public const string _AmplifierPlugin; - public const string _AnalyserPlugin; - public const string _AudioPort; - public const string _BandpassPlugin; - public const string _CVPort; - public const string _ChorusPlugin; - public const string _CombPlugin; - public const string _CompressorPlugin; - public const string _ConstantPlugin; - public const string _ControlPort; - public const string _ConverterPlugin; - public const string _DelayPlugin; - public const string _DistortionPlugin; - public const string _DynamicsPlugin; - public const string _EQPlugin; - public const string _EnvelopePlugin; - public const string _ExpanderPlugin; - public const string _ExtensionData; - public const string _Feature; - public const string _FilterPlugin; - public const string _FlangerPlugin; - public const string _FunctionPlugin; - public const string _GatePlugin; - public const string _GeneratorPlugin; - public const string _HighpassPlugin; - public const string _InputPort; - public const string _InstrumentPlugin; - public const string _LimiterPlugin; - public const string _LowpassPlugin; - public const string _MixerPlugin; - public const string _ModulatorPlugin; - public const string _MultiEQPlugin; - public const string _OscillatorPlugin; - public const string _OutputPort; - public const string _ParaEQPlugin; - public const string _PhaserPlugin; - public const string _PitchPlugin; - public const string _Plugin; - public const string _PluginBase; - public const string _Point; - public const string _Port; - public const string _PortProperty; - public const string _Resource; - public const string _ReverbPlugin; - public const string _ScalePoint; - public const string _SimulatorPlugin; - public const string _SpatialPlugin; - public const string _Specification; - public const string _SpectralPlugin; - public const string _UtilityPlugin; - public const string _WaveshaperPlugin; - public const string _appliesTo; - public const string _binary; - public const string _connectionOptional; - public const string _control; - public const string _default; - public const string _designation; - public const string _documentation; - public const string _enabled; - public const string _enumeration; - public const string _extensionData; - public const string _freeWheeling; - public const string _hardRTCapable; - public const string _inPlaceBroken; - public const string _index; - public const string _integer; - public const string _isLive; - public const string _latency; - public const string _maximum; - public const string _microVersion; - public const string _minimum; - public const string _minorVersion; - public const string _name; - public const string _optionalFeature; - public const string _port; - public const string _portProperty; - public const string _project; - public const string _prototype; - public const string _reportsLatency; - public const string _requiredFeature; - public const string _sampleRate; - public const string _scalePoint; - public const string _symbol; - public const string _toggled; - } -} - - - -// Extensions ////////////////////////////////////////////////////////////////// - -/** - * User interfaces of any type for plugins. - * See for details. -*/ -[CCode (cheader_filename = "lv2/lv2plug.in/ns/extensions/ui/ui.h")] -namespace LV2.UI { - public const string URI; - - public const string PREFIX; - - public const string _CocoaUI; - public const string _Gtk3UI; - public const string _GtkUI; - public const string _PortNotification; - public const string _PortProtocol; - public const string _Qt4UI; - public const string _Qt5UI; - public const string _UI; - public const string _WindowsUI; - public const string _X11UI; - public const string _binary; - public const string _fixedSize; - public const string _idleInterface; - public const string _noUserResize; - public const string _notifyType; - public const string _parent; - public const string _plugin; - public const string _portIndex; - public const string _portMap; - public const string _portNotification; - public const string _portSubscribe; - public const string _protocol; - public const string _requestValue; - public const string _floatProtocol; - public const string _peakProtocol; - public const string _resize; - public const string _showInterface; - public const string _touch; - public const string _ui; - public const string _updateRate; - public const string _windowTitle; - public const string _scaleFactor; - public const string _foregroundColor; - public const string _backgroundColor; - - [CCode (cname = "LV2UI_INVALID_PORT_INDEX")] - public const uint32 INVALID_PORT_INDEX; - - [SimpleType] - [CCode (cname = "LV2UI_Widget")] - public struct Widget { - } - - [SimpleType] - [CCode (cname = "LV2UI_Handle")] - public struct Handle { - } -} - - -[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/urid/urid.h")] -namespace LV2.URID { - [SimpleType] - [CCode (cname = "LV2_URID_Map_Handle")] - public struct MapHandle { - } - - [SimpleType] - [CCode (cname = "LV2_URID_Unmap_Handle")] - public struct UnmapHandle { - } - - [SimpleType] - [IntegerType (rank = 9)] - [CCode (cname = "LV2_URID", has_type_id = false)] - public struct Urid { - } - - [CCode(instance_pos=0)] - public delegate Urid UridMapFunc (string uri); - [CCode(instance_pos=0)] - public delegate string UridUnmapFunc (Urid urid); - - [CCode (cname = "LV2_URID_Map", destroy_function = "")] - public struct UridMap { - [CCode (cname = "handle")] - public MapHandle handle; - [CCode (cname = "map", has_target = false, delegate_target_cname = "handle")] - public unowned UridMapFunc map; - } - - [CCode (cname = "LV2_URID_Unmap", destroy_function = "")] - public struct UridUnmap { - [CCode (cname = "handle")] - public UnmapHandle handle; - [CCode (cname = "unmap", has_target = false, delegate_target_cname = "handle")] - public unowned UridUnmapFunc unmap; - } - - public const string URI; - public const string PREFIX; - - public const string _map; - public const string _unmap; -} - - -[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/atom/atom.h")] -namespace LV2.Atom { - public const string URI; - - public const string PREFIX; - - public const string _Atom; - public const string _AtomPort; - public const string _Blank; - public const string _Bool; - public const string _Chunk; - public const string _Double; - public const string _Event; - public const string _Float; - public const string _Int; - public const string _Literal; - public const string _Long; - public const string _Number; - public const string _Object; - public const string _Path; - public const string _Property; - public const string _Resource; - public const string _Sequence; - public const string _Sound; - public const string _String; - public const string _Tuple; - public const string _URI; - public const string _URID; - public const string _Vector; - public const string _atomTransfer; - public const string _beatTime; - public const string _bufferType; - public const string _childType; - public const string _eventTransfer; - public const string _frameTime; - public const string _supports; - public const string _timeUnit; - - [CCode (cname = "LV2_ATOM_CONTENTS", generic_type_pos = 0)] - public static unowned void* contents (T atom); - - [CCode (cname = "LV2_ATOM_BODY", generic_type_pos = 0)] - public static unowned void* body (Atom atom); - - [CCode (cname = "LV2_Atom", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Atom { - uint32 size; - uint32 type; - } - - [CCode (cname = "LV2_Atom_Int", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Int { - Atom atom; - int32 body; - } - - [CCode (cname = "LV2_Atom_Long", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Long { - Atom atom; - int64 body; - } - - [CCode (cname = "LV2_Atom_Float", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Float { - Atom atom; - float body; - } - - [CCode (cname = "LV2_Atom_Double", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Double { - Atom atom; - double body; - } - - [SimpleType] - [CCode (cname = "LV2_Atom_Bool", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Bool : Int {} - - [CCode (cname = "LV2_Atom_URID", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct URID { - Atom atom; - uint32 body; - } - - [CCode (cname = "LV2_Atom_String", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct String { - Atom atom; - } - - [CCode (cname = "LV2_Atom_Literal_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct LiteralBody { - uint32 datatype; - uint32 lang; - } - - [CCode (cname = "LV2_Atom_Literal", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Literal { - Atom atom; - LiteralBody body; - } - - [CCode (cname = "LV2_Atom_Tuple", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Tuple { - Atom atom; - } - - [CCode (cname = "LV2_Atom_Vector_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct VectorBody { - uint32 child_size; - uint32 child_type; - } - - [CCode (cname = "LV2_Atom_Vector", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Vector { - Atom atom; - VectorBody body; - } - - [CCode (cname = "LV2_Atom_Property_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct PropertyBody { - uint32 key; - uint32 context; - Atom value; - } - - [CCode (cname = "LV2_Atom_Property", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Property { - Atom atom; - PropertyBody body; - } - - [CCode (cname = "LV2_Atom_Object_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct ObjectBody { - uint32 id; - uint32 otype; - } - - [CCode (cname = "LV2_Atom_Object", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Object { - Atom atom; - ObjectBody body; - } - - [CCode (cname = "LV2_Atom_Event", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Event { - [CCode (cname = "time.frames")] - int64 time_frames; - [CCode (cname = "time.beats")] - double time_beats; - Atom body; - } - - - [CCode (cname = "LV2_Atom_Sequence_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct SequenceBody { - uint32 unit; - uint32 pad; - } - - [CCode (cname = "LV2_Atom_Sequence", destroy_function = "", has_type_id = false, has_copy_function = false)] - public struct Sequence { - Atom atom; - SequenceBody body; - } -} - -[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/midi/midi.h")] -namespace LV2.MIDI { - public const string URI; - - public const string PREFIX; - - public const string _ActiveSense; - public const string _Aftertouch; - public const string _Bender; - public const string _Chunk; - public const string _Continue; - public const string _Controller; - public const string _MidiEvent; - public const string _NoteOff; - public const string _NoteOn; - public const string _ProgramChange; - public const string _QuarterFrame; - public const string _Reset; - public const string _SongPosition; - public const string _SongSelect; - public const string _Start; - public const string _Stop; - public const string _SystemCommon; - public const string _SystemExclusive; - public const string _SystemMessage; - public const string _SystemRealtime; - public const string _Tick; - public const string _TuneRequest; - public const string _VoiceMessage; - public const string _benderValue; - public const string _binding; - public const string _byteNumber; - public const string _channel; - public const string _chunk; - public const string _controllerNumber; - public const string _controllerValue; - public const string _noteNumber; - public const string _pressure; - public const string _programNumber; - public const string _property; - public const string _songNumber; - public const string _songPosition; - public const string _status; - public const string _statusMask; - public const string _velocity; - - [CCode (ctype="inline")] - public static bool is_voice_message (uint8 msg); - - [CCode (ctype="inline")] - public static bool is_system_message (uint8 msg); - - [CCode (ctype="inline")] - public static uint8 message_type (uint8 msg); -} - -[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/worker/worker.h")] -namespace LV2.Worker { - public const string URI; - - public const string PREFIX; - - public const string _Interface; - public const string _schedule; - - [CCode (cname = "interface_work_t", has_target = false)] - public delegate Status InterfaceWorkFunc (LV2.Handle instance, RespondFunc respond, RespondHandle handle, uint32 size, [CCode (type="const void*")] void* data); - - [CCode (cname = "interface_work_reponse_t", has_target = false)] - public delegate Status InterfaceWorkResponseFunc (LV2.Handle instance, uint32 size, [CCode (type="const void*")] void* body); - - [CCode (cname = "interface_end_run_t", has_target = false)] - public delegate Status InterfaceEndRunFunc (LV2.Handle instance); - - [Compact] - [SimpleType] - [CCode (cname = "LV2_Worker_Interface", has_type_id = false, free_function = "")] - public class Interface { - [CCode (cname = "work", has_target = false, delegate_target_cname = "", simple_generics = true)] - public unowned InterfaceWorkFunc work; - [CCode (cname = "work_response", has_target = false, delegate_target_cname = "", simple_generics = true)] - public unowned InterfaceWorkResponseFunc work_response; - [CCode (cname = "end_run", has_target = false, delegate_target_cname = "", simple_generics = true)] - public unowned InterfaceEndRunFunc end_run; - } - - /* Status code for worker functions. */ - [CCode (cname = "LV2_Worker_Status", has_type_id = false, cprefix = "LV2_WORKER_")] - public enum Status { - /** Completed successfully. */ - SUCCESS = 0, - /** Unknown error. */ - ERR_UNKNOWN = 1, - /** Failed due to lack of space. */ - ERR_NO_SPACE = 2 - } - - [SimpleType] - [CCode (cname = "LV2_Worker_Respond_Handle")] - public struct RespondHandle { - } - - [SimpleType] - [CCode (cname = "LV2_Worker_Respond_Function", has_target = false)] - public delegate Status RespondFunc (RespondHandle handle, uint32 size, [CCode (type="const void*")] void* data); - - [SimpleType] - [CCode (cname = "LV2_Worker_Schedule_Handle")] - public struct ScheduleHandle { - } - - public delegate Status SchedulerFunc (uint32 size, void* data); - - [CCode (cname = "LV2_Worker_Schedule", destroy_function = "")] - public struct Schedule { - [CCode (cname = "handle")] - public ScheduleHandle handle; - [CCode (cname = "schedule_work", has_target = false, delegate_target_cname = "handle")] - public unowned SchedulerFunc schedule_work; - } - -} diff --git a/vapi/suil-0.vapi b/vapi/suil-0.vapi deleted file mode 100644 index 93ff79eb..00000000 --- a/vapi/suil-0.vapi +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright 2011 David Robillard - Copyright 2011 Artem Popov - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -[CCode(cheader_filename="suil/suil.h", cprefix="Suil", lower_case_cprefix="suil_")] -namespace Suil { - - [CCode (cname = "SuilArg", cprefix = "SUIL_ARG_", has_type_id = false)] - public enum SuilArgs { - NONE - } - - public static void init (int* argc, string*[] argv, SuilArgs key, ...); - - public static uint ui_supported(string host_type_uri, string ui_type_uri); - - [CCode (cname = "SuilPortWriteFunc", has_target = false)] - public delegate void PortWriteFunc(Controller controller, - uint32 port_index, - uint32 buffer_size, - uint32 protocol, - void* buffer); - - [CCode (cname = "SuilPortIndexFunc", has_target = false)] - public delegate uint32 PortIndexFunc(Controller controller, string port_symbol); - - [CCode (cname = "SuilPortSubscribeFunc", has_target = false)] - public delegate uint32 PortSubscribeFunc(Controller controller, - uint32 port_index, - uint32 protocol, - LV2.Feature** features); - - [CCode (cname = "SuilPortUnsubscribeFunc", has_target = false)] - public delegate uint32 PortUnsubscribeFunc(Controller controller, - uint32 port_index, - uint32 protocol, - LV2.Feature** features); - - [Compact] - [CCode (cname="void")] - public class Widget { - } - - [Compact] - [CCode (cname="void")] - public class Controller { - } - - [Compact] - [CCode (free_function = "suil_host_free")] - public class Host { - public Host(PortWriteFunc write_func, - PortIndexFunc index_func, - PortSubscribeFunc subscribe_func, - PortUnsubscribeFunc unsubscribe_func); - } - - [Compact] - [CCode (free_function = "suil_instance_free")] - public class Instance { - public Instance(Host host, - Controller controller, - string container_type_uri, - string plugin_uri, - string ui_uri, - string ui_type_uri, - string ui_bundle_path, - string ui_binary_path, - LV2.Feature** features); - - public Widget get_widget(); - public void port_event(uint32 port_index, - uint32 buffer_size, - uint32 format, - void* buffer); - public unowned void* extension_data(string uri); - } -} diff --git a/vapi/zix-0.vapi b/vapi/zix-0.vapi deleted file mode 100644 index 0cb22e75..00000000 --- a/vapi/zix-0.vapi +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2023-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* - * This file incorporates work covered by the following copyright and - * permission notice: - * - * --- - * - Copyright 2011-2022 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - * - * --- - */ - -[CCode (cprefix="ZIX_", lower_case_cprefix="zix_")] -namespace Zix { - /** A status code returned by functions. */ - [CCode (cname = "ZixStatus", has_type_id = false, cprefix = "ZIX_STATUS_")] - public enum Status { - /** Success. */ - SUCCESS, - /** Unknown Error. */ - ERROR, - /** Out of memory. */ - NO_MEM, - /** Not found. */ - NOT_FOUND, - /** Exists. */ - EXISTS, - /** Bad Argument. */ - BAD_ARG, - /** Bad Permissions. */ - BAD_PERMS, - /** Reached end. */ - REACHED_END, - /** Timeout. */ - TIMEOUT, - /** Overflow. */ - OVERFLOW, - /** Not Supported. */ - NOT_SUPPORTED, - /** Resource unavailable. */ - UNAVAILABLE, - /** Out of storage space. */ - NO_SPACE, - /** Too many links. */ - MAX_LINKS - } - - [Compact] - [CCode (cheader_filename = "zix/allocator.h", cname = "ZixAllocator", cprefix = "zix_", free_function = "zix_free", has_type_id = false)] - public class Allocator { - - } - - [Compact] - [CCode (cheader_filename = "zix/ring.h", cname = "ZixRing", cprefix = "zix_ring_", free_function = "zix_ring_free", has_type_id = false)] - public class Ring { - // Setup - /** - * Creates a new `Ring` instance. - * - * At most size - 1 bytes may be stored in the ring at once. - * - * @param allocator allocator for the ring object and its array - * @param size size of the ring in bytes (note this may be rounded up) - */ - public Ring (Allocator? allocator, uint32 size); - /** - * Lock the ring data into physical memory. - * - * This function is NOT thread safe or real-time safe, but it should be - * called after zix_ring_new() to lock all ring memory to avoid page - * faults while using the ring. - */ - public Status mlock (); - public void reset (); - public uint32 capacity (); - - // Reading - public uint32 read_space (); - public uint32 peak (void* dst, uint32 size); - public uint32 read (void* dst, uint32 size); - public uint32 skip (uint32 size); - - // Writing - [SimpleType] - [CCode (cname = "ZixRingTransaction", cprefix = "", free_function = "", destroy_function = "", has_type_id = false)] - public struct Transaction { - uint32 read_head; - uint32 write_head; - } - - public uint32 write_space (); - public uint32 write ([CCode (type="const void*")] void* src, uint32 size); - public Transaction begin_write (); - public Status amend_write (Transaction? tx, [CCode (type="const void*")] void* src, uint32 size); - public Status commit_write (Transaction? tx); - - } - - [CCode (cheader_filename = "zix/sem.h", cname = "ZixSem", cprefix = "zix_sem_", destroy_function = "", has_type_id = false)] - public struct Sem { - public static Status init (out Sem sem, uint initial); - public Status destroy (); - public Status post (); - public Status wait (); - public Status try_wait (); - public Status timed_wait (uint32 seconds, uint32 nanoseconds); - } - - [SimpleType] - [CCode (cheader_filename = "zix/thread.h", cname = "ZixThread", cprefix = "zix_thread_", destroy_function = "", has_type_id = false)] - public struct Thread { - public static Status create (out Thread thread, size_t stack_size, ThreadFunc function); - public Status join (); - } - - [SimpleType] - [CCode (cheader_filename = "zix/thread.h", cname = "ZixThreadResult")] - public struct ThreadResult { - } - - public delegate ThreadResult ThreadFunc (); -} From 5ac3dbc416ede36aa658bcb67ea7fa81a7ed481f Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 19 Jun 2023 09:26:12 +0530 Subject: [PATCH 11/37] Use new arranger workstation builder --- .gitignore | 1 + meson.build | 1 + src/Application.vala | 24 ++++++++++++------------ subprojects/ens-aw-core.wrap | 1 + subprojects/ens-gui-shell.wrap | 4 ++++ subprojects/ens-tui-shell.wrap | 1 + 6 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 subprojects/ens-gui-shell.wrap diff --git a/.gitignore b/.gitignore index 85c4b29a..3f4edb68 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ null.d .~lock* xtleak.kcg.* subprojects/ens-aw-core/ +subprojects/ens-gui-shell/ subprojects/ens-tui-shell/ diff --git a/meson.build b/meson.build index 3d5dec5d..4818efbc 100644 --- a/meson.build +++ b/meson.build @@ -49,6 +49,7 @@ dependencies = [ dependency ('x11'), dependency ('gtk4'), dependency ('glib-2.0'), + # dependency ('ens-gui-shell-0', fallback: ['ens-gui-shell', 'ens_gui_shell_dep']), dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']), dependency ('ens-tui-shell-0', fallback: ['ens-tui-shell', 'ens_tui_shell_dep']) ] diff --git a/src/Application.vala b/src/Application.vala index 812796aa..c34c95ed 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +// using Ensembles.Shell; using Ensembles.ArrangerWorkstation; namespace Ensembles { @@ -36,6 +37,7 @@ namespace Ensembles { // public static Shell.MainWindow main_window; // public static Core.ArrangerWorkstation arranger_workstation; + // public MainWindow main_window; public AWCore aw_core; construct { @@ -45,8 +47,16 @@ namespace Ensembles { } protected override void activate () { - Console.log ("Initializing GUI Theme"); - // Services.Theme.init_theme (); + Console.log ("Initializing Arranger Workstation"); + aw_core = AWCore.Builder () + .using_driver ("alsa") + .load_sf_from (Constants.SF2DATADIR) + .add_style_search_path (Constants.PKGDATADIR + "/StyleFiles") + .add_style_search_path (Environment.get_user_special_dir ( + GLib.UserDirectory.DOCUMENTS) + + "/ensembles" + + "/styles") + .build (); Console.log ("Initializing Main Window"); // main_window = new Shell.MainWindow (this); @@ -57,16 +67,6 @@ namespace Ensembles { // Console.LogLevel.SUCCESS // ); - Console.log ("Initializing Arranger Workstation"); - aw_core = AWCore.instance - .use_driver ("alsa") - .add_soundfont (Constants.SF2DATADIR) - .add_style_search_path (Constants.PKGDATADIR + "/StyleFiles") - .add_style_search_path (Environment.get_user_special_dir ( - GLib.UserDirectory.DOCUMENTS) + - "/ensembles" + - "/styles") - .build_synth_engine (); aw_core.load_data_async (); if (Settings.instance.version != Constants.VERSION) { diff --git a/subprojects/ens-aw-core.wrap b/subprojects/ens-aw-core.wrap index 38403b1d..7975e09a 100644 --- a/subprojects/ens-aw-core.wrap +++ b/subprojects/ens-aw-core.wrap @@ -1,4 +1,5 @@ [wrap-git] url = https://github.com/ensemblesaw/arranger-workstation-core +depth = 1 revision = main diff --git a/subprojects/ens-gui-shell.wrap b/subprojects/ens-gui-shell.wrap new file mode 100644 index 00000000..0e349fef --- /dev/null +++ b/subprojects/ens-gui-shell.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://github.com/ensemblesaw/gui-shell +depth = 1 +revision = main diff --git a/subprojects/ens-tui-shell.wrap b/subprojects/ens-tui-shell.wrap index f00ab078..936d946c 100644 --- a/subprojects/ens-tui-shell.wrap +++ b/subprojects/ens-tui-shell.wrap @@ -1,3 +1,4 @@ [wrap-git] url = https://github.com/ensemblesaw/tui-shell +depth = 1 revision = main From 95d122b350fac7c001d9b4734164dc6d8e314af0 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 19 Jun 2023 13:23:51 +0530 Subject: [PATCH 12/37] Add styles from the actual library --- .gitignore | 1 + meson.build | 1 + src/Application.vala | 4 +--- subprojects/ens-aw-core.wrap | 1 - subprojects/enstl.wrap | 4 ++++ 5 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 subprojects/enstl.wrap diff --git a/.gitignore b/.gitignore index 3f4edb68..b5b1802b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ null.d *~ .~lock* xtleak.kcg.* +subprojects/enstl/ subprojects/ens-aw-core/ subprojects/ens-gui-shell/ subprojects/ens-tui-shell/ diff --git a/meson.build b/meson.build index 4818efbc..7ad0496b 100644 --- a/meson.build +++ b/meson.build @@ -49,6 +49,7 @@ dependencies = [ dependency ('x11'), dependency ('gtk4'), dependency ('glib-2.0'), + dependency ('ens-enstl-0', fallback: ['enstl', 'enstl_dep']), # dependency ('ens-gui-shell-0', fallback: ['ens-gui-shell', 'ens_gui_shell_dep']), dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']), dependency ('ens-tui-shell-0', fallback: ['ens-tui-shell', 'ens_tui_shell_dep']) diff --git a/src/Application.vala b/src/Application.vala index c34c95ed..9680df89 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -35,8 +35,6 @@ namespace Ensembles { public static bool kiosk_mode = false; public static bool verbose = false; - // public static Shell.MainWindow main_window; - // public static Core.ArrangerWorkstation arranger_workstation; // public MainWindow main_window; public AWCore aw_core; @@ -51,7 +49,7 @@ namespace Ensembles { aw_core = AWCore.Builder () .using_driver ("alsa") .load_sf_from (Constants.SF2DATADIR) - .add_style_search_path (Constants.PKGDATADIR + "/StyleFiles") + .add_style_search_path (StyleRepository.get_style_dir ()) .add_style_search_path (Environment.get_user_special_dir ( GLib.UserDirectory.DOCUMENTS) + "/ensembles" + diff --git a/subprojects/ens-aw-core.wrap b/subprojects/ens-aw-core.wrap index 7975e09a..e866b831 100644 --- a/subprojects/ens-aw-core.wrap +++ b/subprojects/ens-aw-core.wrap @@ -2,4 +2,3 @@ url = https://github.com/ensemblesaw/arranger-workstation-core depth = 1 revision = main - diff --git a/subprojects/enstl.wrap b/subprojects/enstl.wrap new file mode 100644 index 00000000..61b0ddcb --- /dev/null +++ b/subprojects/enstl.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://github.com/ensemblesaw/styles +depth = 1 +revision = main From 728018158e60dd228a973e747e80329bacdc28fc Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 15 Jul 2023 20:57:15 +0530 Subject: [PATCH 13/37] Establish submodules --- .gitignore | 4 -- .gitmodules | 19 +++++++ meson.build | 10 ++-- src/Application.vala | 38 ++++++++----- src/Main.vala | 34 ++++++++++-- src/Services.vala | 10 ++++ src/Settings.vala | 98 ---------------------------------- src/meson.build | 3 +- subprojects/ens-aw-core | 1 + subprojects/ens-gui-shell.wrap | 4 -- subprojects/ens-shell-cli | 1 + subprojects/ens-shell-cli.wrap | 4 ++ subprojects/ens-shell-gtk | 1 + subprojects/ens-shell-gtk.wrap | 5 ++ subprojects/ens-tui-shell.wrap | 4 -- subprojects/enstl | 1 + subprojects/libvinject | 1 + subprojects/libvinject.wrap | 7 +++ 18 files changed, 112 insertions(+), 133 deletions(-) create mode 100644 .gitmodules create mode 100644 src/Services.vala delete mode 100644 src/Settings.vala create mode 160000 subprojects/ens-aw-core delete mode 100644 subprojects/ens-gui-shell.wrap create mode 160000 subprojects/ens-shell-cli create mode 100644 subprojects/ens-shell-cli.wrap create mode 160000 subprojects/ens-shell-gtk create mode 100644 subprojects/ens-shell-gtk.wrap delete mode 100644 subprojects/ens-tui-shell.wrap create mode 160000 subprojects/enstl create mode 160000 subprojects/libvinject create mode 100644 subprojects/libvinject.wrap diff --git a/.gitignore b/.gitignore index b5b1802b..00a18a74 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,3 @@ null.d *~ .~lock* xtleak.kcg.* -subprojects/enstl/ -subprojects/ens-aw-core/ -subprojects/ens-gui-shell/ -subprojects/ens-tui-shell/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..97e736e9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,19 @@ +[submodule "ens-aw-core"] +path = subprojects/ens-aw-core +url = https://github.com/ensemblesaw/ens-aw-core + +[submodule "ens-shell-cli"] +path = subprojects/ens-shell-cli +url = https://github.com/ensemblesaw/ens-shell-cli + +[submodule "ens-shell-gtk"] +path = subprojects/ens-shell-gtk +url = https://github.com/ensemblesaw/ens-shell-gtk + +[submodule "libvinject"] +path = subprojects/libvinject +url = https://gitlab.com/geeky_endeavours/vinject.git + +[submodule "enstl"] +path = subprojects/enstl +url = https://github.com/ensemblesaw/enstl diff --git a/meson.build b/meson.build index 7ad0496b..7a836ccd 100644 --- a/meson.build +++ b/meson.build @@ -46,13 +46,13 @@ message(build_dir.split('/')[-1]) # Listing dependencies dependencies = [ - dependency ('x11'), - dependency ('gtk4'), dependency ('glib-2.0'), + dependency ('gee-0.8'), + dependency ('libvinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), dependency ('ens-enstl-0', fallback: ['enstl', 'enstl_dep']), - # dependency ('ens-gui-shell-0', fallback: ['ens-gui-shell', 'ens_gui_shell_dep']), - dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']), - dependency ('ens-tui-shell-0', fallback: ['ens-tui-shell', 'ens_tui_shell_dep']) + dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep']), + dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep']), + dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']) ] # Set up the profile diff --git a/src/Application.vala b/src/Application.vala index 9680df89..fde18bb0 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -35,8 +35,7 @@ namespace Ensembles { public static bool kiosk_mode = false; public static bool verbose = false; - // public MainWindow main_window; - public AWCore aw_core; + private Vinject.Injector di_container; construct { flags |= ApplicationFlags.HANDLES_OPEN | @@ -46,15 +45,25 @@ namespace Ensembles { protected override void activate () { Console.log ("Initializing Arranger Workstation"); - aw_core = AWCore.Builder () - .using_driver ("alsa") - .load_sf_from (Constants.SF2DATADIR) - .add_style_search_path (StyleRepository.get_style_dir ()) - .add_style_search_path (Environment.get_user_special_dir ( - GLib.UserDirectory.DOCUMENTS) + - "/ensembles" + - "/styles") - .build (); + di_container = Services.create_di_container ( + new ArrangerWorkstationBuilder () + .using_driver ("alsa") + .load_sf_from (Constants.SF2DATADIR) + .add_style_search_path (StyleRepository.get_style_dir ()) + .add_style_search_path (Environment.get_user_special_dir ( + GLib.UserDirectory.DOCUMENTS) + + "/ensembles" + + "/styles") + ); + // aw_core = AWCore.Builder () + // .using_driver ("alsa") + // .load_sf_from (Constants.SF2DATADIR) + // .add_style_search_path (StyleRepository.get_style_dir ()) + // .add_style_search_path (Environment.get_user_special_dir ( + // GLib.UserDirectory.DOCUMENTS) + + // "/ensembles" + + // "/styles") + // .build (); Console.log ("Initializing Main Window"); // main_window = new Shell.MainWindow (this); @@ -64,8 +73,11 @@ namespace Ensembles { // "GUI Initialization Complete!", // Console.LogLevel.SUCCESS // ); - - aw_core.load_data_async (); + try { + di_container.obtain (Services.aw_core).load_data_async (); + } catch (Error e) { + Console.log(e.message, Console.LogLevel.ERROR); + } if (Settings.instance.version != Constants.VERSION) { Settings.instance.version = Constants.VERSION; diff --git a/src/Main.vala b/src/Main.vala index 50a650aa..3c33bc95 100644 --- a/src/Main.vala +++ b/src/Main.vala @@ -3,12 +3,40 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +using Ensembles; + public static int main (string[] args) { Environment.set_application_name (Constants.APP_NAME); Environment.set_prgname (Constants.APP_NAME); - var application = new Ensembles.Application (); - application.init (args); + Services.di_container = new Vinject.Injector (); + + try { + Services.configure_gtkshell_service ( + Constants.APP_ID, + Constants.VERSION, + Constants.DISPLAYVER + ); + + Services.configure_aw_service ((aw_builder) => { + aw_builder.use_driver (Ensembles.ArrangerWorkstation.AWCore.Driver.ALSA) + .load_soundfont_with_name ("Ensembles") + .load_soundfont_from_dir (Constants.SF2DATADIR) + .add_style_search_path (StyleRepository.get_style_dir ()) + .add_style_search_path (Environment.get_user_special_dir ( + GLib.UserDirectory.DOCUMENTS) + + "/ensembles" + + "/styles" + ); + }); + } catch (Vinject.VinjectErrors e) { + Services.handle_di_error (e); + } + + // GTK + // var application = new Ensembles.Application (); + // application.init (args); - return application.run (args); + // return application.run (args); + return 0; } diff --git a/src/Services.vala b/src/Services.vala new file mode 100644 index 00000000..42f099b2 --- /dev/null +++ b/src/Services.vala @@ -0,0 +1,10 @@ +using Vinject; +using Ensembles.ArrangerWorkstation; + +namespace Ensembles.Services { + static Injector di_container; + + static void handle_di_error (VinjectErrors e) { + Console.log ("FATAL: Dependency injection error occurred! %s. Exiting...".printf (e.message), Console.LogLevel.ERROR); + } +} diff --git a/src/Settings.vala b/src/Settings.vala deleted file mode 100644 index d055ce34..00000000 --- a/src/Settings.vala +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -namespace Ensembles { - public class Settings : GLib.Settings { - private Settings () { - Object (schema_id: Constants.APP_ID); - } - - private static Settings _instance; - - public static Settings instance { - get { - if (_instance == null) { - _instance = new Settings (); - } - - return _instance; - } - } - - public string version { - owned get { return get_string ("version"); } - set { set_string ("version", value); } - } - - // Main Window ///////////////////////////////////////////////////////// - /** The saved x-position of the window. */ - public int window_x { - get { return get_int ("window-x"); } - set { set_int ("window-x", value); } - } - - /** The saved y-position of the window. */ - public int window_y { - get { return get_int ("window-y"); } - set { set_int ("window-y", value); } - } - - /** The saved width of the window. */ - public int window_w { - get { return get_int ("window-w"); } - set { set_int ("window-w", value); } - } - - /** The saved height of the window. */ - public int window_h { - get { return get_int ("window-h"); } - set { set_int ("window-h", value); } - } - - /** If window should be maximized */ - public bool window_maximized { - get { return get_boolean ("window-maximized"); } - set { set_boolean ("window-maximized", value); } - } - - /** Info Display theme */ - public string display_theme { - owned get { return get_string ("display-theme"); } - set { set_string ("display-theme", value); } - } - - // Arranger Core /////////////////////////////////////////////////////// - /** Enstl style path of the last used style*/ - public string style_path { - owned get { return get_string ("style-path"); } - set { set_string ("style-path", value); } - } - - // Style Engine //////////////////////////////////////////////////////// - /** - * If autofill is `true`, then style engine automatically adds a fill-in - * when switching between variations. - */ - public bool autofill { - get { return get_boolean ("autofill"); } - set { set_boolean ("autofill", value); } - } - - // /** - // * How chord should be interpreted from the keyboard input. - // * - // * - `SPLIT_LONG`: Determine chord from multiple keys only on left side - // * of split point - // * - `SPLIT_SHORT`: Determine chord from two fingers only on left side - // * of split point - // * - `FULL_RANGE`: Determine chord from multiple fingers from any place - // * on the keyboard - // */ - // public Core.Analysers.ChordAnalyser.ChordDetectionMode chord_detection_mode { - // get { return get_enum ("chord-detection-mode"); } - // set { set_enum ("chord-detection-mode", value); } - // } - } -} diff --git a/src/meson.build b/src/meson.build index 6ee8d3ef..54021ced 100644 --- a/src/meson.build +++ b/src/meson.build @@ -15,6 +15,5 @@ config_header = configure_file ( sources = files ( 'Main.vala', - 'Application.vala', - 'Settings.vala' + 'Services.vala' ) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core new file mode 160000 index 00000000..707f9ad2 --- /dev/null +++ b/subprojects/ens-aw-core @@ -0,0 +1 @@ +Subproject commit 707f9ad25acef3654e1522129e7b574e97be5137 diff --git a/subprojects/ens-gui-shell.wrap b/subprojects/ens-gui-shell.wrap deleted file mode 100644 index 0e349fef..00000000 --- a/subprojects/ens-gui-shell.wrap +++ /dev/null @@ -1,4 +0,0 @@ -[wrap-git] -url = https://github.com/ensemblesaw/gui-shell -depth = 1 -revision = main diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli new file mode 160000 index 00000000..f64ea476 --- /dev/null +++ b/subprojects/ens-shell-cli @@ -0,0 +1 @@ +Subproject commit f64ea4768cf53cb78ab57ad0d3bcd50f9378604d diff --git a/subprojects/ens-shell-cli.wrap b/subprojects/ens-shell-cli.wrap new file mode 100644 index 00000000..77695508 --- /dev/null +++ b/subprojects/ens-shell-cli.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://github.com/ensemblesaw/ens-shell-cli +depth = 1 +revision = main diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk new file mode 160000 index 00000000..603836b2 --- /dev/null +++ b/subprojects/ens-shell-gtk @@ -0,0 +1 @@ +Subproject commit 603836b26e1ec4f47fc8b51738804d7cdb4960fd diff --git a/subprojects/ens-shell-gtk.wrap b/subprojects/ens-shell-gtk.wrap new file mode 100644 index 00000000..f648f841 --- /dev/null +++ b/subprojects/ens-shell-gtk.wrap @@ -0,0 +1,5 @@ +[wrap-git] +url = https://github.com/ensemblesaw/ens-shell-gtk +depth = 1 +clone-recursive = true +revision = main diff --git a/subprojects/ens-tui-shell.wrap b/subprojects/ens-tui-shell.wrap deleted file mode 100644 index 936d946c..00000000 --- a/subprojects/ens-tui-shell.wrap +++ /dev/null @@ -1,4 +0,0 @@ -[wrap-git] -url = https://github.com/ensemblesaw/tui-shell -depth = 1 -revision = main diff --git a/subprojects/enstl b/subprojects/enstl new file mode 160000 index 00000000..21b78ffe --- /dev/null +++ b/subprojects/enstl @@ -0,0 +1 @@ +Subproject commit 21b78ffe86470a9b4335eb27ea97267693219ba9 diff --git a/subprojects/libvinject b/subprojects/libvinject new file mode 160000 index 00000000..3b149cee --- /dev/null +++ b/subprojects/libvinject @@ -0,0 +1 @@ +Subproject commit 3b149cee9b0d9807e8b858d844761ea363954528 diff --git a/subprojects/libvinject.wrap b/subprojects/libvinject.wrap new file mode 100644 index 00000000..2408b60e --- /dev/null +++ b/subprojects/libvinject.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url=https://gitlab.com/geeky_endeavours/vinject.git +revision=main +depth=1 + +[provide] +vinject-0.0.0 = vinject_dep From 3f44ed9b6e87fb21ed582d5990dc3289d77b93b5 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 15 Jul 2023 20:58:56 +0530 Subject: [PATCH 14/37] LINT --- subprojects/ens-shell-cli | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli index f64ea476..83ef9eab 160000 --- a/subprojects/ens-shell-cli +++ b/subprojects/ens-shell-cli @@ -1 +1 @@ -Subproject commit f64ea4768cf53cb78ab57ad0d3bcd50f9378604d +Subproject commit 83ef9eab86539b432f0fa2022c7adb5c65cd2cc6 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 603836b2..2b358681 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 603836b26e1ec4f47fc8b51738804d7cdb4960fd +Subproject commit 2b3586818b32a81d59fdd96b6eb7fe46f58f61c8 From e00ce50fe5bc2e7759a5c9f84945e68eac3ca6c9 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sat, 15 Jul 2023 21:01:34 +0530 Subject: [PATCH 15/37] Update submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 97e736e9..c145f050 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/ensemblesaw/ens-shell-gtk [submodule "libvinject"] path = subprojects/libvinject -url = https://gitlab.com/geeky_endeavours/vinject.git +url = https://gitlab.com/geeky_endeavours/vinject [submodule "enstl"] path = subprojects/enstl From 718f44f1b6b749b35d21acbff4652ab493944946 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 16 Jul 2023 18:43:32 +0530 Subject: [PATCH 16/37] Implement di container --- src/Application.vala | 141 -------------------------------------- src/Main.vala | 30 ++++---- src/Services.vala | 5 +- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-cli | 2 +- subprojects/ens-shell-gtk | 2 +- 6 files changed, 25 insertions(+), 157 deletions(-) delete mode 100644 src/Application.vala diff --git a/src/Application.vala b/src/Application.vala deleted file mode 100644 index fde18bb0..00000000 --- a/src/Application.vala +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -// using Ensembles.Shell; -using Ensembles.ArrangerWorkstation; - -namespace Ensembles { - /** - * ## Ensembles Application - * - * Provides a GTK Application instance where only a single instance - * is allowed. - * The Ensembles application works as a conjuncture of two components: - * - Core: The arranger system and all it's plugins - * - Shell: The user interface - */ - public class Application : Gtk.Application { - static Application _instance = null; - - public static Application instance { - get { - if (_instance == null) { - _instance = new Application (); - } - return _instance; - } - } - - // public static Services.EventBus event_bus = new Services.EventBus (); - - private string[] ? arg_file = null; - public static bool raw_midi_input = false; - public static bool kiosk_mode = false; - public static bool verbose = false; - - private Vinject.Injector di_container; - - construct { - flags |= ApplicationFlags.HANDLES_OPEN | - ApplicationFlags.HANDLES_COMMAND_LINE; - application_id = Constants.APP_ID; - } - - protected override void activate () { - Console.log ("Initializing Arranger Workstation"); - di_container = Services.create_di_container ( - new ArrangerWorkstationBuilder () - .using_driver ("alsa") - .load_sf_from (Constants.SF2DATADIR) - .add_style_search_path (StyleRepository.get_style_dir ()) - .add_style_search_path (Environment.get_user_special_dir ( - GLib.UserDirectory.DOCUMENTS) + - "/ensembles" + - "/styles") - ); - // aw_core = AWCore.Builder () - // .using_driver ("alsa") - // .load_sf_from (Constants.SF2DATADIR) - // .add_style_search_path (StyleRepository.get_style_dir ()) - // .add_style_search_path (Environment.get_user_special_dir ( - // GLib.UserDirectory.DOCUMENTS) + - // "/ensembles" + - // "/styles") - // .build (); - - Console.log ("Initializing Main Window"); - // main_window = new Shell.MainWindow (this); - // this.add_window (main_window); - // main_window.show_ui (); - // Console.log ( - // "GUI Initialization Complete!", - // Console.LogLevel.SUCCESS - // ); - try { - di_container.obtain (Services.aw_core).load_data_async (); - } catch (Error e) { - Console.log(e.message, Console.LogLevel.ERROR); - } - - if (Settings.instance.version != Constants.VERSION) { - Settings.instance.version = Constants.VERSION; - // Show welcome screen - } - - if (Constants.PROFILE == "development") { - - } - } - - protected override int command_line (ApplicationCommandLine cmd) { - string[] args_cmd = cmd.get_arguments (); - unowned string[] args = args_cmd; - - GLib.OptionEntry [] options = new OptionEntry [5]; - options [0] = { "", 0, 0, OptionArg.STRING_ARRAY, ref arg_file, null, "URI" }; - options [1] = { "raw", 0, 0, OptionArg.NONE, ref raw_midi_input, _("Enable Raw MIDI Input"), null }; - options [2] = { "kiosk", 0, 0, OptionArg.NONE, ref kiosk_mode, _("Only show the info display"), null }; - options [3] = { "verbose", 0, 0, OptionArg.NONE, ref verbose, _("Print debug messages to terminal"), null }; - options [4] = { null }; - - var opt_context = new OptionContext ("actions"); - opt_context.add_main_entries (options, null); - try { - opt_context.parse (ref args); - } catch (Error err) { - warning (err.message); - return -1; - } - - if (verbose || raw_midi_input || kiosk_mode) { - Console.greet (Constants.VERSION, Constants.DISPLAYVER); - } - - if (raw_midi_input) { - Console.log ("Raw MIDI Input Enabled! You can now enable midi input and connect your DAW\n"); - } - - if (kiosk_mode) { - Console.log ("Starting Ensembles in Kiosk Mode\n"); - } - - if (arg_file != null && arg_file[0] != null) { - if (GLib.FileUtils.test (arg_file[0], GLib.FileTest.EXISTS) && - arg_file[0].down ().has_suffix (".mid")) { - File file = File.new_for_path (arg_file[0]); - open ({ file }, ""); - return 0; - } - } - - activate (); - return 0; - } - - public void init (string[] args) { - X.init_threads (); - } - } -} diff --git a/src/Main.vala b/src/Main.vala index 3c33bc95..065198eb 100644 --- a/src/Main.vala +++ b/src/Main.vala @@ -9,18 +9,15 @@ public static int main (string[] args) { Environment.set_application_name (Constants.APP_NAME); Environment.set_prgname (Constants.APP_NAME); + Console.greet (Constants.VERSION, Constants.DISPLAYVER); + Services.di_container = new Vinject.Injector (); try { - Services.configure_gtkshell_service ( - Constants.APP_ID, - Constants.VERSION, - Constants.DISPLAYVER - ); - + // Arranger Workstation Service Services.configure_aw_service ((aw_builder) => { aw_builder.use_driver (Ensembles.ArrangerWorkstation.AWCore.Driver.ALSA) - .load_soundfont_with_name ("Ensembles") + .load_soundfont_with_name ("EnsemblesGM") .load_soundfont_from_dir (Constants.SF2DATADIR) .add_style_search_path (StyleRepository.get_style_dir ()) .add_style_search_path (Environment.get_user_special_dir ( @@ -29,14 +26,23 @@ public static int main (string[] args) { "/styles" ); }); + + // GTK 4 + Services.configure_gtkshell_service ((shell_builder) => { + shell_builder.with_app_id (Constants.APP_ID) + .with_name ("Ensembles") + .with_icon_name ("com.github.ensemblesaw.ensembles") + .has_version (Constants.VERSION, Constants.DISPLAYVER); + }); + + return Services.di_container.obtain (Services.st_application).run (); + + // QT 3 + + // Windows UI 3 } catch (Vinject.VinjectErrors e) { Services.handle_di_error (e); } - // GTK - // var application = new Ensembles.Application (); - // application.init (args); - - // return application.run (args); return 0; } diff --git a/src/Services.vala b/src/Services.vala index 42f099b2..d289fe39 100644 --- a/src/Services.vala +++ b/src/Services.vala @@ -5,6 +5,9 @@ namespace Ensembles.Services { static Injector di_container; static void handle_di_error (VinjectErrors e) { - Console.log ("FATAL: Dependency injection error occurred! %s. Exiting...".printf (e.message), Console.LogLevel.ERROR); + Console.log ( + "FATAL: Dependency injection error occurred! %s. Exiting…" + .printf (e.message), Console.LogLevel.ERROR + ); } } diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 707f9ad2..0848718e 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 707f9ad25acef3654e1522129e7b574e97be5137 +Subproject commit 0848718efba7bb236c8fbefc9516e876f1292160 diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli index 83ef9eab..f605ec32 160000 --- a/subprojects/ens-shell-cli +++ b/subprojects/ens-shell-cli @@ -1 +1 @@ -Subproject commit 83ef9eab86539b432f0fa2022c7adb5c65cd2cc6 +Subproject commit f605ec32a4c5068925c6c409d249f1fece4e5e25 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 2b358681..d96d9b22 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 2b3586818b32a81d59fdd96b6eb7fe46f58f61c8 +Subproject commit d96d9b22cb0eda5a6c63ae999642a1eacafc40f0 From a062b38edbfe71a0ed5f511c12fff6f38afbbe97 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 16 Jul 2023 19:55:04 +0530 Subject: [PATCH 17/37] Fix submodule situation --- .gitmodules | 2 +- subprojects/ens-aw-core | 2 +- subprojects/ens-aw-core.wrap | 2 +- subprojects/ens-shell-gtk | 2 +- subprojects/libvinject | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index c145f050..97e736e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/ensemblesaw/ens-shell-gtk [submodule "libvinject"] path = subprojects/libvinject -url = https://gitlab.com/geeky_endeavours/vinject +url = https://gitlab.com/geeky_endeavours/vinject.git [submodule "enstl"] path = subprojects/enstl diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 0848718e..d64e803f 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 0848718efba7bb236c8fbefc9516e876f1292160 +Subproject commit d64e803fc315bb6d9362d59c266370333c5b69da diff --git a/subprojects/ens-aw-core.wrap b/subprojects/ens-aw-core.wrap index e866b831..58444842 100644 --- a/subprojects/ens-aw-core.wrap +++ b/subprojects/ens-aw-core.wrap @@ -1,4 +1,4 @@ [wrap-git] -url = https://github.com/ensemblesaw/arranger-workstation-core +url = https://github.com/ensemblesaw/ens-aw-core depth = 1 revision = main diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index d96d9b22..891fa7b6 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit d96d9b22cb0eda5a6c63ae999642a1eacafc40f0 +Subproject commit 891fa7b67b3a5d42798c30f2c30fdafb39d254ca diff --git a/subprojects/libvinject b/subprojects/libvinject index 3b149cee..3f2f69a8 160000 --- a/subprojects/libvinject +++ b/subprojects/libvinject @@ -1 +1 @@ -Subproject commit 3b149cee9b0d9807e8b858d844761ea363954528 +Subproject commit 3f2f69a867cbed015455c64df4fb30cbbb78ab98 From 9a7dac15c6cd3f33e4517aea1dcd9ad323ce68d7 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 17 Jul 2023 13:39:38 +0530 Subject: [PATCH 18/37] Clean stuff --- ...ml => com.github.ensemblesaw.ensembles.yml | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...g => com.github.ensemblesaw.ensembles.svg} | 0 ...github.ensemblesaw.ensembles-symbolic.svg} | 0 ...in-sandru-7SxSkCvVM1U-unsplash-blurred.jpg | Bin 155871 -> 0 bytes .../catalin-sandru-7SxSkCvVM1U-unsplash.jpg | Bin 213759 -> 0 bytes ...talin-sandru-7SxSkCvVM1U-unsplash.jpg.back | Bin 90591 -> 0 bytes data/Images/Display/splash_screen.png | Bin 19166 -> 0 bytes data/Images/beat_counter.svg | 549 ----------------- data/Themes/Application.css | 342 ----------- data/Themes/Display/Display.css | 570 ------------------ ...thub.ensemblesaw.ensembles.appdata.xml.in} | 2 +- ...m.github.ensemblesaw.ensembles.desktop.in} | 6 +- ...ithub.ensemblesaw.ensembles.kiosk.desktop} | 2 +- ...thub.subhadeepjasu.ensembles.gresource.xml | 24 - ...hub.subhadeepjasu.ensembles.gschema.xml.in | 62 -- data/meson.build | 13 - meson.build | 43 +- meson/post_install.py | 5 +- subprojects/ens-shell-gtk | 2 +- 24 files changed, 24 insertions(+), 1596 deletions(-) rename com.github.subhadeepjasu.ensembles.yml => com.github.ensemblesaw.ensembles.yml (100%) rename data/Icons/128/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/16/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/24/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/32/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/48/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/64/{com.github.subhadeepjasu.ensembles.svg => com.github.ensemblesaw.ensembles.svg} (100%) rename data/Icons/symbolic/{com.github.subhadeepjasu.ensembles-symbolic.svg => com.github.ensemblesaw.ensembles-symbolic.svg} (100%) delete mode 100644 data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg delete mode 100644 data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg delete mode 100644 data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg.back delete mode 100644 data/Images/Display/splash_screen.png delete mode 100644 data/Images/beat_counter.svg delete mode 100644 data/Themes/Application.css delete mode 100644 data/Themes/Display/Display.css rename data/{com.github.subhadeepjasu.ensembles.appdata.xml.in => com.github.ensemblesaw.ensembles.appdata.xml.in} (99%) rename data/{com.github.subhadeepjasu.ensembles.desktop.in => com.github.ensemblesaw.ensembles.desktop.in} (67%) rename data/{com.github.subhadeepjasu.ensembles.kiosk.desktop => com.github.ensemblesaw.ensembles.kiosk.desktop} (76%) delete mode 100644 data/com.github.subhadeepjasu.ensembles.gresource.xml delete mode 100644 data/com.github.subhadeepjasu.ensembles.gschema.xml.in diff --git a/com.github.subhadeepjasu.ensembles.yml b/com.github.ensemblesaw.ensembles.yml similarity index 100% rename from com.github.subhadeepjasu.ensembles.yml rename to com.github.ensemblesaw.ensembles.yml diff --git a/data/Icons/128/com.github.subhadeepjasu.ensembles.svg b/data/Icons/128/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/128/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/128/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/16/com.github.subhadeepjasu.ensembles.svg b/data/Icons/16/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/16/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/16/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/24/com.github.subhadeepjasu.ensembles.svg b/data/Icons/24/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/24/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/24/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/32/com.github.subhadeepjasu.ensembles.svg b/data/Icons/32/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/32/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/32/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/48/com.github.subhadeepjasu.ensembles.svg b/data/Icons/48/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/48/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/48/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/64/com.github.subhadeepjasu.ensembles.svg b/data/Icons/64/com.github.ensemblesaw.ensembles.svg similarity index 100% rename from data/Icons/64/com.github.subhadeepjasu.ensembles.svg rename to data/Icons/64/com.github.ensemblesaw.ensembles.svg diff --git a/data/Icons/symbolic/com.github.subhadeepjasu.ensembles-symbolic.svg b/data/Icons/symbolic/com.github.ensemblesaw.ensembles-symbolic.svg similarity index 100% rename from data/Icons/symbolic/com.github.subhadeepjasu.ensembles-symbolic.svg rename to data/Icons/symbolic/com.github.ensemblesaw.ensembles-symbolic.svg diff --git a/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg b/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg deleted file mode 100644 index b619a954560a6d61324b66bd0c623b31a8d3309d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155871 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
    5c{PR9=xM|zQE3DFq3wy zaf3sqOW=W%zWMb9cb|ivf_Q=AlPIs_>Fu7TCafqOhZ;U6(*OluS?ZiUKU&GWP{7>f zk2_p()&0sb?Ba~w$CxqN6N`gmj3l#0S+!eycGi|dw2_IP=$QMb`=bG%TLrEYhxAiH+7A0MWM>k^f2LgWpW(?JVHkP@c%`%hN%bT|sb{A7es&meQz;iP{SNf6_iK=G5fy=@(SAm$ zx(b)Jy`~*jP=aKfyTEM8X4a)f^7$Tbn|o~(gk+$Ax3D%d+DQ-M$WN-u%zllu5D8%5 zF_uyY<<2}^8D}!xL$@f?ADk+zWm0?nD`9HxJNb$ng|+j@T^s(Hro4Q@#G^I#r&Vqw zAMw`@|Cx@Wm=rzvq$kf;lSujQK%JNSTTKb+zf><77j9PsIkGUcgEq@-sNE{{tK6cm zKlZ@ii`)}rqtDQ|9-kjc$XY$74C=LH)^lAgyorC(;J$q)u}&w5R|g~~DKNUAV&CkQ z2xDW6JiC6FCa9~>=4$8s)p79>W+V$x!uy;W{sLxDWXUIf+4iV&#Rdo_y@Z8;qo2jS zNNDwH8ob$9$$8PT>>~1a>iUDG&t_sd=->u#`NcuOEbeTi-p)j^khXI@u~45avP!4TL4qjKe49+8V=k!0hzKsV=m5iT+lG z5z&H!J9Oup#UvL1a^sGSQ5LNG54kL#bGHE6DR#vibcf#<%-b;4qfRGFvR}LHE*JTC znVE;sTNT@S6uSKLD*|&(F1BJ*@$u@ZvImpG zhYt#i%5-Ibqx6$CoGMXg%=S#H`1C)9zC0cAOEU$00XR- zDm9h&(7OhnuMM%MxVQ8soUQ_jE#MS1n*r4^OOfrs_yu%7OC;3Sf^#dyW`mDVirSCo zJpkPoyLQcBENzo=K1)6772g8h65Iu%VMp#UYD;<%k=DPphdBKfL@(W1nZPZgc$^)jpJN3Uj{ zo~dU4A`r0Ug?8t=Hsz0Yo@MqF7T_0T8cw2uv|WoXmK)G!k9up}O5&nW+&xDFd8w_? z^RV`_rFwOD%lScVqZ1kvvGG=F!N0*kn@Y9Jm7+Bk7<5`3O%8=<%;l}UDZCy)i0@YtbLv=61 zSS6FK4Y?cjW#@4@-w)L-TH20bt{GK$@qhwqcdPc7p8IyxCZAO!V=$suzO}fPt36T3 zZY)iXp4`FMDyD*;FYV)Yy&>72vfgF>DSmfo31T4(`TH_Hn-%)_+&0-qQF9LTN-@8q zVQ7U|IntquYhAMPNeL9$ z%+#yj(RDQ^ZK<#1W6h|a5sgk0@9nWF`;iDQ@al4WNz9Kwt-!q3O;bVb{yt8C{IvGy zX!|#BLPl9|($cn>TC)_Ob8NxqCo&t9S;kA&ZUF4!7t@`Qe4c7xX_4>A@S*}ZIn82g z@5WD^Qc;#GM~6MiLzprbGrt4PLrFJJXt74b)>a}sIsN}AIun1U{|AoGjD}U)+(*pJ zEzEL7n5&Js?<>qzkuxE3j^@7aGjb+Ehb!ltVJVR>xub82kVcO0Z@>RwkI!SDS!P&F>R9vKz!q7CMN(TDaTd8O05o{x7yOraT;cQHJt&TkBgeIEQU}<#{NAnNm0z>7B?>@j~{qcgS(_2IlGuZ0)Ci=Z++a@*CWZfO=*3qowk$78)Qxhh6f9g$KQ*t+0(tX#Kl=|LyP;6O@i#f*CE#y+h3v}M zk&e%Dl62_OVAl!~1n$HabkCG)T(vEz;W2;pagXA^5W<~w{#|%C8pmR2D3|ay_?9mZ z!AQtg{D_p+QTh%k{pS6-3Y(es1K735ATxG>FkuDg)}mkljBgGl##@63B+ULJ5^>w< z1?U6g@3NiJ4F!Xdumz#Thy5gv;!NA!rXH1gy97WEA9W_;C6H4#|G7LH8b>_uqa z0{I(h9&5BaAhFWFsT+w?st#jF$FJGTtEa;)!Q8V4Wy17uS?(a+aUKV(X{#XXCatoWGLYUv zDbz`w;C>!5l7!?|bcO$=4GlAelcD;f2(LTqXgRs-|>Tduj^o>*9> ze>J1^Kfq={pMlngY{g~cZsT^9$9ST4fCcA?0EtuxWVC^8>tNzivL#Ke?@iqw(+sR) zhsN5mlnTWkZs5&vT+{;%lT$+7h9q1zs>)U;17}KPO`fV5qyP2vKcKAd&z~6)Z-HL8 z;xi<#($FPS?abhZx1W&9&7HzFOi&M=iglg-^-*as@6X|Qxa6ptOJQL`np)xcN+!a} z!W5^co}sxcS9VldqrI^$+Ag%4bsJ9=kg|xnlZL~8rU4Z)b&p8v?S9cdTF|;%KLx=v zC2%aX5XSy;Ht2hI|NFdqgxMH{jl(oyxak=5_gSs+QA?s0$LLbxCp~m=o?hT*20eLE z*_HybS5cg;3sdME4Rw=IK8fLCxc`z2tx2h0K4sBbZRt$Ie%#d(&<1}lu{Pecpit#H z44dtq3Z^idiQ&$%QIhgrz`fr;zETMj!xwEMUQzmwu(&3}ko} z+T9@`^3YHng+|%=eoZM}fWK=a^XMpMt9oP|21Zzt69I-W51kJWPxo|Ngc;1b1@E_J zz9F>;4`>yAOgQ9UErYj&5i}H?x4Cd)*i5$NAsFxC_U1q>VCtpv;_Wf54oZl_9y?9l z605{MXU8Jf2)n>3{gXeiTDf=`x(an1&7jUCEg2hm=ZIO&&|8u8yNG$bVMy_s*PDfR zvClae94Bhm8x_Z~+A)XRT{-_Ai-_9WR(bQdU%p&Tb_Hc(_(RA$N1-#>^5-Id9tG-- z@yL)30^S}`({3tVe|u^7QEx$Pbc+d3w(v*D*Gjc@B7;XU&YiXnQ+y%CnjuDV5aR|%szL=*h-&9gH*w+IN{-yzBwOBVzuVFP zuW}&OD@G%mD=JUeVfU({dM?>=OAg?7ReR@G(xY+KVmG}A7oIDcgVobCANW%k8y0*DzbXzacd-9~X(0dk`S=%ghB~De z;ROxU_m`1XB!AxJwZbBry1QNU)5)Hw=E$(8*ARG>W$HT5M#KBB_jKvPy7c0!+=*Gm z-9@@N^OYCD0NicfYSQ+@T4ONJ%iA}IxPKVmw2dt{ta@_3(B)J(E+ie2SH8DE(7RcHXNfXgjgo#<|3*| z(7P#jMyMEUj2#{qea7Re7Hgt1aqudU(8In`0>cBXoanLrM~c2clp$!R2#U>bV;Kw)?qG9B|0|xzQ&_qwPmJ6?ab8n^Gm1x zF8Z(_Sabc+hAvaZXG-;e+tfJ}bjMY-w3l~e$`EeG{9TPs?N0QKU!3zwh#G6U#;k+B zC9bPJFA6Gn{R(4ykmeOX*&B9vYQmGDm-MU#T!2|!3hl$;wO(iMxCNDUB-jg~EqBj% z!k}MSept}vU@lq|P0i#ra1rciIBM7NN4&@K$lQ7ln>_Xsmo>d$x95+Kt$C?QQyc{+ zV3Qx+eUm*X&}t7$Kq)Pu5BOKKWIWZ7f>pF8d1eCKBt5b0@5%&tI!~TJ`x{ok!1495 zndVCY1WvR*`E)(nz%?C5JsUpgkCsaKCN`(y(m|_BfZN~fFX|QIqas|R;ht94%NhOy zR0o8Ks^2WO`MW&?ahiZ=wV=1#Pri!9)ygzA&m}1Jqt!$v(R6$&rvH!WSngHo;_bDGIp4I~Me%pn<`dIxUOHm8?10&D`q7EzH&H2GUFVUu z-ej$D1iW{*8EvbAVtO%4AecB)PLdHFnI1eZj?(wtl1CW8e4hV2W2sSOqm)Y8R+`!A zf2EXG2bi2Wj+n3Z`SH^Sftq;A%O%ICoe>@o=6uZfSQfF z&r|j?wNl>EK@X5~@ai#%Q@Bdg&vryYi|9dTGcF>@F!HPX-_7hwFJDY&)bAiU^}Tra z{fi8X0da{`hY_2x*ut#$5XSA1JrCscqK)G<1{bM39`&4eR|BA>x~Kdm%N`c?qlK2Y zq@-`mk1%B^&5KHhmpjYJREza%)}Y_Q%z-#DGiUv%gCux9vxJ^ThKWh|*F?s<-{8UW zZcYL203B9Ryi2J8bxa%(OXM|rJoh7HUddOd(O67#HDET^rfV3llqCcT@CLdT;oku0 ze_2n>c9uOFn0Y$!&aT*@y|rAOISZFkF;ccn<+yH8!%|Q|)0eFhaPr_aRPVK_dgRZ+ zT})u&Nk4eLKND*zuR9T@c_pNuQ37nvAGnl7xG;jywrxRwrGw#HvBP}EII$C3|6z1n zMiRg}bM0(rT;A+zq9w>tq4Le_!(~xG{wQwD;*sQR&e|v>QEa9?#qKL)-sdv3-l?AO z>{IAUG%pmD8D$vtCQU3kIlR%!$+?H27znb9_a#1R5wNV}lQh>(d>kv9N3Vw^ScAt~ zo*${_kB9Z07@<3$)Uiux}OcFr2>GeZ>|b=nh3E<2KnfoATW`axeZJUVnlxh%jc5ptehSAQ9q z;Rd#S2ZK}&GRTrzdGd~q7)gu;y(kNUypRVsewka`+rGp4xoa%>+-id(UMnV)n0ES` z1_PjYJao)tHLnj!UMzt1nI~W{j@SX5OQAuf!kbV1mCcFkE zu)v$~C0h5O zx0y$%zDsRGEu46?%zgIC7UOF!I;?*(&wDWgs92WNILXk$XPxDaw~4X9)VB*a#(1hy zT0nRW+aT?`LfQM^{DU_wVq1{gm0@wbe9b7Z0*{lD?VoXgxs$fpnX&6QaEv z0_(;h+#qv#OGgCgwQR|Pqvl!S28#>8_F~V-jd$~XMy5b1ANBb)wd4frKgDpw7#usB z5^9YrT>QP5t>U-1Fcb}U)ScT3*jtkxY58zi|#m+K6G?B^V%!DM!3R&;=2JB{AeJ@WO)O;r} zgXBpho16%xK}=ihEr9B27#Zg>2{5A=yA|vBpCLDrfnkJaPk>y8NR}2f%nN({pv*`n z2gZ9N!>?|y-;Q{PZO=CrlV0W}ZKklc>%94Qqguw2fy-;`m3i~>JbEi9S0-kGQ zlFs*iE(<4>!e1Vgx7D#ndB!}QPMJ&lsjycjG2qit`*HnL#Ud7k`i9(84=-Lbng!=f zbclB!NjqjB#25jy3sLQ9M^eaSH0RZ!k)PWAOhDoGxXD|+HSJaLtp6a3_Il^Tq7_hh z&jN$u!2FVKaNcaBz|hCSlRc$8C^V#HZ*OmrY^n_vy1slG$|SF&FLt(j(C6eR0(m}S z*IQJZL3Qq(LohfbKTUqQJu`cJhmv^LQ!;rf{O|e`gw5Nb9?dNf1ILflV3YG@NQ^t> z+Gk;O>UpEb2h$mu)sW^Ud2LR}TugXp2ldw|$V^uE1&8K5X5ph2^e4nHK=Z5{& z*!bs(kTSmjjeUCrVLxW#jA`|hA}-)Y&k`(du=*F zR*+m{l?&x>b>79sWsa3^{Rwa^c@Uq1U1(lYsaHz)^X3gTA{v<0x_NsoApJduWXy?O z@0!s%>1kY|s0pm8NBP1psPlVE z`t|i>0Gy?4;&@4N1%YSTeLJhBF2G{Iz<%fTvgVr+V66V=mm6bc+Wz2s7~LMPW!^fo zW&t{7cZp}6!Q6svrT*-&@0y{zpOABHnbP3 zoTy?Jh1cj@PX6+yFOG*jP@TYgIytG{vBFa_GE(=I^#+g;vvZk3#3IDeq5@rpX;s9bS@FbK55#F3;S#A%}^ka;g>n@sY`C7zl=8Hlc6So-GGDs z+fF|3V7L^@_tTrq=32ndkD!GoE1);vw1OmLRJj0eb`~c_=E~tg$k_CtJcUZT7K#VEBx9oQEiC*z2}|_+sY> z+|Y4M!tvxFI59i6uHv(B5^q6z(|XEF>-ZXipBToZ2Zb}@8hF^7wCu;n$Iou6ekv{pU4-rvrsGKeH94>B)a-YdL(;kM~b&xGC| zm#z9Ny|eU_W?Xk01X)rgvhWWMFW=&7-FJ@$L+{&fIfYkr$}?JK#x9}{)|;d_`Y^F4 zAq5kZuq1DuGJboMn-P+nsG4l$f`)G&5x{euLQtS5T?KMoYctV7w4%sJ- z|0&p4U*n%IX91=!A&!EYZX;X>{ME{L;3r{eXKJfbt}+|t_q-qF4imVuq`>Ew*OiC< z{j3ky{}Sa$O1WPe%sCy$HwHxgiFq)$ceE&r04Dkp=f&1;?H^p!lP5Wf)Ane66c7v@ zc0GI0`l3Hs5-v5SVpJZqEaxa1vit1xLXQZ*>_SIkWfc3DU%IYlWRYXp^YaSbJ1?pIW=G_A0`_C6c+hwGQ-XKIEYQkB$VoF)ZDrs#;e{9m zg8Kb;y@mrc)g!VgCqoC_C3Pw1;19EW<62(KefBbT9< zO&?LD9yDVdJ^Nq9z+Jw7_iQM`7};~yzS%kt#CRl!K&auTw4s_p#cL{G%0CA6$2cfp zRFb#bQ*5qsX?dSEZyk&lI$XeZzOLz!ChHNVG2$`O!{W;vIHnGX<|`u%uYtZ6k>KT( zgNadFE(*_rCM_Q%IFuXrv!^G^+(bs>?%H}S8H^zY@BTh?1QeoX43p-3-|Uh;j)N&C z`D+3PbP?4-`}1e-<|bR*58Vl?kvYFb7A!0aW%@yv68UgdQ6~E+`+48)(YhYKu7R5P z_pj^5SoHW+#hUIh|EYHduY}t+qoRmm{@P|$9m_xV^0QW>7k;L-eBSrC{^G1>VMyP} zg~xY9qo>3=icXy799hDB*$;LdAAeQ;9u@k;b<-O?#r&E?(v ziW)|#x4dWB(Ma%kh`#!+&>kz+z{-ACNmpprLl0pkr;C;k-O#GweX4a=Jj!D;Gy}!` ze&?A$)`RHIJdF^$&Xrd~8Cm2n%Ihp%5qDU|fmMd*XYPzV`anZ+z)hNnqAsJnHJko( zsVEQIT!!!(KTyagKc&5XK%h=n<4*8R{IGBw2TgE2s(3qdfv`kWBTD~KMgB664*uLb zQnvxNOw_%x*y?reS||AfaQO9XN@aj`gs1TP-bG(}{GAc0y>|2T*L3m*OLXm1`!`8L z;g6HqS_iCkU@RnFeGVS0w{8hN}&sdBiR_%ZR^i^*S<9fyoqy_gv_45EoSeVwph0RQ^~Bsc2Iit+>J7NA<SH<#p!ICjsrvSmkS~ zA6};oySr|%;+&5E1N5!bbWdp)Wd!_u{46dj=3=mBK=0?=HE2$u=lAop@kVD39#sQb zw%pojK@~hGx%0=@I`QMj<`9Ze3i}tQ(4C#IF3MAeq`=J6>Qx`D(PRsSZ^&j?s_dEJ9W@!o8N=#Yzod6@DRr6_;xIP1(i*zube7 zNcfq+(=5bt;9?#F0XbUnr+065m@&CuhlSCb+fA&7P!MViBJ`)0vd5s34Jgvn?3vte zmywQnCt3FMOW*HUkOc8bEtIJKZ8wf&>8s0y{a98)5kTZwAnuSqE$t81t7zFO5TJpN zZkK<%tv%?U^?A%}!6GUGV6RnIpIHXzdKs_UD{Uka*btc8}x6T3@C4)bI_xlQRx z&#g)>mY3DpqZwJ9o)4pmiMF`Mwl%1kzh7bleMs&?JaGZLV)sB+o|gqR-n3p)W{S)6 zhR!|rY9p}$5y29|TyOXi)0kxx@USG-G49KvzA^M@KJvyq?^vLJ zMW1=yL2++0{9|A;oI|*?@NoG}M)A`H$&f2kw0dM1V&?Ozc=4~)$+b|T!Zis+A-SRa zCQYY`Aold@L*CJu;=lAG)p3E~cuOn*zpN_!HSZ zjqWl*23cl=?nUIp&@?OK-LR`Wp? zFyEn{87}5_wo(Par8H0V22t(?WlIi+A4We9(3(w@c$|G6)`QmOyq4hWGwi9a9yn70 zV6`6fanc*(&>p)0(kJ@f2zbhh!7~^Z^>U{_iOs;-Y8R)MmtU5Gz{EV6v<_#^0<`k# zB_C^@_WtgBj|9m#P8g-rBFtNd!@Vxm$A$1E@KmAKBIRM99@w{hcm|nk{`@x$gv3?t zUVd_8KOB8ETy(jtrezQiYwxCM@n?Dr_|i48IP(kb>=$U_Ifkwg@n!QVPoj<1^%rk7 z9jqjY4!j?+6%su;e21`K_#msHIFN*7FcJDxYXve9af*%|Q{A?i-RNQFf%zB_YrC!- z^<2$Jl*nO!`!6Y@+hYt%;i`v@CxO(ON3H@Nd%jF@(zBp%pgrGuW za_M6TS6mm576Xmu`xA_$HJ4KZb>S1hHq#RsdXEX|$zoVf+t?eU6W#nyPQx}4L&C4A zU3-TS(l9u5*rAzryir&w4?S-5N3bDzqt?q80nclB6Pp+I_9#RxdA48Mf3B}}!V$VQ z4nKV%$6MytOAOkZ=T~0O=#9QxJmpK@u$4KZ{FQYRaul0-hjQBJc1dhfz1?B$I`@4~ zFR)j}Z#NVO&Huj_^PC-OTQSD&(yS>Sj;vYOpZ0 zIDKF=&j0UXwEiT;+!8?+M2Uy0qnW#k@KY3Y4 z|MaF0-IP}GAXr!_Zbb$RA#xfDuILoM>&7_p(g_r5V)ug5;)l|8yweO-&a- zi+sy_?;eXF@1D>J=g_NsOnE`;r^}pUQuizZ_0PrzIKN8YY)_Qqouq=Y#$!?*E@{~L zkz+EoT?YjXLrpS%#QI4nM?hX`9tLeVhTV5EA^!cw03{oQO z<_{uXV;4z0EO#nPE7$wRF}n7rItpAbf(D(nS9HQNdgcLI+V~6wG||!R=?* z$Eft24n_r2cby*(+mj+akjZ&3VfmfM|MCV(+Fe=nbpGz!el1mO?DLI$yX6eLtFR^I zqhGFO(m0mE^OsBd7TtV9dhTfH&}1lquM?;m;946<`8^3(Qk$3#&72;tZ`I*&@uR@Q#Un z&g=}r&<8h~UVynI5@eOSB+k2%wQ8|St}8qjJZi6owxzE%d`kSelJ)7O*lkqvzi*8^ z08EI~wr!t?w*uFqrT*=uhFl{u02H$<=i9f@y^xt0UVB_nkclF8WzKl4iRqE=3ZX5sM6K0AAM!+Dq7n{?ZYaFZ!6z zI(Vg~&<2X?%M*34C(y=9Dk~Lp@7R24r{L{4bUKzBXS{yA0A)13?h~50t1>KtiUYa9 zP4;e>Kt6L~N3$}|jXo=n&r4k8)Ri|GY>g0DhPQ`JnbTx5;%V zv5lP=SuvjmVAH9$@i?Xywq-$dLDdU88t8DQ*jBIt@wWmUm#V52OVoF_?iRXD6T>Kr zgCG~~9-4KQi5cQK!;Ed(Y5v}+V-*fr+qQGFOXh){PidS+T;Gn?G7K7|#J20De_4kH zN+TC@o6UN4Tyg~PAd@M{w|Y5SNnK_>U2Q?Ey2owVDEW+vBGIF5`E|18dmK6X3U2Fk zjp7LNR_gsIV*9z_3HunqQ*Q3#NSM0>2IXe?@mh#w=77%iLbfX_+lwKiO|~g7-ULUb zsAHvoFeRg_Hu?SHiKG0YPFO~niPOd4;e35iLXhr~=(M9`pNep6F!vw*r4C@MXz9&8 z(8!F9XpU)STBTa4smu3PUo&24%BOf<+8E$fRt0X9VShE$fCMCvDYqmXTFYJu>qG3G z{|zrZ`AXt~`q~I~bryp+b;-u*ah&B_5mrD;Cd1ohQImJk3T!M-M0hCg_RJ<3uX7d< zB5b-2M!c+f%;-)T?#~)ADcwP>f+ab zm;5sAXOTf)=#28qgT&b4a;p4$heIf&LK_RVv;MIdl+igEx%ZUBEbhJKB{8uQuH>n8^c!Z$r$fWKaMab4xS-4n}>emeQ~%lQaE;YDiCe}Drr6d<#E&v8fmp#Mo)XZPL)C>ou#s*-{efmL_Yk65!Q3}W?#I5cFgq)Kp0#86GAI$eM&`<6 zJ6%$dlqVCyqz?HbCjC8luZOcOX+8|i6jpdWVHq}q+496!OM=ypo44Z`OV-!hG=n2j zMHeMK{ljROC2a$ea8g2B?>}qiEW-VIhwF0X{vvmD!8?^xogIHSHeHw!HlH8RR5k<$ zz?7*sd<8{r8L=4?SB%)5U`112+0Y97XI`n-ehw;hCdmC0jOoPIN2K&C2Qa^<_}AGb zCm>-O9Qd$ydEyu9jw^7{f>Rxo$=dz?xVNcx9@Po=5!WmqqhvuhQ8^R7yoX((?xpO) zG@-EG-Bj@>emkC;X@`TO$^I#N)V(tshzC+%3dRkK3oM8JhJ;7kUQ}7&{PEDXU`U|K**<)Lyf-23ehIM-a#g%-(b7{?*zks*<>dhJ)oa z-3e`?Q{*`nkjcz~I=vZwu22VIW~-Qq+G2jngyR&#EQc;`r77Nt<{;R>v=)TPt$&se z?4ptIt6UZHQ9Yq3&gdZuYwmvl#q~@8jx1a*L#0vyK&8X3k_b9eP9@LX3`EE+YnJ3+ zN4wXx!@u9q9AO3H#$^*WCL%u(-nSBcN+?klYH8P0L3Zi8*|<+^#`$dNnoJ{5P2n$2 zDUll2S9JBt%jiDlpXZ^`@|UDF(R<5OxmbAG;pN@G;6@-3|Clb8tb*?Nv)^Gi(-fU! zQTy;>B8=9bJCEobHQ5nK>-&QZ-rf;8=zI6WBduXe^LWhKGv4jV`Ki%J1WW6f%w*~t z?r+PE#Cl&)=y^bbcP@{t)x==bU=M?YcJ>n+C2Y`-6n|izt*^L{T6x&AIAWdPS&+8Q zc=WY(I3`%bJL=W=w3%xjCk0YC6cvF_ine@SMakSqhnFO!wn(Z*Y^HnN1UTV%Yfwe7 z>t5){3~ht-?7^e`i9jitWZRAt+Vv)iQXQeg2ftZKZ^+NSA9!%&obYFQSVVh8cN159 z;jnlO_e?={96M=b<%#@9;wsnJ5!?5k#@TpCp2oe7Uy5Y}oLNlcJDCuoanCOtd^(3- z;nQ3KW(**hj8@oB&Q)Rn)nnvGmt!}21@e4-_;~U+Z~Tpmp7z4}Dq)K9fZ5GViI`wH!^Kb}WR+}RHa7-xNMQW6;pXlKF3j+@7!D%lJ*3H|SwWpOrxR!uHf;nfvrtR=NX{=lOW!?&rM`2_8&q zFdx##7-=q?@G+Q&T5E(BWzJxF$~qJE);rl9gk+a=$?5rh&cUC;HRHHNF|<;i0IuI5 zatnL;_^Oqm8ec?baTb1aHc4FV>o8!lJ|($r)k7JqTt|lGVmBZP(4@)+P1{@-1-8Iu zo4p0o$zMqWB8c`uLENyqdoZ%by&9wPdZ+Awk~G+1oqbT>pJ% zR$mK~m$uoBWC^cS1xe4D1B|{OT;;t=)@7QAk}(;%TJ3%zYavdVN4A!1o?|*jnEA7S zXS})Rt$}G{gS9xoX0*(X?d^uF0Uu@=RGAK59!sUk4Vcs+*W2lT?`oYG3fK)hX=n2to=-d~HFb04E zlN=ry=_{0*Q&?iUVB&ui1-VgJY{I3M>?5iei`EM(R(tC@v9acrBsWfwooo5VaR?naAJ_Mp%f zv6!oy7slEPRS_{4N%}>y&4bqiM-{GFd$7-~bUjW<0JSlQ9Io^p2gcOsvOLN0hEqmp zz{?d0?$zU6Wou8lC6ZfT4yh*7@}XBneV^DA)RF^ZM=8G_?as=PpJAerhSjdeYHlRZ6NDs|op;GA5M(G>dDT!D zrs!|R-UDSO%g7HCynVBWWo@vM0;|^%SNl!rojvI+UG833IBJv8^_dgbnnr2h znRbf~>~&P(b^^036DHZGkJ}{0Lc$d)>p4072OG9VL6op;+or9|`1i2_{a&Tqes^kY zmGNZm^)!85Yd+(W$3o-$a(a_UpMj6u1v6eAN(;pRLWrl)(7esnR@0OTv+(evGzNKd zF|_<{x5iR-bR9;a3;5^e&_1_&bPKHf#%Xw{3s5eWljJKKv8)h3lnK8-okXG9Z{$EN z*^fs)P0x@ao=i19MTZ9(L^d^sYzRI}%xG5DEk>D1iTnJ&`+RZYI1!VE=9=FY1K^Vo^Y0Xi3E_Kjx5lq^G2y!po zDj>$(a++6M{JSq`OI-D26xyYDCp`sA0-blNrUdx`q?d54r{ANS>v`;)ie@TP3e?g) zz$kZ}%fD&|Yl>r|23!Q6^YHU9CHv{u7n-{@FoSZxbTBIEi~bcWRwKg!XVjj^2?mY4DYHx1>-G7~< zkIs)!FOaM{O1mhteksWfzsB3!Jv`=$_j4}cgVRTtGd;Z=emp#E>tZd5ZtaWif3hQW z8W^m?e%1Aq-k8+F3^DtZ-ubIo29<%vPLOa>tAT9;e%NMIzWkQ$b`z?g2bZz?M-XSE zWsndxx?RJ!n!~B>`Kg0SZl2hOJjt!ulu7*eZx5FSYQg$s*O3rv$%zh)>xCJsPw^RY zSuH1jywSCy0F7pFB0#;_PXlEO4bGx8JVJS^7%YsF8GV}L)e z*2ST%@JfEy-?Q{36JbTt{Uf>|F(n1Eequ2}8Qu&2G&=FT;om>$X9vS@yw0Vq$xor% z^pF1jhMn+$T4e$GZv=xpVdc}vAWEVPMnx_vEMg832R5UJ({jtvgJJ`7p>n%x*H;x~ zB~3AH{vOr_vi`NN~{$Ri5adbZZC{0gzX0RO;e!jCj9jlp~!?Fd$mU<6CyI4gs; z+Iyb`@r$JDDbU7Jg|FdDcGtyA{jrv>`&0h|$l3H|DAWt1)AzU4?`WekW`mEZ0`Kw} zhvSIjqE7*$3Q`X2jYB=gq5$m}?Oof!wcqI&$K8ZNx+3@niArKHy7|Y2)D*W-rO#6v;uYihBBL^hGAW_xs48 z!^yt9<7o&y+c|vg_Ek#((16!bI(nqV;j+ojQSQ~a90QNPJJ-E4z7)>n%U)+m6MJvC zZ{)21_K}n{Y9{#P_*9pPKW5myv#HJtH6D*LND%JddahP(G)r{(BD@giP>@eD`>b`X zaHg|kwi3Q7!ec&_eVXBW1pdGe_-K2Y-^0Z(whdAX|$1AuC6Xb135CLQ#A{k}JlBxZH-o~O9Tz3r5zj_+h2 zb{?PSuECJi!#DTry92p+6U~UuAH&yyFsSJ5A)}GxswVk~See%WMiJ-YX;>Hee+Me1hUDKkOiRvl)K72E;6Z92DlETSl41F1fybSv(lkvBfZeP*BhX>e&GovUu6v+JFhH)p7N0yivSO`p|F2dgP+~*NCqm%go#S0@nw{ zKTB0)WZ4i;*VIpcG4pn?Sxc}WG-~C?Rk`X}*VZqu3Ee~i>kD77MU^dHi>SGmc$qeP<9gCWS%be~2V4>7qXJwUcR~Mz+!~5e~o0==P9{&on!#0NDc~kgpY1clgPNF zgK`{VUf=Fv5Eqv8GBF&v|H<9*tCpR^kiF6Ij$C}H49jGDUflzZ(_eU>YGaRAukIBn zFY*$_Og$l^MDK3_X$+`>@A#Y}>NzO-cC>-4<<84BYIar&Mp}2uQB1_5mzVU!#ogUB zGP|~-vM%A>+W2!fg$FZ@@DZH-lSXK?S}pWkyr!b zYVY=3nFKOhJ~wx@vk3rz7XEBMumzWGA>=6;Pmn9(GfPX5q>V$ticeuvjM2h4hAc0& zU3oK;C&`T@Zp$N)jtRj~s4pHzyoyT(JEP^xtNgdO>MdepD=`%w5+$LOc9F`unIb6uf=|7h!ksItCsSr zM344Yswicdt^5?GkKV?BeOG&(7`NZ`1AdH;70)gDZKv{FXUkeWlaKSsA+V=LS8lK^at=s2Wqi@6B$N66k_3p8LoEGVxa)j@ub-9Jta2_i!dD)U)V%%c zZaassnqhzO=^1^-Lchd{eJtked~ID|`r&taq?`Pg@a-wzihPLIIQw=5|ZHAtg_d8SvU!R*!!5?Pa$>dR>;c|BbCdr zK|IkvKAaP~o~^=pwXVBAq6P%?Teb+x`Z-gUH^ZPYJj7pi*EMbo-;!q?B(U;iU3$AF zl5Hwl#%{1(Ab;c7kYf4Aq_THP{hiFy=gW;Y28b`@!WcH56oWOD zN)$^RnbInjqApWD+*iMzx7JW5+OD}!DedEQ}pqy}GQr$_3YiW1^ zvZ*IxMCzZ<%J$UBxr0$slCX@)<2SM3x*TvofV@yEr6diSt5aK8#jZJ-R9MJ-H|h#4 zYD;utAlU74^F*M0PQlolA7^E*{x*Rc=jY1fz&NFKjM?eiUqI}iwW{^Mw9&gYE^?D| z%X{O@{l$f)54`?}WFZXyUbYga!dSG@3rlx<5Rc{YmtHKr{e?>l^U#C^tT!F8i$2nG zN#7fRW<>KkMwLdDu)q*{*0|&C&bNWz`0^XYLl3r=g>OHpBwk)FBjSE8>MC!Y`>(WA zQ+$8!ZH>Uy_z5%_qTRtKy%z>W)l1@YsY0xMqH&FLRN8tm3(Cp+?`gQILSu)wIv6Qh zoY*`~rE(OYA1OLNR%eh$+~X9%&@8y?RvQu-7*tRL1tR|}Qm=Hby0CbLFG-N!WK}-- zbaOhcYi^l7Gsq{xY)d~DeA`MfWr9g;{*R)o3~RD&!`m1!L}VMWDH3Chltx0D(W65^ zlpYEyj1Z9S(cO)xfCvHxor3`qq9~$BjZl#oyh!7>@7MnBd5+_L?(2-}JYz0)-&({b zLS=c!&W?X)B5f;>p4S5AWn9D(`KpEuhmm2lDYUbn80mhr-K6?^BsuA$h(nx78kM(9 zOD0oFRE@Pe@W#ptLR1s#C%Mo2xShc-p^P~B>*F6#mM${K- zS$DVKMtrCX)6fwUC;JO|+YJt6FouzT+fUWhKg=hx2$lqcFJzS8CRh@tW|LC)dBcOJ zD#pw-ISaG80|qmt#I-#Z&JPAZ#I}DB81A4UB4GUE*#69bki!?m#cJk@VvnnyJb073 z17=`zi8r;*rVdy^gw4dvAFT(Oz+6Fz4@y_Y^cu?yMU$&^6sYP~C)x7NNZ2*sTQg;i z$s#$>c;&tN+}pmS47|=M3u9{VH{b)q{sDh?n%Ku}0MaPhZl;a<-zhT8mCt9k^I9<$ zPsI+bAL(qw0LtE@aoGBv&^%@jWdbiEjqb)zd_=gRq6D&3)jefAA~Z;xZY*B9(fSN% zfY4p0*cbN2trTfd&XX8U!jWrFSI~IV^ecmxm)P8E<(#jooVB@?JK-7lUi;Rs?!5;J z-{iN(1g!UPL)cO_SCQoBONy3YX>gT{G%r`u0?ZDAlSg@rnJ~7#A7M5^eK06>_2>z0 z!*P5dsv$R;UaVNy@!3zi2}Rr_vmEOyXA;u=wljZZYPlEA9Vsu00^S-(dnx;-V!cy3 zVVW9|cyHQPRHvLd&fdVs^Fnu>Tq;Bn7NQ!oai3e-160*D#JYPBt(Sz+cbmB3O4ms! zs^do0^}X)Nu3M#Fc)r0c4&{sypN%diyqgrjJS~ha$?}?LZ5=lE zLk@Q@q)M>S%+QrmkBd)#=+U!iYW;P>ag~>n6Bm{%t&2)GRxwt*>m0lPii@4u%bR-MjlOU~|%;%mM@83)$jt1P5G< z1&`{k(vYgO3fy9~!szi#4bxl+5;$+S$?gX-mv zEK%fr+i%OEz;doWm@ET~Q)J*wyBp}2`#MkF0v_?EUn>I$%#6E@J6DhyCh}Xm5iu@S zrC@m8VYWzX_Jh^8_-=tG$;o$7pY_J1pR8=>Fgn|5J^i^5u!3y}5TKJ9Yl>E;hW;Xr zL$vJu%*=^}g~f_2-(nx6cHd|aqSwR&LFZ~s!xl-#ABfbeM<=mf013CICqn{M8LH0^ z03EMl0OimwMBV$Sjq}fG36A+1s{X zW|-E{!QyZ@-X9ZY{P!KL*MlOq1*^ZZiBp!2-OE(j=w-$RwBdz~e%yOtZKtvQgJF^9hO64|yO`0(5>s5fRk-VlO-414(;*uw2zl6fA!n@Lv-y88g)sz{ZP?$(dK zA$5?nvc}H>Gx-PLWj!@zQB48v2EtEwq1GZ&qiUQ18w&yt)N+Gw5YuX=U#)7v)OO~e zwJ-03#K9>0s%a!G?2%K&u3SLJ)$&T`ng8z$@Q{nz@v@BE#BQv&ZU9x^7s!{`sjYVQ z51^tiFNgqjs6E^)jf|`0bozDfHTgjlZT@pG=ClV{nC$#ZeDc@6gH_+ncN*GAkA?mI z9GRwQR5B^s{>9u_jSPhI+nnG(fX`YmcmW66UROW#zwIXzLv?#jUC)xvn#B4ak!hS8 zIP0zu+~4X!(z3yoHlNm`vu-Q|bnuz-w}<^t{$_gi$OzC?1X|8}blRD9AyuM^Lc0e# z{bf9Wc)#P|6|lyVv^rzSzy*hTP7DD$(`Ba~3M~|;Pr`1H|4gEzIfT8i$BhRLkvBB% zUnz%N_I|a5Hqg%jnSMz%QS5itTJX6<;7Zyx)0AWSkgR7KT^_Wo`zZQallVF6AK+^g zR!<9VX4ZT<{T#?YLVyC0&)ML6sx=dtPQNALxySsa4e- zAx(2k3eU>JWBVZX>4Ymjb0;(WulVJ%oO||6Ltl@{!gwBr=AAcj39@NRgU#0^22C`G zkI7>P`}^Ivq#U5EF|ETwVL=Y$HGtvWI>7A$7hph1pM1viPBRGbK1-;J?Wqtu0@YCE zB6hGkDSn?*R7&v6St%q9msLRJ>zcGZ4W>Xw(Vn6#0kqZ2Ih0{w%0GbWG362)1C!Ct z?R`fFLX{}!A7JzMy`u~?`({|j47D4G;rG#f$aAp%YY`2JBwk%dY{b6O-!0nn{t>Vq zsgP0_{k(Q>-c^5s<>M_m+P1@i`2dR}np8A)ULtM#!N7B*Yi_-JJ#`oTDje|-0H<)X zJD`gl6EY4@vZDp%S%*_-R&eg!myzs4UK4(Gofh&JvPz8`&qF3*T~jPpm^XVnJ4TB` zhDB%P$f+kzY^Agk5xy<NuR*hRIVQSn$y|3?sMqE z54x($ps|Agbb`gEsVp!!`=>+M)|%IpMU+H5Zv3PqLWrAF*L*@c_2E^TQK4?s$vHD^ zbHkk86wzw`^jA&Mmlup)ZtR#;)#3r@jD@dZQ(XE%!Z(9IL$>6U2v5nxBZu=-@1&2{ zC(^qG0XbKM2P-UbB0lFF{r?GKBWZq z$;y_`#gR0`Q^6{BEjr~7JZwnK-$&EdIaWVO_KT!$yf~XDqFB7^{S1l@6+eeDod|EH zqQ3ESC~$o<@AA=bbF+?4s8<};6L7D*XApVb!_}r~tfkYewQO5N4ZAgB&IVF`&-jZ< zx~CxuJA5w-46}35%8%wKl=fTZFYRRGcdB-vFP>~`FIWUPTkWvCoh{g3&nZcXR!~rS zNU>k+wE`PHa#A=tE;Dao!)jHkyOpOc@f&jRU9@9)@$AjYGDCI6{U5KlRkxG?(M-e9 zZ*d324=(dyCSsnZ^L)8))8#aN)Q7(`(e9<^-mr+kSfOCq*!d)VhDJtvIDr~Am#C^y zD5Rq%fg>G+@`DV40hk8LWU5LG7|GVj-?!KloFZNw&7YYP@W4~zk#BAe9A+(;1UcwaVP>;pr6-{2WY26;6%6B*O>c_j(vk!o)<0(iF^!IFhxlDN0*8S&3P(?I%qsZG+TvQ0K`18mEvG`Qs5a3odVq-_-Q1inWjJIo?ON)GYuFN$~sdt>97S9W!lMg3U# z3Uz4W>hyy3AXt;8`)npCqGW3q$6#}OBRq)nH+8E{Pc;%PE{VAv6uI1SxX-|@FG_hg z;k=}gSAkls_+8g`Fg9!%$YEEEu?&}NK!E@VZ*}!n&`W^Cf92l)zaAC%9-6HC%~;Ox zeXN2)mc5@XzZ~g90~Qna=@#}?s+=#R75RFELNKu`G2s`lP^m-EOwWw@3;WrJtMouS zww~PT-@zPFY*!$WJ2?LtQ@;BC*;X#5l29ul_V#9h`uffw7Xrx%n+$6A()kE58M?2AnB=hwYklmVJ=0OBN&xC@{TdVV|gdH@V37#nm^uiX} zB`QO|?6UVp#tJ@o6Vcun$`QF@`IK?(qJqGvIW!|t`hz&z7RwATI2-+7^4EF;Vw4H< z4{&gxtd!~EL^7?c9iJH)B9LN(10Iy8w?u;IAa1zcOD3jAgD`%OYyxe-^GJ1jB^rB2 z;~#+Tung9(kXU~<6Fd}rBTJ@FGrQ(*aH$Y-h!%sZX6(Qbk;d}n6$3*$?ZWBusmS4D z!7jTt#vHB`%dJ{C&#V&V%cyfMOB(6249fq;zYr)yuv4 zNgO}HQ620u&vt@~JnzU03j9WFZy&An!frd!ey1Mv3f_G$=V23fR5D1=l^by;a(4(3 zo-_cMP*4Hs+Wf6z-@*teR(EibGpL}h@Cno6`vD^EJXYy)DKRS=zh6e?s~k}9~Gt>zrHP)NP?YuC(i?+i)F&!=cCneTP^Hr| zAI1LA?w<8uq)ZuU6jSDYIO^Sy3~a7N(CL(S;toAh;L+svuaP=Urb~Y*_P^f+7<1&g zaE3aZJEp;$KWvr9pX2`SvY#4w$W6@l{Dma4=`ey9me1RmqFL(8dzwc1+2$G*yJ1m`ig~o^-Fbt;jH@%Y+{)7K0a; z-$7LBZjJHa(DK!NT1{}ZXQ8h8<98#R)sflEGf)3chZ3gbIMz_hPq%pwQix1XjVEtU z`mGf$tpO8jX4w=SP046cNgBLv4%ca;b*?7-otY+pd}9#B>1!@0Gk|#BNDk?%yykmD z0AYhGakS@PTMspm8g0nOb**-;XN*25$CMn_oT^Ct{I0zFq2+XC8N``pa5pZT_eXsS zKu4ap-gHQMpn@qy$j*@Xsnu@=psQtKosLlXRCU-0i7PZIqp)9x6Yj6&)#*(gtRF6+ z=qy{PC&{#SAu|AzNP5rru?y07dj(OW`=PkV82B$v$4`;mUj;;^i}5NEfqiIPoUIGK zCyc6rZelu44@y@7fQ_Z4JsJy-14lR?U3O>`T*Irc!}`}AV3a2(H|1Gi&M0jbh5Qam zOa_G6<8sOYwCd2wTu>{fty(Q&n<1gaNnQ$GRGJLlLHN+$?4Nk|wy90Ypo)mr;oWsW zwhN`+%YIur`-ZxwQV+6^KW^RmB6E8u$FR0O_v}DbkLA^-G;;TXY+xayijxg9%vz)1 z+uxH#uvTPW!e)(RVLXvORqbb(TjrnKD3o=psr==VvKB$MVJPZv@Yc0HG82YtR^%dZ<9Dn1 zwPD$zD9=fTYhY{KIABhSf;AOe7oNboA6_YzBN?n`!OD*hn^1&|cjM z_i{r1$ud2WlMKA!K&kT#!m;79;zGX+H6N~4pktV%J}*tWEtDDRWL7gl3lEDAbIEjW zQHHY8i_X-oXY@d0n{RLO{r=Pa6+NK;v`RuS>#^7Zx2Q0<&8Kji;(XbOh(PtdhU0~1 z1bj(aq%zT=&ZZeid~;k)GE;g~R-kMjyII~vS#U1Qw8sNXe|=HczC)S3o}rKG{h4XW zVDt32-vZ6gxmD1vR(Z<|0pOR-3Ih~i7Xtg3Q8;1@FwdZ_-ZgPab_e-buaSPopA*%4 zu}kA;iUYx&0fGTq6@6cQca0(187-?_%2D)m&}VGKGfZgiiQgQDO4ch;rqWmb`|I4u z0a17N*aH)4J~v#x$(Xb_^!$q~BkGpe_4JyyqP%cLc;lk847e@KpiEHiqqcA{A~f*3 zNY&(Br(Xs(m9)*TbBW0?h1CK_4Db46MG{p_;z`1GF!43}Lu0pOM=d3^|?6USAo> zQWMh?+^IG&N{8;1>Cx9Qxr)oS?gS{9pDq)&0-ZLzTtZ-<$*^Geb)Vl zpb6O(!k;?^P0li5~dEd!F%DdDXw%$1_v zwuK`FgO3VOg0a{0;cW+M=(XM`EY3&{k6Cl>iPCw+q|G+uFdpvRk{OG7-|qY!*+%0T z?rOotbQ={H4n`~>xO(vI&!=QR6$RhBnbtyo3!fx;ncKuSo#1w7;a5myyhlgNU?TDP zMORuyc+%+Crs8Yo5$o4f<6`hG`yWl0XGOsopdOlBwwIX*GDeq6xRD!nY~ipB@_*Ya z`zoPB8n1Ix_YeL0^IWpjy2C>zp$645R(EJ!sXwSbnorKv!yYVyQ*->UT3tNFw`w#= ziMGX1O~eY#hMC4fXnpD2C8&)1ndOOlX)^X7TaQd51_lA{(FxVpBUrX1<74A8WiO6U z)ShHUie~9eyErP0_%KY;-6#tC?WdA$jT(6&e^RC_k5hkbx_fP>MjBfY`TWbJ6Y_x>qw<`7;=RVyLY0#RMcQy3t<5OQR@fTwr zZMz#;@?d0T*JR`7YJH5HuGLwD3D{O!SGjy4l%B<$BWPxujQKeLh(K<%(#lnkn6F|r z@M(_;*GPT{{;%HT`Xq6&`0m)?__|{w8Vy&BmsqwvKPmwxtRL{K$76HQgo3_u${r~b zeeKG|@~O`ebC6Ky@$ziLfT`c5jegyJp^Mcok?IpyV8cb4xe+1DNgB<3`8zD8Orx5G z_n0hctIn<&b-7XL&kP(Fm8;M%tc)Lyhoo<(F}Qfy7tq427uffjkwrvuBVNvwlc~k9`5~-JKc74cAp$L z_W_L-mZnq^Y0l#N5qd85xvl!?#jF?P&j)B7ediMN{>zAm!E&ik+x<1~5L&Gx zWH|0Y^`DuCE?i{{)r6(;x%Cv`oQjk?$@L4=k>UP>_6_nOLCgR5;^U3eA1X4}nJQy$ z9GtJDF-%WMEmH|+yBborZrY|Vvnm?O-0JK$DCmhzQzAZMNv**iT-vAA`IU!h%`>unzfm)1Mmg{4nIf~$D+=8`|!k>6fdvAtPR9MQ3e7w6tvZx)@12B+A7h!L5;HnN@F>RUnJEW;?e z)D6?(GAZMD7qi~jAJqC0&D?@$R8Q@GzZZ-z?E{H4JpNc@vBH+^`UpS;Kyy5(L;!iZ6&6BncldZj8Iv~K*^KpLff14|!$B^N5odCIaB(2-c zU698+*d6v7J32Vg>x>X8PRuYv-A{};Czmu2U2^GW-2HD9iV6Zu+@< zgRZeXA9day^nS+(MgpFhn(P(oCUy6xROgq_8nfSb>lf2k0T^hyhk^-!je#42;5~EPz(SZHc#cxQ_7$e51IDsIhrTQ^NrvB0{ z(dF>>wb?mu!!aM%_1HhjJI7_TUoSXDaM0-_7nei1rcHuXEh?jJHTfC?Wvw=1O_Yc?l5{$2{oyeEiC(FOpc#F6F6^uDDVoz^;+3A-dPq!hHk5 z&TjB$$42-Q5w>fX$2B`|R6xDjDis@zC_S}){2wHV2v5vzRR4RZ1ISj=lYc9#-a-PJ zr3|T$r7i>)aYh+>mS{(m_%wqxqxyZ=C=myzpI;BV=>X9C zBrRmMQ>(%0i>`s+YAw-YZXPuH_Q0)B^<9IQ6OEMn<2oTUg9P3~YkCBQiltFUSY)gU z{HeCJEm=&949*bq@N_O7jG@Kg1D|fn;c2HChy^Wc=Roc{+kMHxVEx}i_3Mvzh}9sX z$Iy7r5i7(xMrO=>CL77ar2~M&hA?-!zMvRWGG8ag2g@~mKq5vy8uQ&Cw5-oXve+bJKKncp+KX*zEMgD}_t1q;1&UI##d zjqN)gSK0KAB}OHdaijpxyO(|(ksPi(j}`G*%^E}aQdd$RB@4>_mDxQSvG?bgNcRN9 zk5t`9+pX4CO!1MLxC$p(jB!j1-jv#NMJ}h*tjvYl^N?o-oMw_xnXc7yMZjj%C#Y>v zC;6JNfoKe}v0hyvbe2uaLV^Itbth~`bI?f&-TSY4K6KZ=PhSelK6$vu?eAVW-sW8s z9un-I1TBzMJgV8I<>1S?UqRVFr_w@m(ya6MPE8kG?dp696<8E1|w=RlERLt@wZR`!e zg_vd%!)SMFoq5^hV`3;qm2;=wVk)gc!h2X!P)gXPzDVq(v)Tv16jy?FIoKvUl%UOa zIphl__d<&dIK-`kQXaj74!#C3ISXy?Ool>qo(O6tOzO>}^kOk_i53SODG%Kzf|WBa zTnkKq)BbTcR|ZHNbwj>WI^BW50OGg!tt+rP_9w~NnFX@b6xKw0F_2iC0R;Nmy6xe(E2%TIi)JPwGj1qduzuPV3sqa$~7`2$nGS1 z9^sLd32RtXpe2`vH}wJxr**U(d#ERsl2Nj15rJhgMz8|aE%h)eT!629dwYB5m6rWk zui@buzZ(aVI%BseSFLP#a9Do20()^)S{{COR#*lydIg(aB_9>9@;!3aT&Hv^u_O(H zym?$YW)Ohfx}?W6DLy*l*o2|co}+03J6om}K17Qa z6kmT)Y$0%+b$Ag8XG_?-QtC~H@@o=&OP_D%4jpLU6C7#0BRR^JBq5jR@;1zmU-M~C z;+diu+Id-d=lC$FFcXwbSJiazAZQWe{OSgQfshk@9xN(rvlK1s{bV*{rT0;;*y|cH zwe1B3%|rf`z828H#^7mzNVwCv&Yi~BX{l~nP(p??qPVrje=9@;Q6RvA7l*m;-XD!Z zrQQ}!(T4|+4X*dHpB_@L2J*q)X5d=)PAJ@kPgp9@{h|9bLm$e$;HDJi{FjjYFc4-C z@0hOE^=25QG1v!HS2!BfqpQ3|OffO(Sia`@h@129I7Mqnj0+psML+S(GhAl&z&t@Yf= zzM`j_>E9GbXkH@8S6&aFU=I2DxS+|`E(Mk=FE9CJw3&94k+~y@{AhjtJluBHFhc*W z)MqDk?rdhw(1Ieta9-UuLz|irgqlLOxCuy!zZ+L=e9|(wD_{<{x96We^&sZ?MB-P8 ze6y!so@jJ0gKF{QNbNFFSfX6!G4<1tp;#`jFYwl(^p)W3`^s-8NA^{$^*5*){XxCln|v^g2-kHTA;?l| z1c(at66ShRCNY8qN=_p25X0y4Cbv$h&iCXho3^TVo)8>T2jgsCa~%bq`aP=}w0Zt{ z6hX)_B;-A(Gm#MEvR`Bd5V2^y{K1qB3iQ!{UuNz2h5GYoKHZ=CwiE)(e&J4~$Yp*B zSFm$6^N=D)PqU0Yb6suR#|IJ(OUYDd9fIHwr**SsTb}cTyU6z@0kT?oqkT56nSvf; z`{}r*9A{s!S~HNupTUu>jT=dy|2#!c|5)9-oRp|lfp~;<+(oy|j?`KVqxa7=LsNt} zHgAs^!td0VwrLp+%YVl?EdF(`_;fed5NC3?btT%E-%YQ}%*NzZ34@k2Bx6_o;`(=} z<_kNqjJ)?dWWQlqbT7RCf95gSK^SSBl_?>1L2&2b=ZNFEq9< zB}LOgJxk<^ZVo-kiHl-Sy5~BRw^HSi)n|~%jCMP3IaIs=5cK>kF_in^U~x60@?K&f zgTwI)B{o3>vqS(oU2|vm%JmVAM!j}VyB|BTW*2<>FpGyH+c_i-pjR`5?(d5@CPR<} zgSXh4nroIJh;BCji{lm_tGNCc^X_+97Ww7YubJ7%LO}9Az)UpY0WCDmT_|MU#}B6n zAa{Mvd1}cmo}@{TnBP{gymfbsMx$)#blpa{G4$inNq49BTO#|kuq+G#Ckx^hsYUth zaUPpx5C~AlZQ5ufC`lj|n5j|4;5xi)!Je!*A;l7S>!`;jm~z=S86kGZGMq5rOrI?}NrN1KUUaZ6<&PS& zr1QGIPIT*kI9hsw=|w?YN*UFpo^~N{ie7uJ@4UU$=3mA3Ouu*VVQ1+iZ4}iLfT@{ev771$b}1>tx?JvN{hX9v*>RI8KEQ(mLT#y(d4 zV<9$E!NJT7oQx4H6OU*=0>1Q*kEO(}fYqVi#Z= zt7k#002uN*i)q)%ab#5SQ-^0&5B}OMFje%URai!iZ08i?gC^=GphEr$3d=3;*P<(* zJ%9QAdG} zARPKEB2ax@KtwCD#4(w)5&0#`yDKF5#4Dbol296~z97WUoQS`iywOu0_@2~DGPv3o zQJW^MZwHQgC%~9u=UZ}5(@Ep4L(x3tkOKT;7wi8I(3477yatyX4r$u>9mM|j=g28YGec)txz2zONf8l9!&gcMg$X6G+ zI|)I`-2G0oyv_Z``k$=^j9Q*r*1GDVC!ISOLJn^TDq`KU8#E3*E;G>)CSuA_+rOVt z(p7}~loqI`JL1IF5w%XQ!=;*gxqReIM>1^Ijw8sypF$x`0(F|2@#h^`3qLh9QnYk= zBUVEiuo?&|^r0L#HWtwoo3%YN_Ly=7q@Qtcuyf{1zhvLXswS{QoiLYy&iRUS234l5ModRj^}-U-|N6|YH< znGz!`G&=A{vNB=3%}uG`-Bet(dgELeVU_8gvHFCo+QCq7)pXvDjW?~NhV6;ygSV8c z8{NIh?4*El4DX5JawKQ|BAGUD2Y~_k{Bu9|4jg=3@GF(S<}4eI%zywse8H25``IdJ z&eq(5_JzYgnMxaWX8U6c$DJAWzfeV}1;K7z#0O?nCsti7~iWYDnZJkq% zAQIA{>)ci;NsI2~3*`V1tJ;gpg%yT$Ph`2+c%{c?86F~d=kgD86QbV1ZiRQ% z9?D5G=Uv!VV7obJ%I_!a_26J9V#Q5V<2`gw$~$F|-$^=)=GMvDjr)KPK$~{IL8PIv z8OUf-)45(Zn-xoIZ@x~UFtQIC28+Y% zN;@^0QErpRG(}xbBQpw-_xF74TiY@g?fimJa(WuPN~-In^ezmf-p#_LMKuj1qmQ#Q zQfl-YqgYJ+sICPx`;*z}5LI27@`_zk>8o^4O5jj(q??P-?UGc0w0gN%cN5Q+)}P!q zFEZr^EE;Oy%6t3#aJ&%A*Xum5t|Dx$-+WDcJ$OFU6m6^_;Vc<&J-D$}_m$MsS$AmC ztiTVyI---Er>j-2-d-P3tGIUKxx)PQ9Yhl+KAQLX*fKJS zdG17N-FcAJ2g5_P7hM)X?!V~~DX));w;nBEZpBvAxKv%P=WRk6Vl=eqrKb~#36V{s z=s%M06-}xd1>|0cXa2r&OeJA`T6BY!xX@ zcJcIOpZ#fCd9x(ly)5^^&+AKRiW)ffS7=MMCOID_nF-xz+%w^G-A6JavRwD*ibvFx zca$JSUp41Ny?F!3fLNJiFw5(IfTkIATmb}^@)>&j(YA_P96g8@RG3a|!(|qTqSC?Z zNUlASBBp@7_|teusu5P0{voQp57S5}iL?eYQYl#c{eWRX_bj%M>qoz0-mEs8<-{MT zogb()ANmK%(48ISCZaPV7f^p*Ps&-rlJCgV_F3-<|)-1jPm-5tiR zg7*VVk)lZ3ssB2XH+?RYKm~qFfA7c_VwNk;8gh~gCVx?6#T)7i*N^IV&kir&?d{U# zX8GG)7z7qf`G!KFGrwRPxoujB<`$ zt00UgaNEI7`-@ZUrstv~{I`jIj)3AHD$VxE7%ZuXHuHOVJXb6vsQZfjuX|ZZSjp&! z6#muM!^6+J8XuZdboq{mH=h01Ujwnp|Ae@okTHE5ghI}T+&?9_qL>|s?E$bKG^|w{ z6`8^>_{myfa}f;gtH9QpGRT};&ilx-F_=mB~in6Fu2ZP?a|Q+ z+uSST0ptgVahvC{T007N56kwc(}WebMXOA6V=o;&SvLACzib-54~E(0L@7OPEd*}#u1;$n-kxo!sw6=|7i z(t34W?eTS>m*Zx-f7RMx@$_PkJQTtTmZO+d>VJ-?cOQ0CM$774LCexY??x+1zI&TD z9t|0S+AhkicHHw;iOjO9^HdEZJCa<1%DKWVdOvx8Xi6*vN3)EMxexX-V4uCRkqC4>+{j?=&3GU{^K;+! zg|b;(7?7LEEKie;*06K=lqXLCH4Oon^-N}JPnZ37w&O_n9T|@vq0kPVw~KP)W&R6( zB%lpTiX%oh_E@dKl}bs~WMa-so>)^=S0RSQ8x5_!q$(7zxB?|y&;@%pkJ=MtusX<> z+Xt)n*_*YSPh!uThO8Dn;I*DwiPWKcXe4VRG>Ia?2F7cA-wLEX2e&}HIs5cH9@RNR z&zYRsQB4dz9pvWp({e%7?h*GlGLrf~T!>3(>|t3z0_#Q~GA1^j%v%MOEf8q;8qdKq zk4fg1W`1JbezEUNRN%16)m*FN5gTRo;Et;!d zp|AVmvp^o?xo%@3JwyIQ_tc>cuWl!_>OIz%q(R;pfC**;+;ul^Vts~QQ@o-nPt|3; zf%OeKQy$67vGPNu0-_PKK`u{m`OJ6?@J#Fz!d@Uv4$Xhje(oP&VBu0GeKzBCX`t=O zjFy(ZhxGodfkMS1Y&FL@@4~HRu=uO=`cU)2G%6COQ z7$0#@sp|~K4d8EW_wQ+IFer=S*C^|xkPgObEN(bI?O8vhuoE{e+h%(4-c}a%)1#DcCxlp=+k;-aKAPPX=UJP(6jPof=Q@S1kWT! zb#xeZn8Q8`o7rw&?X^(j{YqwF(pnj>KA0)|&4<461iX2COqJ(O0l5(k29BNPZUO<3 zy6gzIq`#LJKm(At{|*l#NRyz&Tr{QbOofn8WJzlW(fJ49G2WFIX?&nqH!ndWH=|vh z#Ni*q{|s8=awO^QyrUhl;!2oFzuHQoa@rb@zW&`lygFYm{^H&Lg&YblF~>hv&ZyL^)$1XCvwQW^86G3 zsCJRTXZZ5d+GPNX_^Sc&n5`~70S1Tx=dgAStjkkzMNq(USGeVN7414lHfJ}2go7By~u)Mw!4DMg=i++Wb}8v2%n)K=m)0m21yE>I^LpVuJO6 z_fzkG0Nq5UO9`vTX@-N=b-<&H)3C%Q;ik(R)+WgZ;8l;*{FXd}mVJGA+htmstQaU|+c zga%#!gEMaDlad!)AdqqK^}lIay3lw+*82QAVi`;1gEhLB?X-R&vtU{M$f7q%TnEA3 z2pe`>-9-jRd5e-OY`AIXIacphZR~XzRFgNgJ{a8s35OpUT6TZa@-u2H| zj7Q>cP9Zv-8boRsXrV@Etb2Ez`|@BGO0dnhfwO^;O^@z zBJ6L~X!5@|QL1R*+ne~7t-F&DZ6lb(IB!$yBJS-+shRb&Np>A+COks^r|PLAAYR)_ z2ADY>5%N?H`-<5N_r^1*U0?C{9a|2$f|17bG{p!MOGrsiXri9&tLl=5m*OYwize{f z#fhz`lj)HW7>qqLg;rv7x)J$}=_y-SES{Kfb71naTW4&E!=#C$aQKGC9ZV z&0lgbtHZEIm-(Hpch=Pl-s_rh-j0otwD?iH{@mX!^2w( z+#$w@PV$zbc(J_``S{nviM1yh;LpxC&W2ha{P`2H%dOgFiqy!u2q|}q;E+wz(r{0@ zA3#|C2iRSzVhc>EEIjzni9^c?Dndo7shCQGZxx#J*V0^0H%EsIZ04!I$VoI~YA#7l zGNAMvo+{xybkjhfB?X^>e#oDDEcQd?0gCP8f_bp&=`ywe5*KzzZO~3ee_F_g|0FX+ z;uDQZ=0%d~h?5M3X$3Z2Au(r6Iqbx|*zCrUM%e*yoQy`yQi>_*VbUvkNq*Oi?eE)@ z80|tuh)ejuxr)FQ=zo`q4~2Nnc9?DX`9@5+I4Iou2#d$X3mfVl5GPMi4SufFKU02iOmX>C<;3>PZSYifBbH&H1uL~7d%T`3S~C#- zy1RJfIh#lY!yo?YdbBf!;T@BANaP31%K(HNx_!%*1%}GbiU+FKo|n z6GIsA$Fr2~U3>bqx62Bguy*(;kWRG7; zhn(%b@T&Mp{09h}Z-v!je${nQ5yxq4I%u}>Y?^GjzleH*Un}Q5h!f2~v5w@Q2ZcOO zOzH=Can(DnN3#7GRp3!GIB2-E!YD&?SU)4A;c}uhk|hV=CmU!6wi{cQklc!+m9MLibSKYDGblW?xSd@^Oi@pa_V`cc>dQ?k}nY}$DvoELvP zR=S3CcD9VCyN4lwt#sBpCIc>XW6-a9bxzNYz#~fqv6<7Y`C+D^h4e1MMqQJ^&8$SdAJ@5%KoEe5aGN!QFpd6aZFei}4(eSWF^Z)#o@#F@VntzJJA~NY2~X zo?WI~$b+OjE3!2Uzttx=(F`0@(PDcv^yfSJQLu1_$1e9b-Xz6|%b)2d!i5x`S`kIt zcQ9X8v{mpn3?w_nTmSARykcxw=9x;v?8^}wLff~&H}^s33tk_qQy<5-+E^N%*85U# z7Ky3dy>fBRiQ#>4%)Byhe%4LrO@Z1-j2cq?Q%h3)o?+Ti2A~rIe?X3-x43(SXLsj| z2MugY--WagGkhIAvabg`Oo4OZKa>ZU$(?RSbTFdBXQk|V|~}Jec(cRVoSFYL|P!M zK`$f3iAX#5K8_Fp-JzH;Z zQIUarNht+rg=BrUconx+apVB8=a!xqRxye_NV`i4`W7<$ZYY@4Z_Q)AaoMhXJs}l~ zOm^Ex$L={70V>3#8tj(N!iOgFzLFWni6&aEKIkrr9TwFOFD!$+zvf4#O&)1b*hEl> zm-D9gWBkiNge0Uh5`EGCV`P~uVl?_N=wR!;DmumJU)A5C;S+AzS~jpXRzD)qB{Iqc zd!F-Pa*#UDu));pX zzP1#~(P|;drVo4W_oVk;V0`|0tWF(i*7k6-ACugM#%>)=g|H%76hH9s*L=XKeJ8>l zjQmi9X-r>m%Y-U5CNI-#b=Cr?syLX1ZYrv!WF}2Z|}<^nk=JVRuOjc z`&m|gQo1lvUh6)6meXXE&6`Mke^28|a>js%J?eh|(ak&FKI7nwu%M+fpwsoxcZL|B zxN(ffoor_L+h@S7oSbA7pK`)wf`7wsM5_DECCRH}|CZpO=T#uwN6PCM#@`_cgOz=a z_DytkGwbVUhxYV_O=60|d zxW_O?j_c$Ql6a2o2=5lyyp7|kH-IvS zbnay+s_1#V;irGIC*R5j-b@{T-5#E)agrRn)utT2J2pEgAmMvW-!r2lKfhtdoG}+t z@k$cU@rm)3hp;NRP2`}X&|je2*Lj{Hvpt-lG0s6bsoY6e&H1pU3|OJ&^R}Y-|BOG$ zXLX1%hqRq;DEASF--}M-1V`ERm_*bv%ZF7J6L>zRcNur8y?CvX3%Z*%X&Pg>N1z~) z(uKZrO-=81{X`uL!WofqwUibpRmVNctFAUZ@YBJl2k(VyG+khKkj=;+P%|TR5VB((Kge#ll9w(@|4ME9+3^(h_7< zT*BsC-2CCPw8uGQqWgMK29tyr{2PdqMv<1PaJ$tV^YFU}01C(vX7n^SBRey>`ye-8 z)|O};Gv*I^It9;aE#%|0!iQKyZUzkNG%Z9#q=toG4r9!GyFsQxc|&FU^f^|Ndv%aP zc!n-q6vdU19#^_SRR0KAyLHxV!N}c-T^^$MIKqv~^+q{$F>ku8jH8H%mYpV1og zE_~!X{&jzh;miq65nRa{OKG$OR}fmMy>MDqg{)DGGwpcQ!!jQ$A78(;Tr}zJpU$EZ zZ4xS7gMk}&DcbKpy1K4pgiw3%_o+0^|(>N3VoFv9z*rafVgpC+caf&T?-#SH#YUCv`h*6 z>zTonuh|us@yf{a!*>0<#Xgz?ols`KA6jWdw zC_CWU!B}rag;eH!#$qlBUcxfdr4ILTJ)JR$tP7(C>T#&{c*q^Nj8jebNDZYz1`A&( zScnch&Jt&`uPxQpjP16Du}gQTEy_nL?SM@sG`=77fXw@zn7tf1{uC*TCtK()`UDvE z*uDj8*V5@@4I(fPH>c#i%v}O9{uR5R)v4pg?(-(T}n)7R!@{ zB4g(vL!I$wo9h|O@`rY+{f zC}P1wM(c0*Z*RPjV~ByL?_&GtH^PO!tCi!?NiB_tGy@_rQM0to+_%uKioKisu^jz4 zcs3!&eH7W#BF*PH+z&?RB+8ibE&Rhl5^@NCn}-4yUkjo+AP@CI>nA_847qcxCbJ_N zebAln>Hs-r9yZSnHibZZqijA85%eIdt2>I@o`k3K4)@jddzQ7yZvTBH2_^2zDkgPp`S!GN8HMrMt6Q_HX^lbf22Mw07``^LQyV23$cf zNtg|-Zxkl+wD|5Xc4uoiS~7EvX=J4vyxG1}_2yjf(_b&vv+(c3#M?tpe~RT0-dZsI z{{3*?75csvMGj235i^e2*PQTL~f-2r%t~d9kWMqJd6$1i?O*zlzcwS)i z=g977H1l913`bq6b+2}-&l}A6O?ZIDT*7?%ITaZul|6}e{!Ue9g?z$7neeqg6$5`o zm0hYen4Pum{JEhFLe#xCxuk8$1^~-_xpsJBm|+ai1Lgoz|FD*ZFY(vV%)4CLCC{p1 zP(;6L#OtXaufKX!VSJ#Hr>7zz=j*PROxgUq7s<{FQYkpX;e8vXMjOmtT0hxbua4-G z5y2bXPQxiV{3v5?6Lf0F72k#J&mlROt{MHE@28*dcrBXG1T7fy2^WTGq`$#3vw^t=_EpN=gqI=j`mjr5g%2iGR(8wu^2VCuUdtZ9kD&ta5Oc zO3Z}kKyO&6v)b08!eSRNzQh`QPGNp^HoF@n3G$6cL!CJUYTpz0o;Lk`< zNnk#=(M0F3uEu)2l)!ZfoXX@OMT!|0fPvNS48OwChZFqr6RhY(t4IYnOVtY!Pl7DT zIDaTkX@&#-T^ZVP{ma|Up4;5ZZe3=!0m9B{IMF+k&MzB2<}Qh|6eN8_J(S#|z$BD9 zMK$BXhMp79CigxONOu=7ukk(t*qg?46q`o0C@*yKvRG_L98aDIgVWcoawb{Hntbdx zZN>ZOChMnP&DBcE@ziFEjA$L{xMsT!&k-lfbvy7Qb}l8e+g zGP0haz+AZ9L$`4a8@3Jenf_=K)Aj4%nRs?^Es+w{-=Ev4=VulU={gCPRWS5q%&(hz z?Z&U&` z@tB!fuGcjjl`*XK|6Q`iG0aP$_nX@k#xzNuk;8APHx5me=M*2CjLV*!OuPO17@|Kk z`0K@G)M|!cyj10q)!}KrgK3DhMpF}I)rwQ*iTZq;vk^<{&|`zHHP)e5ql48-j1Y+w zlJ%FQy{7NAcO{W|@GN};#+Zg@6bR8^a2i542+)OFHKr%3lsO5VVq4Pm{{a3O9GDpd z&&QYzB<@w!Wbx4Yk}CzO|626=KS$c%Rm_-KBKzj+;@u2qUQwx@E-l8hOJN7ll{_&~ zZ$emEi%pJBXU19moyHh(!VW4j`K>tKo_5?Q!*}WFQ0p&}a&;M~mSnsWW3xYmQ|NCJ zjSY?H)sXq}n&%;71~pA%WPNjild!m0@8ukjXuuJ00G^2%Hx0_Q5bPPl;QDarhpcJB0Q(!JWOA z%^@H|=E|G7+@FA-qP%5>vaCB}rPC%haymZ)L}>gc%gf6|PtX;rL+{R*$0!~reM!4x zD1`Hpj(h&@I-BcTJD5njNRLHlOt3Lia+2e1^NXw7U+chb*#q$(K85!qOo6GHkZ)Fk z*~B+H&gE6~#R_#u>Tbr_^)?Rk+tQUAWO|VU!$|m=Qt0DC7sM!8ou?_@4{WCA|KoZX z$PV6k`q#Khm-Bane5re*13!mcfr4SvNVL^!J=vlLPO(&yj9-9f(sBCVt*gL-$rY$bqx97Ow~;>d<-`2EW(|00gcWE)#8 z*e~vm@bcav8`g}xR4vm4G#kj(#Lx$lz~U+?8mF0vl>Xmt=J_?Zd_awe3k;8cZP4Dl zQ?zcMqwQ@z$N8&34wVY?6j;0>+9utT_Zl}7kPBsJE4&j;_xd5F#9e-ykpX2(0`tF_ z{z=cxV%8V+5s90(SGdAGmh7O2G2=!r$IIxq#qE(kuj8hUPj2;&C2HUKF| zhHn-w6SF(2brjD1TmtZmoqyDQ>s#^GHKbs}2j&D|;@q$&G2q#K6AAF_LR9*$EV;Rg z@9m@G31^mvNcM8ntX5HFE)p8xE9zN!noa9>yfE~(Hgs-p!ty`tja;Mrb#A_XFPM#3 zl<>x3nQs;l_yi4DhZsCI8GYRGf!pp_xsT%#nbWhj)bMPV#~4_J{2s4do{0wl`;qAv z$zF#Y5z^jBR@8g`X*pwV3OJPetVy zX9u$VNA6DU(oZoVY|Phl|9!?r^!0pON^Q7Ep>1pEpl|A9e3g1pX+1!R8M8HS(ZLf)g|TT}(@=-bq70VjqDIVXl`j_-y4^&K+;<)rZqg0D>*U&VcYky`*)|{N z_7CJF3^q9nCgDY@m=5(9Y&CI19*#z}qtOSY=8x>bcyR-6q1doj1I?Rb?CZy!!i{WR zkO^?!qKqfkHNJ@zmV!IPM@l8-G%padX{7AQ$m7XTCRXO!B2s?hIyzpZsv0~nX$3Z< zxM~2f`c=CXIl?6q8PHqXcBcuhKUZ0vEYT#D6oJp(|zZ)^ftsk?nkU{%X_l;lW#Rpg3e@p=0wzPH2cWM?Z4qkQz{AUg;u+vM{!n0x2AtZWv&nJ zsNf51E_@x24xeKMlLkIY{@Wht=Sc#ph(|Gw3y-{fh|uZ!Qp+-d)%wp+QD0`Dq$m%w z*MK94wWI9SASQ&2$zeks;1dc#V2t4%*non$Fob7gxqr@lqKnVqa-tV!9_@2mJvz4*xM^$AbM(R#!3fEqT?i4bFg~m zF%k4!NvXaHcf`s1>FR%OtdQKt`p{$DG|%Kbme*OWm0wOmJQ9++PwgCA&nm2N*;BE5 zr`;)igXTW5+M&+OEgET9Phs`tmLve^ZTP-3Li}9FZMEa_kP#kCF$pwZ9L^cdh4$6c z{&TcH=C6x?7-N>1&+=h%02UR6HS_Ma5KBn&(zi61MCWSUy%y=R(sjCp2YJ4n;Ryj) zAtz)E3zr^j=K!Fh{!_0Z+B?&Lx9S|5ewyN4)KntuMu@o(E&S93ssNPpgzmYZmjEDt zf__yt{6*7#+Fd@5{l5|PjY5KGd?7b9^K@!zC-qLrr)A&uzm14iPGCv#BVm`0);}q} z?2>a18G1+q%y*AD*R{y2!(6~YG`nUTY!zw5@9nq6waXytcriVD2-IkD-R`_z`kz@4 zm;ILApkTvT-dmQrx4jy+=K&2oynB{bb5ill%8pZKOBB{8Oq}Z9(w&52C2|;HRGsRx zw~eAzlgp;%>QDYf`g0^mvh68n?j~o03?%+Btt{^DNZGYK!}L}wp16uj+`=dyRx8Dg zK*rhQ8sd5#zeC{I;)9XB8M0pgwQp9jFZcyRI(TJ6Yy&p5j|W&-#LR|b887ITpcJz2 z$TjyUK_%gN7Js>`LR1HJ+Oy)4;m8&(o**?wQfRQ)dMgGnmU~)&JNsyl{Ak=hzWDIn zK7&)D_;|Rj=?`@P!Rh!x%VIWyl=Ka-+_}FY4}8abQ$pta+>->EQR{pD^Gnpm7D%43 zyQZeay3_JSH}*-fV#*Sa#3<<+@00Z}G=(pPKosw}T^AY!l8U{-ijB;y@QGT!B#`3l z^iRh1r;d)_x7?GthbZ4z&!1`+$}OUKR%P?1_O-n%7J?m3l>x4<+FcoPh^e*m9-6kM z1|Ugauz!xMw))6R|Ay=o%F^v^q7`Rd}b;kP(FLCl4daDsZ}@~O)sl8mg<*) zpB$g0y0rQP9v+RAbVvAsn2f?o?V=~hOu2@&-#%BPH?l3%QcxrrkJN(Ji?Js%!N80;o%0M}o#6RR=gOHI7o00Wr5Ba7|l?D}1g@G}*L*1<1 z3#3;nJBRuErW2tNrpfDW@pG;$Lmlr^hP6Bbh2}DxpMpBYg}7TUQ8tK>yb7$@hj#QK zPLLb?`xU65YV2JMuEJA1vq(ydL(Cb+9|At#S{>LS6{g%DpXDISk=63N3G#47QPF?r zsC=P2NxC)IID5!T4Z2Uhn8lZpqf_?Ikn7fjbkevh>|jTfwFt54ox59HKB!Opm@)(A zPIfIC2k5x7?Pmt zpd6zMo1@CL(fVpB?yRzE-Vbfd3wH->+&z5Yw(KXzM3v`29UmQ^YqJ#n=Z<7m5d-k* zgzu(2$-EzGw!mLX8)3f=Y&#(gb1r>RWX8|J4>U$zPj06gqrgCLF1$bDF9m7!itW({ zhjK3qXSc69ZB;?1??$+O^8n?i7*vz``Cf z98?oUQ_arpxX1j6{&rd==kX=$dibW~Rsu^Bel~0H$ls?E$)sQCAwYZ(DZHN7pWJ7H zWj+0}E6F8}{2IRgfdOJveEu4_{?EUNhGeq2#C<1X0J~7UY*zIR0jR6U5&R#(kdNJK zveAa?&eFq5<+`?-x1&S8^Sy#7s_Xy|Z8KZwxs_ju!TZpa-3E76R1xtx;yQ&-)}quD zcX&nGxeCXJ)k{Zrs>HZq$!$VYTJ_P)`PR?^Uu54gj+CP+qExFW4!`Gr1IgUgpiM%^HVH2{7dxz0L~u38)MyFErdsk-!w2- zqsMwSqB|1)2CAGo{7D`aGVEJGzQPCxDAze?Pud5oO|MJ1X5-E=!j7|f(Xvhm!ogTE zL(!VQgTjn$*8ge%EdJDLs(~lspVhR~-XqH2pMxUJ6u4l)$Gc9C(rY-H+5fxUGRvqb zpTPRK5qe%qFNN_=gpNYe5#SRTUu$gyUdrhf(05Upn+)eo;zUHfixjn?S$W_LHSp6>X!J9-o8IBFC;zT92o%0xTd^ApDd7@IZ%F6+M)ZBv z_WJzl6V-EX?^`V?&iH(o`O&`e3pL=Dr}NlA@o&s&a4LuMa~BQCKtgrIbCdWl!r##J zt(2;~ft+O6W=qYVWf5jkkDeD_mgabJ_{DFL;D?e24WphCiU5&zyP`H%K)55+Oqmzt z?j0xiqz;>Fym#(~D^UuhBjVT@xMAH7&8@;@%iQ}KV1}J9VItHjf;!z8jv2Y3mm(kz zQq+goE?VAoW?hbpF~2e!RmBT_DrIgR(s&}dW4pI8;sSaS>cjt^drzO_$9)VJWG}SU ziJ&Cn=<%zLuONh}%btgekx0cBi%j#O-&tMMEAGvB(I&64Q>WoXB;Tub&9lK_P7WjO zrby?huOqDF3SX;_%t0<4s_m=#iB`gKAdOI#qyR@c`q;)9Qw!I>ja4}dTrZSrcE23( z>EgSn)hkSY72g;2oR|qFzDa*&ASf^u7?0qu5e0>JmZMf^?CINg76|)%Etkx#<1&-+NwUX=#kXH7 zz+}9`fX_SO<8c-)hpQ5dAB8f9XPAt$xHX zgbv|TT<^0La1EAGq=@ugn=)ZlkUeJl4X-%x_Dx&Db%L;L~@KF&$o+w3!~kY<8?Py5gu8 zEkO0l?P)n)+`<>mh`u~1KH8i5@)vu!7rAW0PrNXmrZ7nxnuC7G|Es-!x{5M6lH-x+ zEniQqCI;lcJoAhbgb-PjpS*uk{&~#}0st`tmS{s}Hjx}|$gjQo>wMn;hq}yAa&%mi zoJ5MF`^zXQ{_!l*K9-T(`b`lTG61#vuKZl#_cpL*ur&`>C53?r8B zKX!a&B26Gn!4tLa%UJa_i)%Y34$-X)OY&SNJ#X*#p`PknbZ_;nbx{Gv-bvQ~Uue%5 zOd;yS)qb_n(pvxm62kj`DS&eFfnH^X_hj zsk@lOHLOqgc5DPG-hiVbtm#W)qNteLRVr%#wt?ycDK#&z+8Q4|;Spw}?j2G{@fmD@ zZkfOue{lRalYxj8MsaWpcZnLGLI#lEn%+Rf7)ZpI`o=>gWEog_1jN3WtKTa zKaO)k_qX4MCZW@9P6b=B@7)pSHr5Z93qMQh$+Y8}KGPJrzVPP)CV5@oeB#y%>gw68 zRim;%0&!d9lb%RvVxbptVNG~R2I*|fEnPYp>lrrm>Q>6{?StJ3a)6EZ+4`B6s2h?= zn2$j`b1_iAay1lp7&`7wB-MWF5gN}oz>s*GjV<(a<#HSf#%;?F}SOI42S(V@{gAl9ev?<2-QN8KE+ z>O(}Nb@UosB&>IbtB~T!T6P`VOH2HqY$-G*Q#hRGZAg+tn_|ot&EZ8J_DsbaEXz7=_ zX?F|BXR0D?T*}vCdZ)trD~$YPbqZ5}f3*-*cq1WFh{^BCGs7gE=Ev~}8ZLQ`2ZBtp z_DafVd&0G(U{ZHmY~Smb7$XyJgiuIuSG6Qq_eig-JjA8c(I5|_N#d8-zs}`eRzrqItX9FBPkoVhSgp(EX&O z3!Y4z86~{+W$b+>e&yN(|HViyh%vzi@e;R=ntwi!G-SMnR`ooIc+X3^KJ{__xb(yj zfc(ndu#g|nwL^!mB5OrH{y6F?(`#nCVqg5Y^ee%UHxXIMQLA+7>K-`CX(d*S*86h& z14R(Zf?2%0z~IzbyK{+fLjt+V?Zz%xA*3@&OJ^1$Al7sQ;%i|?=881GY+XFJLSksq zOLk{64N_rWQws5AqYd7F1)h$c)K|V73A&OX0?+eQJ{G}UScY21Mw{ZgXLEj;-uq?t zF!Pk=#$=SGD<~WkHU>&69-zh4$9TRSdU{y-YuN!lWiUL?M>e-COMjfE;Z&Jqd7BMb585o~n56hi**)LNq zZ9usgG}+PcMt&*^mwMnQL4qj!hxnu{$7zYmbXK<4w&M6Xw}>(w@z-Cya@Rhm-*yz~Q$`wr3DNv9ZcL;*oP6qJ_c9x* zi7jL(bV*`jh=t|yi@m52ezD3o!Ixd9(Zlzj$~7-!i~jTV#=*sIb^THWyibrnw?wIv z#KXCYT<7;i#)PegZi6eOMl2@(Y^5esA6Z#U9{A4EP3`a}4|1pZwRYFHF}GZ)bfNO7C<=ds9R>U6 z_+eoHv&}ixjGq_IJop-dP&+D=HV# zK6JKu+M$%opbA9-;5u&YsHU4e9b-l8Tvts;HpYhDPk3e@oT?aOnsZJJZ5Zgj&}-~X zXSDUwzAT-qjw6NpZ>igG9b}Nr?y<8o+okOIj#%Znu|CpQBd!?ja2sKK$rXIuxh?t# zheD!u=PwIE4w;HX|HqW>pn~@gCQx(h|4J&xg>O+&jw?C86>H=OnJR}{S#0MWm;%B4nU_Z{O~}4DzlB-~XZ`^V1m1f^ zA^h`rJ^BptuK@nLHGHL!Ga687v_5#8!3-nKG>OVTq5T-S27P3{%-DYqSJyo}NQB~l zlwPZQmQg(L=O-~kYv4h!+~HhP%m_CxU?xZX^z1<9YGEkV$<{oV1QDlXQ;tvk^s4|M$RPiw3G+C()%`#Y;&L}vcp9m>uUouxb;`8@*t zD(d9WkO6xf?zp12;XT+{?z$drucTwSsy)BZ-Y=>yhEw912EN;JhV>OH|0EoYI15P1 z>Uqnap1-FGd3A%mU4=ridH-1kT-C%wIZo_BvSOZ}>v(kAkRt76J7R;n2mY2$f#|sv zv2`4jtJoJ{oTP(|4XxlkG82G7{u_2a8c}6(LQuo^TGY@~b6%$A>vct+B}~sqvX_t; z*o5rgDAcf&L(62k9wXNp8)4urRHYWcSHqxGh&S^T2=2%2QA$_RH`TiLwxWltj6v>b zd8=~G2cm+jJ|+3(9UY}OuLQOPk;3yqSt6sBPgcrlP`Z4V#YW! zK`hqBRHcK(>$2Ypo&QDZ7UwNYpp>{M(W5z%u~d=DEwP#Y`7Fg@nc>x(m^Gh>@#`gaIO za!F=E10bPE^9gG1XN;qdVfHt0amj>i3kPH*p2Gq-Nn7;W~e?bLv8>v2O(%T zV$gKhzL)@haQ3CgZBPzRu`7X#rmEc3$G>5d(a$`94-S|ad%aWq({8`>e7k7kbpq=? zU-|muoFJ<4g?3aqze;VQ__eHi;{T#4Jl6O(Ox&UGXx>H3SxL|0Q!(mS;-V8O9vJ@4|ZJ^I-_M0-VPVQ`F7&q0uPROsj*4^F_HjSL(t{dm!28zXiv-DR!iAco#NBXJWr z{xJM)q-yFjSqTgB@e&zd@|@%K!b3tiIiwV2k8t$38fv#Uz(W*W7=1l^CYjI%QhKjT z(w^42f>Q2G_#Ytibgd8D@Uu4WqOx0HG6JpZme=}&=gc!f00_kJEL?TWyyv#e{vVde z=#m>cCeGp@r=aXS-N6PZJ(SDO~@f`BP zeEfkz+|s}j2Ov5~_{9|#L=l^N(2iMI8AlSJ!ZN`}K5pK}1(0^L*#QmT7ieb~d7gIn z+sL|7cB+I1ddzQDkEMx$S%#++hZJQT(F?rvVg8#k53#oPcC}UV$zHmlf<_zmF&~5Q zY!FKF?7CL8Aq;q%Eqx})bPr0_Fs>$IWwbS;=8%M^K6xmPYvu^n4fv$)vq^CN?p5`EyD}wDu-Ij)W?XTAc>;>mZM)I=`2zlO6J##L{Y{HA z9x!BWUabA^st38jc5-}H+_8-=__#pUq)#o~-oAvuCOv&`u6Ck>WAoQ}>REm4 zNyUZAN+SU>s~IOQ1o@nARTp+s3$bK<>~{$fZ^gW}Rj0rWvexJxrLuP&<%7i>E%piU!0g3Gu82C)!g(~*bWnVY8(=?erK6QwgeJoHb#&Dhvg;wveBlV z(s?*OT&Ybqr(SoyG3M=*%qKEr$mikDbZP&XD3+Ae_bC2BetlZ6pdUw#!r9WFZLF%p z(BAf5hWZ2Mr}yn+do=`_y*)O=WqY;H30bqH7|5$IT2h)cDw(6FXh)KJMtbfNRf->9 z{LC;L{l@GzIk`=reEW!uSxnjZ`$+|Kl+A{xfxV5NK1uCBV2Zm zcWEhus`}Fp3+vxfQdORhDkA~^7VFek4qkO2g>&~c_{LZ-7F~7MI!L<$_-HXVk~xYg zoT|^`<~O+Y?;{T6hkTGtKXZi<&BoW5GQA_W?U8Sdbx$f!!)HtG-@7Y>!RBg@Fmo{g zB|nPP%dQ~U)1UcI-i*_VgvtSnUW8J8+w;KOvB3sA!;0TmjHIqBy}CB?!L2YU}>e0c* z9C&;@slo3IH;3RVGDNqbw}>J@w!ftElV#{DGo~TEs)FOKzlW<8Q19-zvc1nE0uui< zz-viyK8I8re)Q62#}Mla-8E&@fV6If^}oZDf6t92LBJUAOYYkqs8gVS z-sN6OL|F$)>wM6H(&O@|TsL;ROgs6^Ej;lY^ESi_g(*GR2{DttJpT}W#W_#J4Kw_9 zK6XiH2b5cI_H6TE54Y%x=;2CV*JyooJn3nsMcm~BBQXFz?c&lpuCF3KA+>Z~yQd>9 z9&cYH<&%0Gfygt8l2o1iNYhgJr}WvtSq$9%=-d*U_yi2#M(|uGKzRVMuCfP(O8^%( zruQ`y3zUq5Br8ZEf*N=c;bz;1t*%$!ifm77xxvZx=Opl$ify&LyDP>@eX;vY8d$3D z@#k|S19GH?=0eqboy6Un%$k*6M8t*m!3NM08bkgERc$HSiVf{c(>-gdkY|D&(9puK zXE=>fe7uKxFHJ?mQLrLS$BtuDqbwp3nV&scG-h|~Y>b@&gnu8wO^BZZb+q2t-%1}$ z+Z4X&I_yQe{`i7~BqQF@>RW0D9fTe3ZynZ(a!TVu6)*1pUS9l)!5D7+2@M0dU9?jS z4_XfC1tA|gjCIx30==9k1`vTrzqcjjDSVCC>bg>~$jnAD$qJYSEXpKaWU0o>n_q+ zHtYtmj9K@4GN0o2M=t}qR#z;&$hMu=X3#b&**`?%F`Mj;1L;OL;bjWX{z~ASa>ts= zWOZaMb10-4NmAIr0PLR8FHf$6vNGm7-Y{zo*Zot6AvU%_1!-69!Vb^G3w;VS%8y7sH^gP0#8oPd)r*~+lZjVlb^4<6vV3@j`b3mZ zDuA!}Ctc|hUJh>pI!Jr0Ew^(weVj?OBuSf%Og~@qBsjPJk&v(^N1iB#doIt+o$Rt^ zkTM`Pd04i%)~Rp@k)^lDV5<&C7=h$IgKM=v&uEeQ5OPvk-F6%FLQyFm@#dcAwd2l* z+{s}6gc|UaHqYekU_DV;IkvzFE==vsonSMCzN?>4@`X%r;_1;vw|pF<_U4$3xwyP- zN%XIQ$|FPmD3&$FLm#PXy{w-%l_BcG+8WRc5ZR%^ALJc3Rkoiw|KA3te4kmx7}B=$ zXD^az(NOGMQ0y6z+{%QYJTQQuA09+r$VT|DVs;-URveh*^(FdG2BI8}^AI)6-sPo} zE~7}QEblo$(kN$YPY(k7nq!ElVv%};9y0Z6RpzgoH8><$VOpK`XUYjwQ4wa=#Ot*$ zqIUa`OrBs<@KkOZ3fH;HxJbMN)JFYseUhYLCkaRxpNu_xc7+4!C&{&!rW8Sy_R`76 z#(IpF5a?ra$ zoNQaEEsa=hRovyp$?csSt|pM`-WxPFX}kPo_7E*KejmH?FUx#X^ycJ(Ph8QPehx3) zlyeGeO}yXpavTf1!$bG)Z+GAojd;Rp17y`|;8HhpxF#*^V!I_d@R(;jKPL~03JxW{ z0#@ll>m3aWYLMiFTEqJXXAy8+J4bee-gHG-vs=V-Z&8|RjyI+M@RouThvSlW)V@Xy zQi`NhSW|L4$oZ~#jg?}fjQ(g;o>^FCu9#y(FaCQL@EPBn z-!kbrboSfU+Kn0L5x7s!z!oxt5zz?-)>uP+5lC{2&AA%WCH{~?kq(Q{U+YL$L4d8{iSD ze156N#_<}tI`uTRIfN%wie#}kv$t8; zwh@(RPU~uq<~g4#kV)BeB+^(r+@C1r#NtjuBCez|D8ms4oy)Zli75eCCGWvfs!Sd; z?Z+p^L2t>O8b4+gk(wSA$9g^kAxhb(1NpwG7q9-3hS*JyZ7c_`8H^g1eBrdlOm}Fny zk2om*Y56_@`JYQ%{c3u4Nvl*_TKeJP{2hFP?WBhoh3F=k+IAi871$6rRyqI;PcluL zTR$k1z2Yybqpo~UORUF)H4_mNGe@FIC+ZN{wRx60mmv9gZXuV_;{M)(7a~LE-;Xj! zq!dHEFJ6s{p*z;O{Seol{<)RZkkoN*Y-aZj>s_@L=kEDy*HTH9^xqUu~r3r|7_=8eloJXOufNl>1vGg(ILx!aLcPsIW z!dTfP=B!805(P@ya{2#~)u$IO$oNoB_vpL`EK>VXgW>MAEEAT?t}VYhWWa-k_3r3n zXCH`}M2tk`yrTw7b2GlAlN2WWf=3T!681W+{Lv%NCohKL1eOy3*6zs%5;$u0cWOPT zLPWcD4yWbSpdSoVOaFF^w=$kLuW&d%Qx+YwKF?u;E}z*T_~^#_x!?Cxjv0|MkO@99 zd_uz~=Qn8j9M4TO@)9i{-r23wmIQtWLX__{x~9L4c*+i9U&CD|=MJ|1BqA!5ZRQj% zc@?YyB&qMrcDxOS4gNn`!#A1(LB2ea-1iNBjrWDSB<|9(q-|}=5r6jo1`I_JCB&i>l!pUA$FdmQ5lDIPU z=IR6|I8ZBGJpz2oAT|^lSHdE3gH18sx2Y{O1L-*XeLDhGKEm}@@m=oWJ+Y%zPNazD z!@*rqK};3NJ&Sv*dkaRxBSqBQONF8%zq`qY%Ts83t7FD?(q6sMV0d`NJqlqj+BgN^ z+$nT)a=22$g${^qTH>!{k)6os72aa(YM#Fk6$b-G0Im-(rCVd8cBVyt&Z5j^gS|=k z>A=eexjDfOmxAkukA72_M?G}8^^(k~ZuQsc)#*#-%4{Py{c+@K;|eC|0K3?wtsyc` zA{3(wCq}FPS@C+J?htJYT;I%K_5jYO0K?nX9E-|Sp88bP6*V|}-%{$oLUI#lc2k?( z`JxKAYv}!}x_+lm5}bv}TReW7+PPvZOAYwt8EJU9%=V0J`6=le*ZI3I@NO68zOAhP H@5}!I^zQnZ diff --git a/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg b/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg deleted file mode 100644 index 915cb5810564babebc9023731540dafe8d8edc27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213759 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

    The currently installed version. - The currently installed version of Ensembles, updated only after the user launched the app. This is used to know when to trigger the Release Dialog. - - - - - -1 - The saved x-position of the window. - The saved x-position of the window. - - - -1 - The saved y-position of the window. - The saved y-position of the window. - - - 800 - The saved width of the window. - The saved width of the window. - - - 400 - The saved height of the window. - The saved height of the window. - - - false - Window maximized - If window should be maximized - - - "Default" - Display Unit Theme - - - - - '' - Enstl style path of the last used style - - - - - false - Automatically trigger a fill-in when changing style variation - - - "split-long" - Style chord detection mode - - - diff --git a/data/meson.build b/data/meson.build index 9c3b9188..0b54efbd 100644 --- a/data/meson.build +++ b/data/meson.build @@ -59,19 +59,6 @@ i18n.merge_file ( install_dir: join_paths (get_option ('datadir'), 'metainfo') ) -# Install Settings schema -schemas_conf = configuration_data() -schemas_conf.set('SCHEMA_ID', application_id) -schemas_conf.set('SCHEMA_PATH', schema_path) -schemas_conf.set('GETTEXT_PACKAGE', gettext_package) - -configure_file( - input: meson.project_name() + '.gschema.xml.in', - output: application_id + '.gschema.xml', - configuration: schemas_conf, - install_dir: join_paths(datadir, 'glib-2.0', 'schemas') -) - # Install documents install_subdir ( 'Docs', diff --git a/meson.build b/meson.build index 7a836ccd..f1ec8bd5 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ # Project name, programming language and version project ( - 'com.github.subhadeepjasu.ensembles', + 'com.github.ensemblesaw.ensembles', 'c', 'vala', version: '0.1.0', meson_version: '>=0.57.0', @@ -33,17 +33,20 @@ add_project_arguments ( language: 'vala' ) -# Compiling resources -asresources = gnome.compile_resources ( - 'as-resources', - 'data/' + meson.project_name () + '.gresource.xml', - source_dir: 'data', - c_name: 'as' -) - build_dir = meson.current_build_dir() message(build_dir.split('/')[-1]) +# Set up the profile +profile = get_option('profile') +if profile == 'development' + application_id = meson.project_name() + 'Devel' + schema_path = '/com/github/ensemblesaw/ensemblesDevel/' +else + application_id = meson.project_name() + schema_path = '/com/github/ensemblesaw/ensembles/' +endif +gettext_package = application_id + # Listing dependencies dependencies = [ dependency ('glib-2.0'), @@ -51,35 +54,23 @@ dependencies = [ dependency ('libvinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), dependency ('ens-enstl-0', fallback: ['enstl', 'enstl_dep']), dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep']), - dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep']), + dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep'], + default_options: ['profile=' + profile]), dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']) ] -# Set up the profile -profile = get_option('profile') -if profile == 'development' - application_id = meson.project_name() + 'Devel' - schema_path = '/com/github/subhadeepjasu/ensemblesDevel/' -else - application_id = meson.project_name() - schema_path = '/com/github/subhadeepjasu/ensembles/' -endif -gettext_package = application_id - +datadir = get_option ('datadir') +subdir ('data') +subdir ('po') subdir ('src') # Define executable executable ( meson.project_name (), - asresources, sources, config_header, dependencies: dependencies, install: true ) -datadir = get_option ('datadir') -subdir ('data') -subdir ('po') - meson.add_install_script ('meson/post_install.py') diff --git a/meson/post_install.py b/meson/post_install.py index bf02d96a..aaa4826d 100644 --- a/meson/post_install.py +++ b/meson/post_install.py @@ -4,14 +4,11 @@ import subprocess prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local') -schemadir = path.join(environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') datadir = path.join(prefix, 'share') desktop_database_dir = path.join(datadir, 'applications') if not environ.get('DESTDIR'): - print('Compiling gsettings schemas…') - subprocess.call(['glib-compile-schemas', schemadir]) print('Updating desktop database…') subprocess.call(['update-desktop-database', '-q', desktop_database_dir]) print('Updating icon cache…') - subprocess.call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')]) \ No newline at end of file + subprocess.call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')]) diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 891fa7b6..1e4dfa24 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 891fa7b67b3a5d42798c30f2c30fdafb39d254ca +Subproject commit 1e4dfa240308aa31f17a3b13206abccd3e684145 From 56708094319684f624879d8479115f79cc745393 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 17 Jul 2023 15:47:33 +0530 Subject: [PATCH 19/37] LINT --- subprojects/ens-shell-gtk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 1e4dfa24..f999afeb 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 1e4dfa240308aa31f17a3b13206abccd3e684145 +Subproject commit f999afeb9e52a05e6fd593de6b88f16ec8421808 From 69898f70ddeb3f7e4e507595aec9a377d4de5393 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 17 Jul 2023 16:26:31 +0530 Subject: [PATCH 20/37] Use cmd args --- src/Main.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Main.vala b/src/Main.vala index 065198eb..a64aec2b 100644 --- a/src/Main.vala +++ b/src/Main.vala @@ -35,7 +35,7 @@ public static int main (string[] args) { .has_version (Constants.VERSION, Constants.DISPLAYVER); }); - return Services.di_container.obtain (Services.st_application).run (); + return Services.di_container.obtain (Services.st_application).run (args); // QT 3 From 2d6fdd65c654511f19996512a01169524a542fe3 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 17 Jul 2023 22:16:35 +0530 Subject: [PATCH 21/37] LINT --- subprojects/ens-shell-cli | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli index f605ec32..e6d0608d 160000 --- a/subprojects/ens-shell-cli +++ b/subprojects/ens-shell-cli @@ -1 +1 @@ -Subproject commit f605ec32a4c5068925c6c409d249f1fece4e5e25 +Subproject commit e6d0608d62dff40bc6a6fb13414e8af5ffc38e9a diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index f999afeb..c3c03391 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit f999afeb9e52a05e6fd593de6b88f16ec8421808 +Subproject commit c3c033915ad8122d3fc57aeebcef6c2c795361c1 From 12c1c514bfec3802c5471f18b7e17d4a1528f212 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 23 Jul 2023 18:02:03 +0530 Subject: [PATCH 22/37] Clean stuff --- src/Main.vala | 7 ++----- src/Services.vala | 7 ------- subprojects/ens-shell-cli | 2 +- subprojects/ens-shell-gtk | 2 +- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/Main.vala b/src/Main.vala index a64aec2b..7cc729ba 100644 --- a/src/Main.vala +++ b/src/Main.vala @@ -35,14 +35,11 @@ public static int main (string[] args) { .has_version (Constants.VERSION, Constants.DISPLAYVER); }); + Console.log ("Starting application"); return Services.di_container.obtain (Services.st_application).run (args); - // QT 3 - // Windows UI 3 } catch (Vinject.VinjectErrors e) { - Services.handle_di_error (e); + error (e.message); } - - return 0; } diff --git a/src/Services.vala b/src/Services.vala index d289fe39..2789a5f7 100644 --- a/src/Services.vala +++ b/src/Services.vala @@ -3,11 +3,4 @@ using Ensembles.ArrangerWorkstation; namespace Ensembles.Services { static Injector di_container; - - static void handle_di_error (VinjectErrors e) { - Console.log ( - "FATAL: Dependency injection error occurred! %s. Exiting…" - .printf (e.message), Console.LogLevel.ERROR - ); - } } diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli index e6d0608d..d8bbd2d7 160000 --- a/subprojects/ens-shell-cli +++ b/subprojects/ens-shell-cli @@ -1 +1 @@ -Subproject commit e6d0608d62dff40bc6a6fb13414e8af5ffc38e9a +Subproject commit d8bbd2d7d1aa7b7f276557e2efc1a205008bf51b diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index c3c03391..19b8d872 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit c3c033915ad8122d3fc57aeebcef6c2c795361c1 +Subproject commit 19b8d8720a87d69045f1d57667d4d20877bf88d9 From 383f38c5e875d4d95a2455c3e0545a17c31722fd Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 23 Jul 2023 19:58:58 +0530 Subject: [PATCH 23/37] Update submodules --- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index d64e803f..f428cf3a 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit d64e803fc315bb6d9362d59c266370333c5b69da +Subproject commit f428cf3a57cea6d14b16a3919df414a7e3a8ec65 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 19b8d872..f9b6cf85 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 19b8d8720a87d69045f1d57667d4d20877bf88d9 +Subproject commit f9b6cf859f79c81306a0680d6196ff8f8141db1b From d4ec965064e2c58e552f84948f2623609066d7c9 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 23 Jul 2023 20:13:55 +0530 Subject: [PATCH 24/37] Remove scalable icons from here --- .../scalable/actions/plugin-add-symbolic.svg | 12 ---- .../scalable/actions/style-break-symbolic.svg | 7 -- .../actions/style-sync-start-symbolic.svg | 69 ------------------- .../emblems/plugin-audio-lv2-symbolic.svg | 3 - subprojects/ens-shell-gtk | 2 +- 5 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 data/Icons/scalable/actions/plugin-add-symbolic.svg delete mode 100644 data/Icons/scalable/actions/style-break-symbolic.svg delete mode 100644 data/Icons/scalable/actions/style-sync-start-symbolic.svg delete mode 100644 data/Icons/scalable/emblems/plugin-audio-lv2-symbolic.svg diff --git a/data/Icons/scalable/actions/plugin-add-symbolic.svg b/data/Icons/scalable/actions/plugin-add-symbolic.svg deleted file mode 100644 index 1c3cb996..00000000 --- a/data/Icons/scalable/actions/plugin-add-symbolic.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/data/Icons/scalable/actions/style-break-symbolic.svg b/data/Icons/scalable/actions/style-break-symbolic.svg deleted file mode 100644 index 0900ecdd..00000000 --- a/data/Icons/scalable/actions/style-break-symbolic.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/data/Icons/scalable/actions/style-sync-start-symbolic.svg b/data/Icons/scalable/actions/style-sync-start-symbolic.svg deleted file mode 100644 index c05a1bae..00000000 --- a/data/Icons/scalable/actions/style-sync-start-symbolic.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/data/Icons/scalable/emblems/plugin-audio-lv2-symbolic.svg b/data/Icons/scalable/emblems/plugin-audio-lv2-symbolic.svg deleted file mode 100644 index b534b296..00000000 --- a/data/Icons/scalable/emblems/plugin-audio-lv2-symbolic.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index f9b6cf85..f900a6fc 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit f9b6cf859f79c81306a0680d6196ff8f8141db1b +Subproject commit f900a6fc6e34a78d4fcd45ad3d6e850d1d61f1bc From f21ab874a0c5394b9c71fbf2a1db0c0875b01eee Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 30 Jul 2023 12:32:46 +0530 Subject: [PATCH 25/37] Make remaining connections --- com.github.ensemblesaw.ensembles.yml | 4 ++-- src/Main.vala | 4 +++- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- subprojects/libvinject | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index ca784203..2934d320 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -1,8 +1,8 @@ -app-id: com.github.subhadeepjasu.ensembles +app-id: com.github.ensemblesaw.ensembles runtime: io.elementary.Platform runtime-version: '7.1' sdk: io.elementary.Sdk -command: com.github.subhadeepjasu.ensembles +command: com.github.ensemblesaw.ensembles finish-args: - '--share=ipc' - '--socket=fallback-x11' diff --git a/src/Main.vala b/src/Main.vala index 7cc729ba..d34e2eef 100644 --- a/src/Main.vala +++ b/src/Main.vala @@ -16,7 +16,9 @@ public static int main (string[] args) { try { // Arranger Workstation Service Services.configure_aw_service ((aw_builder) => { - aw_builder.use_driver (Ensembles.ArrangerWorkstation.AWCore.Driver.ALSA) + aw_builder.use_driver ( + Ensembles.ArrangerWorkstation.AudioEngine.ISynthEngine.Driver.ALSA + ) .load_soundfont_with_name ("EnsemblesGM") .load_soundfont_from_dir (Constants.SF2DATADIR) .add_style_search_path (StyleRepository.get_style_dir ()) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index f428cf3a..dceb44b4 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit f428cf3a57cea6d14b16a3919df414a7e3a8ec65 +Subproject commit dceb44b423dea247854d0b5174ebeabecc9b4bc2 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index f900a6fc..64cacde6 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit f900a6fc6e34a78d4fcd45ad3d6e850d1d61f1bc +Subproject commit 64cacde6b287df2e0b033c77895c43e2de2b60fd diff --git a/subprojects/libvinject b/subprojects/libvinject index 3f2f69a8..8a0d8726 160000 --- a/subprojects/libvinject +++ b/subprojects/libvinject @@ -1 +1 @@ -Subproject commit 3f2f69a867cbed015455c64df4fb30cbbb78ab98 +Subproject commit 8a0d87262cd560310af7c233da5293d5c704cfee From 7003f6b40998283addf06f1ec284b3779575c5bb Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 13 Aug 2023 18:03:56 +0530 Subject: [PATCH 26/37] Subproject update --- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- subprojects/enstl | 2 +- subprojects/libvinject | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index dceb44b4..934f2888 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit dceb44b423dea247854d0b5174ebeabecc9b4bc2 +Subproject commit 934f288815185a92f274b73733d14ffe2e1199de diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 64cacde6..085e7cc4 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 64cacde6b287df2e0b033c77895c43e2de2b60fd +Subproject commit 085e7cc4bb77371b86f4f0f17140c84c94e4fb19 diff --git a/subprojects/enstl b/subprojects/enstl index 21b78ffe..d0d35ad5 160000 --- a/subprojects/enstl +++ b/subprojects/enstl @@ -1 +1 @@ -Subproject commit 21b78ffe86470a9b4335eb27ea97267693219ba9 +Subproject commit d0d35ad5407647a5aa8f8637d177ed3f3498c067 diff --git a/subprojects/libvinject b/subprojects/libvinject index 8a0d8726..bad5b8ae 160000 --- a/subprojects/libvinject +++ b/subprojects/libvinject @@ -1 +1 @@ -Subproject commit 8a0d87262cd560310af7c233da5293d5c704cfee +Subproject commit bad5b8ae3c2ed14f0ab6820c10c47217e4cfa126 From fa7b83784f2fd57aff34b60b8ed777b4e713e03c Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Tue, 15 Aug 2023 18:06:43 +0530 Subject: [PATCH 27/37] FInally got a real instrument plugin and some effects to work! --- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 934f2888..149a5eff 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 934f288815185a92f274b73733d14ffe2e1199de +Subproject commit 149a5eff65c19acd0fe75c6df5026bc2fd6b62bc diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 085e7cc4..58c4e807 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 085e7cc4bb77371b86f4f0f17140c84c94e4fb19 +Subproject commit 58c4e8072452645a89b1a8a53c9befba60943251 From 9c7da0ad5471bbf1b4fd8b8f4d50cac24b76ac48 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 10 Sep 2023 20:45:27 +0530 Subject: [PATCH 28/37] Add lv2 options feature and knob control fixes --- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 149a5eff..97f7660d 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 149a5eff65c19acd0fe75c6df5026bc2fd6b62bc +Subproject commit 97f7660db286d7056ba74bea9f2dabdfe5c213b0 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 58c4e807..40abbdc0 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 58c4e8072452645a89b1a8a53c9befba60943251 +Subproject commit 40abbdc0a766a99504d134fe418426a82bdb0c51 From 59c5d1837ef86c45774884ca370600f6294e2b7c Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 4 Dec 2023 23:16:55 +0530 Subject: [PATCH 29/37] Implement assignable controls --- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 97f7660d..3d47533c 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 97f7660db286d7056ba74bea9f2dabdfe5c213b0 +Subproject commit 3d47533c7a9d720da6d5a89d6d062dc5bdb05f62 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 40abbdc0..47cb25b2 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 40abbdc0a766a99504d134fe418426a82bdb0c51 +Subproject commit 47cb25b28e21a44122942e4d4f11d154fb6056fe From 751c71f77f3d973d5b38d13a3fdab4cfcf0d3519 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Tue, 5 Dec 2023 22:10:49 +0530 Subject: [PATCH 30/37] Get flatpak build working (kinda) --- .gitmodules | 1 + com.github.ensemblesaw.ensembles.yml | 129 +++++++++------------------ subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- subprojects/libvinject | 2 +- subprojects/libvinject.wrap | 2 +- 6 files changed, 47 insertions(+), 91 deletions(-) diff --git a/.gitmodules b/.gitmodules index 97e736e9..9bd69786 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,7 @@ url = https://github.com/ensemblesaw/ens-shell-gtk [submodule "libvinject"] path = subprojects/libvinject url = https://gitlab.com/geeky_endeavours/vinject.git +branch = 9.1-unit-tests-using-boxed-values-fix [submodule "enstl"] path = subprojects/enstl diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index 2934d320..6b65cd28 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -1,6 +1,6 @@ app-id: com.github.ensemblesaw.ensembles runtime: io.elementary.Platform -runtime-version: '7.1' +runtime-version: '7.3' sdk: io.elementary.Sdk command: com.github.ensemblesaw.ensembles finish-args: @@ -21,105 +21,90 @@ finish-args: modules: # Adds support for lv2 virtual instruments and effects plugins - name: lv2 - buildsystem: simple + buildsystem: meson cleanup: - /bin - /include - - /pkgconfig + - /lib/pkgconfig - /share - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST --lv2dir=$FLATPAK_DEST/lib/lv2 --copy-headers - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install sources: - type: archive - url: https://lv2plug.in/spec/lv2-1.18.2.tar.bz2 - sha256: 4e891fbc744c05855beb5dfa82e822b14917dd66e98f82b8230dbd1c7ab2e05e + url: https://lv2plug.in/spec/lv2-1.18.10.tar.xz + sha256: 78c51bcf21b54e58bb6329accbb4dae03b2ed79b520f9a01e734bd9de530953f post-install: - - install -Dm644 -t $FLATPAK_DEST/share/licenses/lv2 COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/lv2 ../COPYING - ln -sf lv2.pc $FLATPAK_DEST/lib/pkgconfig/lv2core.pc # Allows Ensembles to act as a lv2 host - name: lilv - buildsystem: simple - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install + buildsystem: meson modules: - name: serd - buildsystem: simple - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install + buildsystem: meson sources: - type: archive - url: https://download.drobilla.net/serd-0.30.10.tar.bz2 - sha256: affa80deec78921f86335e6fc3f18b80aefecf424f6a5755e9f2fa0eb0710edf + url: https://download.drobilla.net/serd-0.30.16.tar.xz + sha256: f50f486da519cdd8d03b20c9e42414e459133f5a244411d8e63caef8d9ac9146 post-install: - - install -Dm644 -t /app/share/licenses/serd COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/serd ../COPYING cleanup: - /bin - /include - /lib/pkgconfig - /share/man - name: sord - buildsystem: simple - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install + buildsystem: meson sources: - type: archive - url: https://download.drobilla.net/sord-0.16.8.tar.bz2 - sha256: 7c289d2eaabf82fa6ac219107ce632d704672dcfb966e1a7ff0bbc4ce93f5e14 + url: https://download.drobilla.net/sord-0.16.14.tar.xz + sha256: 220fd97d5fcb216e7b85db66f685bfdaad7dc58a50d1f96dfb2558dbc6c4731b post-install: - - install -Dm644 -t /app/share/licenses/sord COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/sord ../COPYING cleanup: - /bin - /include - /lib/pkgconfig + - /share/doc - /share/man - name: sratom - buildsystem: simple - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install + buildsystem: meson sources: - type: archive - url: https://download.drobilla.net/sratom-0.6.8.tar.bz2 - sha256: 3acb32b1adc5a2b7facdade2e0818bcd6c71f23f84a1ebc17815bb7a0d2d02df + url: https://download.drobilla.net/sratom-0.6.14.tar.xz + sha256: 9982faf40db83aedd9b3850e499fecd6852b8b4ba6dede514013655cffaca1e6 post-install: - - install -Dm644 -t /app/share/licenses/sratom COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/sratom ../COPYING cleanup: - /include - /lib/pkgconfig sources: - type: archive - url: https://download.drobilla.net/lilv-0.24.12.tar.bz2 - sha256: 26a37790890c9c1f838203b47f5b2320334fe92c02a4d26ebbe2669dbd769061 + url: https://download.drobilla.net/lilv-0.24.20.tar.xz + sha256: 4fb082b9b8b286ea92bbb71bde6b75624cecab6df0cc639ee75a2a096212eebc post-install: - - install -Dm644 -t /app/share/licenses/lilv COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/lilv ../COPYING cleanup: - /bin - /etc + - /include - /lib/pkgconfig - /share/man + - name: zix + buildsystem: meson + sources: + - type: git + url: https://github.com/drobilla/zix.git + tag: v0.4.2 + - name: suil - buildsystem: simple - build-commands: - - python3 ./waf configure --prefix=$FLATPAK_DEST - - python3 ./waf build -j $FLATPAK_BUILDER_N_JOBS - - python3 ./waf install + buildsystem: meson sources: - type: archive - url: http://download.drobilla.net/suil-0.10.10.tar.bz2 - sha256: 750f08e6b7dc941a5e694c484aab02f69af5aa90edcc9fb2ffb4fb45f1574bfb + url: https://download.drobilla.net/suil-0.10.20.tar.xz + sha256: 334a3ed3e73d5e17ff400b3db9801f63809155b0faa8b1b9046f9dd3ffef934e post-install: - - install -Dm644 -t /app/share/licenses/suil COPYING + - install -Dm644 -t $FLATPAK_DEST/share/licenses/suil ../COPYING cleanup: - /bin - /include @@ -127,56 +112,26 @@ modules: - /share/man # Synthesizer backend - # - name: fluidsynth - # buildsystem: cmake-ninja - # config-opts: - # - -DLIB_SUFFIX= - # cleanup: - # - /bin - # - /include - # - /lib/pkgconfig - # - /share/man - # - '*.so' - # sources: - # - type: archive - # url: https://github.com/FluidSynth/fluidsynth/archive/v2.2.4.tar.gz - # sha256: 83cb1dba04c632ede74f0c0717018b062c0e00b639722203b23f77a961afd390 - name: fluidsynth buildsystem: cmake-ninja - config-opts: - - -DLIB_SUFFIX= cleanup: - /bin - /include - /lib/pkgconfig - /share/man - '*.so' - - '*.a' sources: - - type: git - url: https://github.com/FluidSynth/fluidsynth + - type: archive + url: https://github.com/FluidSynth/fluidsynth/archive/v2.3.4.tar.gz + sha256: 1529ef5bc3b9ef3adc2a7964505912f7305103e269e50cc0316f500b22053ac9 # MIDI controller support - name: portmidi - buildsystem: cmake-ninja - config-opts: - - -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/app/lib - - -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=/app/lib - - -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/app/bin - post-install: - - ln -s libportmidi.so /app/lib/libporttime.so + buildsystem: cmake sources: - - type: archive - url: https://sourceforge.net/projects/portmedia/files/portmidi/217/portmidi-src-217.zip - sha256: 08e9a892bd80bdb1115213fb72dc29a7bf2ff108b378180586aa65f3cfd42e0f - - type: patch - path: patches/portmidi-no-java.patch - cleanup: - - /bin - - /lib/pkgconfig - - /include - - '*.a' - - '*.la' + - type: git + url: https://github.com/PortMidi/portmidi.git + tag: v2.0.3 # The app itself - name: ensembles diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 3d47533c..26f4f87a 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 3d47533c7a9d720da6d5a89d6d062dc5bdb05f62 +Subproject commit 26f4f87ab28cc7735dae4908b177664ecf9ac73e diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 47cb25b2..1b7d509a 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 47cb25b28e21a44122942e4d4f11d154fb6056fe +Subproject commit 1b7d509a15f0174ab34ffa8c53d4d2fc8ffff930 diff --git a/subprojects/libvinject b/subprojects/libvinject index bad5b8ae..e1117084 160000 --- a/subprojects/libvinject +++ b/subprojects/libvinject @@ -1 +1 @@ -Subproject commit bad5b8ae3c2ed14f0ab6820c10c47217e4cfa126 +Subproject commit e111708411f7076270613397bc05e444a2360774 diff --git a/subprojects/libvinject.wrap b/subprojects/libvinject.wrap index 2408b60e..71e0cacf 100644 --- a/subprojects/libvinject.wrap +++ b/subprojects/libvinject.wrap @@ -1,6 +1,6 @@ [wrap-git] url=https://gitlab.com/geeky_endeavours/vinject.git -revision=main +revision=9.1-unit-tests-using-boxed-values-fix depth=1 [provide] From 7c2daf06e206702bcf03ed0f6fb2c109bb712f90 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Tue, 5 Dec 2023 22:14:20 +0530 Subject: [PATCH 31/37] Fix Github CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de610f13..5b586a6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v3 with: bundle: Ensembles.flatpak - manifest-path: com.github.subhadeepjasu.ensembles.yml + manifest-path: com.github.ensemblesaw.ensembles.yml run-tests: true repository-name: appcenter repository-url: https://flatpak.elementary.io/repo.flatpakrepo From 0cc291f753a676807bbbc9d18027ee8021a0d19d Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Wed, 6 Dec 2023 20:50:00 +0530 Subject: [PATCH 32/37] Add vinject to flatpak manifest --- com.github.ensemblesaw.ensembles.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index 6b65cd28..8d817c39 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -19,6 +19,17 @@ finish-args: - '--filesystem=xdg-run/pipewire-0' - '--system-talk-name=org.freedesktop.RealtimeKit1' modules: + # Adds dependency injection + - name: vinject + buildsystem: meson + cleanup: + - /include + sources: + - type: git + url: https://gitlab.com/geeky_endeavours/vinject.git + branch: 9.1-unit-tests-using-boxed-values-fix + + # Adds support for lv2 virtual instruments and effects plugins - name: lv2 buildsystem: meson From b6a28bf84a390b07a65ee9ddac9109cedf857efb Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Wed, 6 Dec 2023 21:44:34 +0530 Subject: [PATCH 33/37] Fix vinject lib name in meson script --- com.github.ensemblesaw.ensembles.yml | 8 ++++++-- meson.build | 2 +- subprojects/ens-aw-core | 2 +- subprojects/ens-shell-gtk | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index 8d817c39..c5aef6c0 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -22,8 +22,6 @@ modules: # Adds dependency injection - name: vinject buildsystem: meson - cleanup: - - /include sources: - type: git url: https://gitlab.com/geeky_endeavours/vinject.git @@ -147,6 +145,12 @@ modules: # The app itself - name: ensembles buildsystem: meson + build-options: + config-opts: + - -Dprofile=default + - -Dbuildtype=release + - --wrap-mode=nofallback + - --force-fallback-for=ens-enstl-0,ens-shell-cli-0,ens-shell-gtk-0,ens-aw-core-0 sources: - type: dir path: . diff --git a/meson.build b/meson.build index f1ec8bd5..b309e334 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ gettext_package = application_id dependencies = [ dependency ('glib-2.0'), dependency ('gee-0.8'), - dependency ('libvinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), + dependency ('Vinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), dependency ('ens-enstl-0', fallback: ['enstl', 'enstl_dep']), dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep']), dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep'], diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core index 26f4f87a..4babd953 160000 --- a/subprojects/ens-aw-core +++ b/subprojects/ens-aw-core @@ -1 +1 @@ -Subproject commit 26f4f87ab28cc7735dae4908b177664ecf9ac73e +Subproject commit 4babd9533839cd8401bdd328a7530a8fb1f968c2 diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk index 1b7d509a..50eea80d 160000 --- a/subprojects/ens-shell-gtk +++ b/subprojects/ens-shell-gtk @@ -1 +1 @@ -Subproject commit 1b7d509a15f0174ab34ffa8c53d4d2fc8ffff930 +Subproject commit 50eea80dbe417304df5d7871d30e05ce97a03a7b From cad99a2e1477213929641998fa07b1f315a6bd04 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Wed, 13 Dec 2023 23:53:58 +0530 Subject: [PATCH 34/37] Hopefully fix flatpak build now? --- .gitignore | 5 + .gitmodules | 20 - com.github.ensemblesaw.ensembles.yml | 43 +- meson.build | 22 +- subprojects/ens-aw-core | 1 - subprojects/ens-shell-cli | 1 - subprojects/ens-shell-cli.wrap | 2 +- subprojects/ens-shell-gtk | 1 - subprojects/ens-shell-gtk.wrap | 1 - subprojects/enstl | 1 - subprojects/libvinject | 1 - vapi/fluidsynth.vapi | 896 +++++++++++++++++++++++++ vapi/libpipewire-0.3.vapi | 27 + vapi/lilv-0.vapi | 279 ++++++++ vapi/lv2.vapi | 959 +++++++++++++++++++++++++++ vapi/portmidi.vapi | 193 ++++++ vapi/suil-0.vapi | 91 +++ vapi/zix-0.vapi | 138 ++++ 18 files changed, 2650 insertions(+), 31 deletions(-) delete mode 100644 .gitmodules delete mode 160000 subprojects/ens-aw-core delete mode 160000 subprojects/ens-shell-cli delete mode 160000 subprojects/ens-shell-gtk delete mode 160000 subprojects/enstl delete mode 160000 subprojects/libvinject create mode 100644 vapi/fluidsynth.vapi create mode 100644 vapi/libpipewire-0.3.vapi create mode 100644 vapi/lilv-0.vapi create mode 100644 vapi/lv2.vapi create mode 100644 vapi/portmidi.vapi create mode 100644 vapi/suil-0.vapi create mode 100644 vapi/zix-0.vapi diff --git a/.gitignore b/.gitignore index 00a18a74..54d54d31 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ null.d *~ .~lock* xtleak.kcg.* +subprojects/ens-shell-gtk +subprojects/ens-shell-cli +subprojects/ens-aw-core +subprojects/enstl +subprojects/libvinject diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9bd69786..00000000 --- a/.gitmodules +++ /dev/null @@ -1,20 +0,0 @@ -[submodule "ens-aw-core"] -path = subprojects/ens-aw-core -url = https://github.com/ensemblesaw/ens-aw-core - -[submodule "ens-shell-cli"] -path = subprojects/ens-shell-cli -url = https://github.com/ensemblesaw/ens-shell-cli - -[submodule "ens-shell-gtk"] -path = subprojects/ens-shell-gtk -url = https://github.com/ensemblesaw/ens-shell-gtk - -[submodule "libvinject"] -path = subprojects/libvinject -url = https://gitlab.com/geeky_endeavours/vinject.git -branch = 9.1-unit-tests-using-boxed-values-fix - -[submodule "enstl"] -path = subprojects/enstl -url = https://github.com/ensemblesaw/enstl diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index c5aef6c0..cccc7e51 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -142,6 +142,47 @@ modules: url: https://github.com/PortMidi/portmidi.git tag: v2.0.3 + + # Install styles + - name: styles + buildsystem: meson + sources: + - type: git + url: https://github.com/ensemblesaw/styles.git + branch: main + + # CLI shell + - name: ens-shell-cli + buildsystem: meson + sources: + - type: git + url: https://github.com/ensemblesaw/ens-shell-cli.git + branch: main + + # Arranger Workstation Core + - name: ens-aw-core + buildsystem: meson + build-options: + config-opts: + - -Dprofile=default + - -Dbuildtype=release + sources: + - type: git + url: https://github.com/ensemblesaw/ens-aw-core.git + branch: main + + # GTK Shell + - name: ens-shell-gtk + buildsystem: meson + build-options: + config-opts: + - -Dprofile=default + - -Dbuildtype=release + sources: + - type: git + url: https://github.com/ensemblesaw/ens-shell-gtk.git + branch: main + # The app itself - name: ensembles buildsystem: meson @@ -149,8 +190,6 @@ modules: config-opts: - -Dprofile=default - -Dbuildtype=release - - --wrap-mode=nofallback - - --force-fallback-for=ens-enstl-0,ens-shell-cli-0,ens-shell-gtk-0,ens-aw-core-0 sources: - type: dir path: . diff --git a/meson.build b/meson.build index b309e334..6864be9e 100644 --- a/meson.build +++ b/meson.build @@ -29,7 +29,7 @@ add_project_arguments ( add_project_arguments ( ['--vapidir', join_paths (meson.current_source_dir (), 'vapi')], - ['--vapidir', join_paths (meson.current_source_dir (), 'subprojects', 'ens-aw-core', 'vapi')], + ['--vapidir', join_paths (meson.current_build_dir(), 'subprojects', 'ens-shell-gtk')], language: 'vala' ) @@ -51,8 +51,26 @@ gettext_package = application_id dependencies = [ dependency ('glib-2.0'), dependency ('gee-0.8'), + # Core deps + dependency ('fluidsynth', required: false), + dependency ('lv2', required: false), + dependency ('lilv-0', required: false), + dependency ('suil-0', required: false), + dependency ('zix-0', fallback: ['zix', 'zix_dep'], default_options: [ + 'tests=disabled', 'default_library=static', + 'docs=disabled', 'tests_cpp=disabled', + ], required: false), + dependency ('portmidi', required: false), + dependency ('libpipewire-0.3', required: false), + dependency ('x11', required: false), + dependency ('granite-7', required: false), + dependency ('libadwaita-1', required: false), + dependency ('gtk4', required: false), + dependency ('gobject-2.0'), + dependency ('libsoup-3.0', required: false), + dependency ('json-glib-1.0', required: false), dependency ('Vinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), - dependency ('ens-enstl-0', fallback: ['enstl', 'enstl_dep']), + dependency ('enstl-0', fallback: ['enstl', 'enstl_dep']), dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep']), dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep'], default_options: ['profile=' + profile]), diff --git a/subprojects/ens-aw-core b/subprojects/ens-aw-core deleted file mode 160000 index 4babd953..00000000 --- a/subprojects/ens-aw-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4babd9533839cd8401bdd328a7530a8fb1f968c2 diff --git a/subprojects/ens-shell-cli b/subprojects/ens-shell-cli deleted file mode 160000 index d8bbd2d7..00000000 --- a/subprojects/ens-shell-cli +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d8bbd2d7d1aa7b7f276557e2efc1a205008bf51b diff --git a/subprojects/ens-shell-cli.wrap b/subprojects/ens-shell-cli.wrap index 77695508..a65e5cbd 100644 --- a/subprojects/ens-shell-cli.wrap +++ b/subprojects/ens-shell-cli.wrap @@ -1,4 +1,4 @@ [wrap-git] -url = https://github.com/ensemblesaw/ens-shell-cli +url = https://github.com/ensemblesaw/ens-shell-cli.git depth = 1 revision = main diff --git a/subprojects/ens-shell-gtk b/subprojects/ens-shell-gtk deleted file mode 160000 index 50eea80d..00000000 --- a/subprojects/ens-shell-gtk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50eea80dbe417304df5d7871d30e05ce97a03a7b diff --git a/subprojects/ens-shell-gtk.wrap b/subprojects/ens-shell-gtk.wrap index f648f841..69e9cf90 100644 --- a/subprojects/ens-shell-gtk.wrap +++ b/subprojects/ens-shell-gtk.wrap @@ -1,5 +1,4 @@ [wrap-git] url = https://github.com/ensemblesaw/ens-shell-gtk depth = 1 -clone-recursive = true revision = main diff --git a/subprojects/enstl b/subprojects/enstl deleted file mode 160000 index d0d35ad5..00000000 --- a/subprojects/enstl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0d35ad5407647a5aa8f8637d177ed3f3498c067 diff --git a/subprojects/libvinject b/subprojects/libvinject deleted file mode 160000 index e1117084..00000000 --- a/subprojects/libvinject +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e111708411f7076270613397bc05e444a2360774 diff --git a/vapi/fluidsynth.vapi b/vapi/fluidsynth.vapi new file mode 100644 index 00000000..5d8957b3 --- /dev/null +++ b/vapi/fluidsynth.vapi @@ -0,0 +1,896 @@ +/* + * Copyright 2020-2023 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ +/* + * This file incorporates work covered by the following copyright and + * permission notices: + * + * --- + * + * FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + * --- + */ + + + /** + * FluidSynth + */ +[CCode(cheader_filename="fluidsynth.h", cprefix="FLUID_", lower_case_cprefix="fluid_")] +namespace Fluid { + /** + * Value that indicates success, used by most libfluidsynth functions. + * + * @since 1.1.0 + */ + const int OK; + /** + * Value that indicates failure, used by most libfluidsynth functions. + * + * @since 1.1.0 + */ + const int FAILED; + /** + * String constant of libfluidsynth version. + */ + const string VERSION; + /** + * libfluidsynth major version integer constant. + */ + const int VERSION_MAJOR; + /** + * Value that indicates failure, used by most libfluidsynth functions. + */ + const int VERSION_MICRO; + /** + * libfluidsynth micro version integer constant. + */ + const int VERSION_MINOR; + /** + * libfluidsynth minor version integer constant. + */ + + /** + * Wrapper for `free()` that satisfies at least C90 requirements. + * + * **Warning**: + * Calling {@link Fluid.free} on memory that is advised to be freed with + * `fluid_free()` results in undefined behaviour! (cf.: "Potential Errors + * Passing CRT Objects Across DLL Boundaries" found in MS Docs) + * + * @since 2.0.7 + * @param ptr Pointer to memory region that should be freed + */ + void free (void* ptr); + /** + * Check if a file is a MIDI file. + * + * The current implementation only checks for the "MThd" header in the + * file. It is useful only to distinguish between SoundFont and MIDI files. + * + * @param filename Path to the file to check + * @return TRUE if it could be a MIDI file, FALSE otherwise + */ + bool is_midifile (string filename); + /** + * Check if a file is a SoundFont file. + * + * If fluidsynth was built with DLS support, this function will also + * identify DLS files. + * + * **Note:** This function only checks whether header(s) in the RIFF chunk + * are present. A call to {@link Fluid.Synth.sfload} might still fail. + * + * @param filename Path to the file to check + * @return TRUE if it could be a SF2, SF3 or DLS file, FALSE otherwise + */ + bool is_soundfont (string filename); + /** + * Get FluidSynth runtime version. + * + * @param major Location to store major number + * @param minor Location to store minor number + * @param micro Location to store micro number + */ + void version (out int major, out int minor, out int micro); + /** + * Get FluidSynth runtime version as a string. + * + * @return FluidSynth version string, which is internal and + * should not be modified or freed. + */ + string version_str (); + + [CCode (cprefix = "HINT_")] + namespace Hint { + /** + * Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field of + * the FLUID_PortRangeHint should be considered meaningful. + * + * The value in this field should be considered the (inclusive) upper + * bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also + * specified then the value of UpperBound should be multiplied by + * the sample rate. + */ + public const int BOUNDED_ABOVE; + /** + * Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field of + * the FLUID_PortRangeHint should be considered meaningful. + * + * The value in this field should be considered the (inclusive) lower + * bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also specified + * then the value of LowerBound should be multiplied by the sample rate. + */ + public const int BOUNDED_BELOW; + /** + * Setting is a list of string options. + */ + public const int OPTIONLIST; + /** + * Hint FLUID_HINT_TOGGLED indicates that the data item should be + * considered a Boolean toggle. + * + * Data less than or equal to zero should be considered ‘off’ or + * ‘false,’ and data above zero should be considered ‘on’ or ‘true.’ + * FLUID_HINT_TOGGLED may not be used in conjunction with any other hint. + */ + public const int TOGGLED; + } + + /** + * Settings type. + * + * Each setting has a defined type: numeric (double), integer, string or a + * set of values. The type of each setting can be retrieved using the + * function {@link Fluid.Settings.get_type} + */ + [CCode (cname = "enum fluid_types_enum", has_type_id = false, cprefix = "FLUID_")] + public enum Types { + /** Undefined type */ + NO_TYPE, + /** Numeric (double) */ + NUM_TYPE, + /** Integer */ + INT_TYPE, + /** String */ + STR_TYPE, + /** Set of values */ + SET_TYPE + } + + /** Chorus modulation waveform type. */ + [CCode (cname = "enum fluid_chorus_mod", has_type_id = false, cprefix = "FLUID_CHORUS_")] + public enum ChorusMod { + /** Sine wave chorus modulation. */ + SINE, + /** Triangle wave chorus modulation. */ + TRIANGLE + } + + /** + *Specifies optional settings to use for the custom IIR filter. + * + * Can be bitwise ORed. + */ + [Flags] + [CCode (cname = "enum fluid_iir_filter_flags", has_type_id = false, cprefix = "FLUID_IIR_")] + public enum IIRFilterFlags { + /** + *The Soundfont spec requires the filter Q to be interpreted in dB. + * + * If this flag is set the filter Q is instead assumed to be in + * a linear range */ + Q_LINEAR, + /** If this flag the filter is switched off if + * Q == 0 (prior to any transformation) */ + Q_ZERO_OFF, + /** + * The Soundfont spec requires to correct the gain of the + * filter depending on the filter's Q. + * + * If this flag is set the filter gain will not be corrected. + */ + NO_GAIN_AMP + } + + /** + * Specifies the type of filter to use for the custom IIR filter. + */ + [CCode (cname = "enum fluid_iir_filter_type", has_type_id = false, cprefix = "FLUID_IIR_")] + public enum IIRFilterTypes { + /** Custom IIR filter is not operating. */ + DISABLED, + /** Custom IIR filter is operating as low-pass filter. */ + LOWPASS, + /** Custom IIR filter is operating as high-pass filter. */ + HIGHPASS, + LAST + } + + [CCode (cname = "enum fluid_gen_type", has_type_id = false, cprefix = "GEN_")] + public enum GenType { + STARTADDROFS, + ENDADDROFS, + STARTLOOPADDROFS, + ENDLOOPADDROFS, + STARTADDRCOARSEOFS, + MODLFOTOPITCH, + VIBLFOTOPITCH, + MODENVTOPITCH, + FILTERFC, + FILTERQ, + MODLFOTOFILTERFC, + MODENVTOFILTERFC, + ENDADDRCOARSEOFS, + MODLFOTOVOL, + UNUSED1, + CHORUSSEND, + REVERBSEND, + PAN, + UNUSED2, + UNUSED3, + UNUSED4, + MODLFODELAY, + MODLFOFREQ, + VIBLFODELAY, + VIBLFOFREQ, + MODENVDELAY, + MODENVATTACK, + MODENVHOLD, + MODENVDECAY, + MODENVSUSTAIN, + MODENVRELEASE, + KEYTOMODENVHOLD, + KEYTOMODENVDECAY, + VOLENVDELAY, + VOLENVATTACK, + VOLENVHOLD, + VOLENVDECAY, + VOLENVSUSTAIN, + VOLENVRELEASE, + KEYTOVOLENVHOLD, + KEYTOVOLENVDECAY, + INSTRUMENT, + RESERVED1, + KEYRANGE, + VELRANGE, + STARTLOOPADDRCOARSEOFS, + KEYNUM, + VELOCITY, + ATTENUATION, + RESERVED2, + ENDLOOPADDRCOARSEOFS, + COARSETUNE, + FINETUNE, + SAMPLEID, + SAMPLEMODE, + RESERVED3, + SCALETUNE, + EXCLUSIVECLASS, + OVERRIDEROOTKEY, + PITCH, + CUSTOM_BALANCE, + CUSTOM_FILTERFC, + CUSTOM_FILTERQ, + LAST + } + + [CCode (cname = "enum fluid_midi_channel_type", has_type_id = false, cprefix = "CHANNEL_TYPE_")] + public enum MIDIChannelType { + MELODIC, + DRUM + } + + [CCode (cname = "enum fluid_channel_mode_flags", has_type_id = false, cprefix = "FLUID_CHANNEL_")] + public enum ChannelModeFlags { + POLY_OFF, + OMNI_OFF + } + + [CCode (cname = "enum fluid_basic_channel_modes", has_type_id = false, cprefix = "FLUID_CHANNEL_MODE_")] + public enum BasicChannelModes { + MASK, + OMNION_POLY, + OMNION_MONO, + OMNIOFF_POLY, + OMNIOFF_MONO, + LAST + } + + [CCode (cname = "enum fluid_channel_legato_mode", has_type_id = false, cprefix = "FLUID_CHANNEL_LEGATO_MODE_")] + public enum ChannelLegatoMode { + RETRIGGER, + MULTI_RETRIGGER, + LAST + } + + [CCode (cname = "enum fluid_channel_portamento_mode", has_type_id = false, cprefix = "FLUID_CHANNEL_PORTAMENTO_MODE_")] + public enum ChannelPortamentoMode { + EACH_NOTE, + LEGATO_ONLY, + STACCATO_ONLY, + LAST + } + + [CCode (cname = "enum fluid_channel_breath_flags", has_type_id = false, cprefix = "FLUID_CHANNEL_BREATH_")] + public enum ChannelBreathFlags { + POLY, + MONO, + SYNC + } + + [CCode (cname = "enum fluid_player_set_tempo_type", has_type_id = false, cprefix = "FLUID_PLAYER_TEMPO_")] + public enum TempoType { + INTERNAL, + EXTERNAL_BPM, + EXTERNAL_MIDI, + NBR + } + + [CCode (cname = "enum fluid_player_status", has_type_id = false, cprefix = "FLUID_PLAYER_")] + public enum PlayerStatus { + READY, + PLAYING, + STOPPING, + DONE + } + + [CCode (cname = "enum fluid_midi_router_rule_type ", has_type_id = false, cprefix = "FLUID_MIDI_ROUTER_RULE_")] + public enum MIDIRouterRuleType { + NOTE, + CC, + PROG_CHANGE, + PITCH_BEND, + CHANNEL_PRESSURE, + KEY_PRESSURE + } + + [SimpleType] + [CCode (cname = "fluid_audio_func_t", has_target = false)] + public delegate int handle_audio_func_t (void* data, int len, [CCode (array_length_pos = 2.1)] float*[] fx, [CCode (cname = "out", array_length_pos = 3.1)] float*[] aout); + + [SimpleType] + [CCode (cname = "handle_midi_event_func_t", has_target = false)] + public delegate int handle_midi_event_func_t (void* data, MIDIEvent? event); + + [SimpleType] + [CCode (cname = "handle_midi_tick_func_t", has_target = false)] + public delegate int handle_midi_tick_func_t (void* data, int tick); + + /** + * SoundFont synthesizer. + * + * You have to load a SoundFont in order to hear any sound. For that you use + * the {@link sfload} function. + * + * You can use the audio driver functions to open the audio device and + * create a background audio thread. + * + * The API for sending MIDI events is probably + * what you expect: {@link noteon}, {@link noteoff}, ... + */ + [Compact] + [CCode (cname = "fluid_synth_t", cprefix = "fluid_synth_", free_function = "delete_fluid_synth", has_type_id = false)] + public class Synth { + [CCode (cname = "new_fluid_synth")] + public Synth (Settings? settings); + + public Settings get_settings (); + /** + * Get a textual representation of the last error. + * + * @return Pointer to string of last error message. Valid until the + * same calling thread calls another FluidSynth function which fails. + * String is internal and should not be modified or freed. + * + * @deprecated + */ + public string error (); + /** Get the synth CPU load value. + * + * @return Estimated CPU load value in percent (0-100) */ + public double get_cpu_load (); + + // Audio Rendering + + /** + * Synthesize floating point audio to stereo audio channels + * (implements the default interface {@link handle_audio_func_t}). + * + * Synthesize and mix audio to a given number of planar audio buffers. + * Therefore pass `aout.length = N*2` float buffers + * to `out` in order to render the synthesized audio to `N` stereo channels. + * Each float buffer must be able to hold `len` elements. + * + * `aout` contains an array of planar buffers for normal, dry, stereo + * audio (alternating left and right). Like: + * {{{ + * aout[0] = left_buffer_audio_channel_0 + * aout[1] = right_buffer_audio_channel_0 + * aout[2] = left_buffer_audio_channel_1 + * aout[3] = right_buffer_audio_channel_1 + * ... + * aout[ (i * 2 + 0) % aout.length ] = left_buffer_audio_channel_i + * aout[ (i * 2 + 1) % aout.length ] = right_buffer_audio_channel_i + * }}} + * + * for zero-based channel index `i`. The buffer layout of `fx` used for + * storing effects like reverb and chorus looks similar: + * + * {{{ + * fx[0] = left_buffer_channel_of_reverb_unit_0 + * fx[1] = right_buffer_channel_of_reverb_unit_0 + * fx[2] = left_buffer_channel_of_chorus_unit_0 + * fx[3] = right_buffer_channel_of_chorus_unit_0 + * fx[4] = left_buffer_channel_of_reverb_unit_1 + * fx[5] = right_buffer_channel_of_reverb_unit_1 + * fx[6] = left_buffer_channel_of_chorus_unit_1 + * fx[7] = right_buffer_channel_of_chorus_unit_1 + * fx[8] = left_buffer_channel_of_reverb_unit_2 + * ... + * fx[ ((k * synth.count_effects_channels() + j) * 2 + 0) % fx.length ] = left_buffer_for_effect_channel_j_of_unit_k + * fx[ ((k * synth.count_effects_channels() + j) * 2 + 1) % fx.length ] = right_buffer_for_effect_channel_j_of_unit_k + * }}} + * + * where `0 <= k < synth.count_effects_groups()` is a zero-based index + * denoting the effects unit and `0 <= j < synth.count_effects_channels()` + * is a zero-based index denoting the effect channel within unit `k`. + * + * Any playing voice is assigned to audio channels based on the MIDI + * channel it's playing on: Let chan be the zero-based MIDI channel index + * an arbitrary voice is playing on. To determine the audio channel and + * effects unit it is going to be rendered to use: + * + * `i = chan % synth.count_audio_groups()` + * + * `k = chan % synth.count_effects_groups()` + * + * **Note:** The owner of the sample buffers must zero them out before + * calling this function, because any synthesized audio is mixed + * (i.e. added) to the buffers. E.g. if {@link Fluid.Synth.process} is called + * from a custom audio driver process function {@link Fluid.AudioDriver.with_audio_callback}), + * the audio driver takes care of zeroing the buffers. + * + * **Note:** No matter how many buffers you pass in, {@link Fluid.Synth.process} + * will always render all audio channels to the buffers in out and all + * effects channels to the buffers in `fx`, provided that `aout.length > 0` + * and `fx.length > 0` respectively. + * If `aout.length/2 < synth.count_audio_channels()` it will wrap around. + * Same is true for effects audio if + * `fx.length/2 < (synth.count_effects_channels() * synth.count_effects_groups()). + * See usage examples below. + * + * **Note:** Should only be called from synthesis thread. + * + * @see Fluid.AudioDriver.with_audio_callback + * @param len Count of audio frames to synthesize and store in every + * single buffer provided by out and fx. Zero value is permitted, + * the function does nothing and return {@link FLUID.OK}. + * @param fx Array of buffers to store effects audio to. Buffers may + * alias with buffers of `out`. Individual NULL buffers are permitted + * and will cause to skip mixing any audio into that buffer. + * @param aout Array of buffers to store (dry) audio to. Buffers may + * alias with buffers of `fx`. Individual NULL buffers are permitted and + * will cause to skip mixing any audio into that buffer + * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise, + * * `fx == NULL` while `fx.length > 0`, or `out == NULL` while `nout > 0`. + * * `nfx` or `aout.length` not multiple of 2. + * * `len < 0` + * * `fx.length` or `aout.length` exceed the range explained above. + */ + public int process (int len, [CCode (array_length_pos = 1.1)] float*[] fx, [CCode (cname = "out", array_length_pos = 2.1)] float*[] aout); + + // Effect - Chorus + public int chorus_on (int fx_group, bool on); + public int get_chorus_group_depth (int fx_group, out double depth_ms); + public int get_chorus_group_level (int fx_group, out double level); + public int get_chorus_group_nr (int fx_group, out int nr); + public int get_chorus_group_speed (int fx_group, out double speed); + public int get_chorus_group_type (int fx_group, out ChorusMod type); + public int set_chorus_group_depth (int fx_group, double depth_ms); + public int set_chorus_group_level (int fx_group, double level); + public int set_chorus_group_nr (int fx_group, int nr); + public int set_chorus_group_speed (int fx_group, double speed); + public int set_chorus_group_type (int fx_group, ChorusMod type); + + // Effect - Reverb + public int get_reverb_group_damp (int fx_group, out double damping); + public int get_reverb_group_level (int fx_group, out double level); + public int get_reverb_group_roomsize (int fx_group, out double roomsize); + public int get_reverb_group_width (int fx_group, out double width); + public int reverb_on (int fx_group, bool on); + public int set_reverb_group_damp (int fx_group, double damping); + public int set_reverb_group_level (int fx_group, double level); + public int set_reverb_group_roomsize (int fx_group, double roomsize); + public int set_reverb_group_width (int fx_group, double width); + + // Effect - IIR Filter + public int set_custom_filter (IIRFilterTypes type, IIRFilterFlags flags); + + // Effect - LADSPA + public LADSPAFx get_ladspa_fx (); + + // MIDI Channel Messages + public int all_notes_off (int chan); + public int all_sounds_off (int chan); + public int bank_select (int chan, int bank); + /** + * Send a MIDI controller event on a MIDI channel. + * + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param num MIDI controller number (0-127) + * @param val MIDI controller value (0-127) + * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise + */ + public int cc (int chan, int num, int val); + public int channel_pressure (int chan, int val); + public int get_cc (int chan, int num, out int pval); + public float get_gen (int chan, GenType param); + public int get_pitch_bend (int chan, out int ppitch_bend); + public int get_pitch_wheel_sens (int chan, out int pval); + public int get_program (int chan, out int sfont_id, out int back_num, out int preset_num); + public int key_pressure (int chan, int key, int val); + public int noteoff (int chan, int key); + public int noteon (int chan, int key, int vel); + public int pitch_bend (int chan, int val); + public int pitch_wheel_sens (int chan, int val); + public int program_change (int chan, int program); + public int program_reset (); + /** + * Select an instrument on a MIDI channel by SoundFont ID, bank and program numbers. + * + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param sfont_id ID of a loaded SoundFont + * @param bank_num MIDI bank number + * @param preset_num MIDI program number + * @return {@link Fluid.OK} on success, {@link Fluid.FAILED} otherwise + */ + public int program_select (int chan, int sfont_id, int bank_num, int preset_num); + public int program_select_by_sfont_name (int chan, string sfont_name, int bank_num, int preset_num); + public int set_gen (int chan, GenType param, float value); + public int sfont_select (int chan, int sfont_id); + public int sysex (uint8[] data, int len, char* response, out int response_len, out bool handled, int dryrun); + public int system_reset (); + public int unset_program (int chan); + + // MIDI Channel Setup + public int get_breath_mode (int chan, out ChannelBreathFlags breathmode); + public int get_legato_mode (int chan, out ChannelLegatoMode legatomode); + public int get_portamento_mode (int chan, out ChannelPortamentoMode portamentomode); + public int set_channel_type (int chan, MIDIChannelType type); + public int reset_basic_channel (int chan); + public int set_basic_channel (int chan, BasicChannelModes mode, int val); + public int set_breath_mode (int chan, ChannelBreathFlags breathmode); + public int set_legato_mode (int chan, ChannelLegatoMode legatomode); + public int set_portamento_mode (int chan, ChannelPortamentoMode portamentomode); + + // MIDI Tuning + public int activate_tuning (int chan, int bank, int prog, bool apply); + public int deactivate_tuning (int chan, bool apply); + public bool tuning_iteration_next (out int bank, out int prog); + public void tuning_iteration_start (); + + // Soundfont Management + /** + * Load a SoundFont file (filename is interpreted by SoundFont loaders). + * + * The newly loaded SoundFont will be put on top of the SoundFont stack. + * Presets are searched starting from the SoundFont on the top of the + * stack, working the way down the stack until a preset is found. + * + * **Note:** Since FluidSynth 2.2.0 `filename` is treated as an UTF8 + * encoded string on Windows. FluidSynth will convert it to wide-char + * internally and then pass it to `_wfopen()`. Before `FluidSynth 2.2.0`, + * filename was treated as ANSI string on Windows. All other platforms + * directly pass it to `fopen()` without any conversion + * (usually, UTF8 is accepted). + * + * @param filename File to load + * @param reset_presets TRUE to re-assign presets for all MIDI channels + * (equivalent to calling {@link Fluid.Synth.program_reset}) + * @return SoundFont ID on success, {@link Fluid.FAILED} on error + */ + public int sfload (string filename, bool reset_presets); + public int add_sfont (SoundFont? sfont); + public unowned Preset get_channel_preset (int chan); + public int get_bank_offset (int sfont_id); + public unowned SoundFont? get_sfont (uint num); + public unowned SoundFont? get_sfont_by_id (int id); + public unowned SoundFont? get_sfont_by_name (string name); + public int remove_sfont (SoundFont? sfont); + public int set_bank_offset (int sfont_id, int offset); + public int sfcount (); + public int sfreload (int id); + public int sfunload (int id, bool reset_presets); + + public int handle_midi_event (MIDIEvent? event); + + // Synthesis Parameters + /** Get the internal synthesis buffer size value. */ + public int get_internal_bufsize (); + } + + /** + * Functions for settings management. + */ + [Compact] + [CCode (cname = "fluid_settings_t", cprefix = "fluid_settings_", free_function = "delete_fluid_settings", has_type_id = false)] + public class Settings { + [CCode (cname = "new_fluid_settings")] + public Settings (); + public int copystr (string name, out string str, int len); + public int dupstr (string name, out string str); + public void foreach (void* data, foreach_t func); + public void foreach_option (string name, void* data, foreach_option_t func); + public int get_hints (string name, out int hints); + public Types get_type (string name); + public int getint (string name, out int val); + public int getint_default (string name, out int val); + public int getint_range (string name, out int min, out int max); + public int getnum (string name, out double val); + public int getnum_default (string name, out double val); + public int getnum_range (string name, out double min, out double max); + public int getstr_default (string name, out string def); + public bool is_realtime (string name); + public string option_concat (string name, string separator); + public int option_count (string name); + public int setint (string name, int val); + public int setnum (string name, double val); + public int setstr (string name, string str); + public bool str_equal (string name, string s); + + [SimpleType] + [CCode (has_target = false)] + public delegate void foreach_option_t (void* data, string name, string option); + + [SimpleType] + [CCode (has_target = false)] + public delegate void foreach_t (void* data, string name, int type); + } + + [Compact] + [CCode (cname = "fluid_sfont_t", cprefix = "fluid_sfont_", free_function = "delete_fluid_sfont", has_type_id = false)] + public class SoundFont { + public unowned string get_name (); + public unowned Preset get_preset (int bank, int prenum); + public void iteration_start (); + public unowned Preset? iteration_next (); + } + + [Compact] + [CCode (cname = "fluid_preset_t", cprefix = "fluid_preset_", free_function = "delete_fluid_preset", has_type_id = false)] + public class Preset { + public int get_banknum (); + public unowned void* get_data (); + public unowned string get_name (); + public int get_num (); + public unowned SoundFont get_sfont (); + public int set_data (void* data); + } + + /** + * Functions for managing audio drivers. + */ + [Compact] + [CCode (cname = "fluid_audio_driver_t", cprefix = "fluid_audio_", free_function = "delete_fluid_audio_driver", has_type_id = false)] + public class AudioDriver { + /** + * Create a new audio driver. + * + * Creates a new audio driver for a given `synth` instance with a defined + * set of configuration `settings`. The `settings` instance must be the same + * that you have passed to {@link Fluid.AudioDriver.AudioDriver} when + * creating the `synth` instance. Otherwise the behaviour is undefined + * + * **Note:** As soon as an audio driver is created, the `synth` starts + * rendering audio. This means that all necessary initialization and + * sound-setup should have been completed before calling this function. + * Thus, of all object types in use (synth, midi player, sequencer, etc.) + * the audio driver should always be the last one to be created and the + * first one to be deleted! Also refer to the order of object creation + * in the code examples. + * + * @param settings Configuration settings used to select and create the audio driver. + * @param synth Synthesizer instance for which the audio driver is created for. + */ + [CCode (cname = "new_fluid_audio_driver")] + public AudioDriver (Settings? settings, Synth? synth); + /** + * Create a new audio driver. + * + * Like {@link Fluid.AudioDriver.AudioDriver} but allows for custom audio + * processing before audio is sent to audio driver. It is the + * responsibility of the callback func to render the audio into the + * buffers. If func uses a {@link Fluid.Synth} synth, the settings instance must + * be the same that you have passed to {@link Fluid.Synth.Synth} when + * creating the synth instance. Otherwise the behaviour is undefined. + * + * **Note:** Not as efficient as {@link Fluid.AudioDriver.AudioDriver}. + * As soon as an audio driver is created, a new thread is spawned starting + * to make callbacks to func. This means that all necessary sound-setup + * should be completed after this point, thus of all object types in use + * (synth, midi player, sequencer, etc.) the audio driver should always + * be the last one to be created and the first one to be deleted! + * Also refer to the order of object creation in the code examples. + * + * @param settings Configuration settings used to select and create the audio driver. + * @param func Function called to fill audio buffers for audio playback + * @param User defined data pointer to pass to `func` + */ + [CCode (cname = "new_fluid_audio_driver2")] + public AudioDriver.with_audio_callback (Settings? settings, handle_audio_func_t func, void* data); + } + + /** + * Parse standard MIDI files and emit MIDI events. + */ + [Compact] + [CCode (cname = "fluid_player_t", cprefix = "fluid_player_", free_function = "delete_fluid_player", has_type_id = false)] + public class Player { + [CCode (cname = "new_fluid_player")] + public Player (Synth? synth); + + public int bpm { + get { + return get_bpm (); + } + } + + public int midi_tempo { + get { + return get_midi_tempo (); + } + } + + public int current_tick { + get { + return get_current_tick (); + } + } + + public int total_ticks { + get { + return get_total_ticks (); + } + } + + public int loop { + set { + set_loop (value); + } + } + + public int add (string midifile); + public int add_mem (void* buffer, size_t len); + public int get_bpm (); + public int get_current_tick (); + public int get_midi_tempo (); + public PlayerStatus get_status (); + public int get_total_ticks (); + public int join (); + public int play (); + public int seek (int ticks); + public int set_loop (int loop); + public int set_playback_callback (handle_midi_event_func_t handler, void* handler_data); + public int set_tempo (TempoType tempo_type, double tempo); + public int set_tick_callback (handle_midi_tick_func_t handler, void* handler_data); + public int stop (); + } + + /** + * Functions to create, modify, query and delete MIDI events. + */ + [Compact] + [CCode (cname = "fluid_midi_event_t", cprefix = "fluid_midi_event_", free_function = "delete_fluid_midi_event", has_type_id = false)] + public class MIDIEvent { + [CCode (cname = "new_fluid_midi_event")] + public MIDIEvent (); + + public int get_channel (); + public int get_control (); + public int get_key (); + public int get_lyrics (void** data, out int size); + public int get_pitch (); + public int get_program (); + public int get_text (void** data, out int size); + public int get_type (); + public int get_value (); + public int get_velocity (); + + public int set_channel (int chan); + public int set_control (int v); + public int set_key (int v); + public int set_lyrics (void* data, int size, bool dynamic); + public int set_pitch (int val); + public int set_program (int val); + public int set_text (void* data, int size, bool dynamic); + public int set_sysex (void* data, int size, bool dynamic); + public int set_type (int type); + public int set_value (int v); + public int set_velocity (int v); + } + + /** + * Functions for managing MIDI drivers. + */ + [Compact] + [CCode (cname = "fluid_midi_driver_t", cprefix = "fluid_midi_driver_", free_function = "delete_fluid_midi_driver", has_type_id = false)] + public class MIDIDriver { + [CCode (cname = "new_fluid_midi_driver")] + public MIDIDriver (Settings? settings, handle_midi_event_func_t handler, void* event_handler_data); + } + + /** + * Rule based transformation and filtering of MIDI events. + */ + [Compact] + [CCode (cname = "fluid_midi_router_t", cprefix = "fluid_midi_router_", free_function = "delete_fluid_midi_router", has_type_id = false)] + public class MIDIRouter { + [CCode (cname = "new_fluid_midi_router")] + public MIDIRouter (Settings settings, handle_midi_event_func_t handler, void* event_handler_data); + + [CCode (has_target = false)] + public int dump_postrouter (void* data, MIDIEvent event); + [CCode (has_target = false)] + public int dump_prerouter (void* data, MIDIEvent event); + public int add_rule (MIDIRouterRule rule, MIDIRouterRuleType type); + public int clear_rules (); + [CCode (has_target = false)] + public int handle_midi_event (MIDIEvent event); + public int set_default_rules (); + } + + /** + * MIDI ROuter Rule + */ + [Compact] + [CCode (cname = "fluid_midi_router_rule_t", cprefix = "fluid_midi_router_rule_", free_function = "delete_fluid_midi_router_rule", has_type_id = false)] + public class MIDIRouterRule { + [CCode (cname = "new_fluid_midi_router_rule")] + public MIDIRouterRule (); + + public void set_chan (int min, int max, float mul, int add); + public void set_param1 (int min, int max, float mul, int add); + public void set_param2 (int min, int max, float mul, int add); + } + + /** + * Functions for configuring the LADSPA effects unit. + */ + [Compact] + [CCode (cname = "fluid_ladpsa_fx_t", cprefix = "fluid_ladpsa_", has_type_id = false)] + public class LADSPAFx { + public int activate (); + public int add_buffer (string name); + public int add_effect (string effect_name, string lib_name, string plugin_name); + public bool buffer_exists (string name); + public int check (char* err, int err_size); + public int deactivate (); + public bool effect_can_mix (string name); + public int effect_link (string effect_name, string port_name, string name); + public bool effect_port_exists (string effect_name, string port_name); + public int effect_set_control (string effect_name, string port_name, float val); + public int effect_set_mix (string name, int mix, float gain); + public bool host_port_exists (string name); + public bool is_active (); + public int reset (); + } +} diff --git a/vapi/libpipewire-0.3.vapi b/vapi/libpipewire-0.3.vapi new file mode 100644 index 00000000..0f84a79e --- /dev/null +++ b/vapi/libpipewire-0.3.vapi @@ -0,0 +1,27 @@ +[CCode(cheader_filename="pipewire/pipewire.h", cprefix = "pw_", lower_case_cprefix="pw_")] +namespace Pipewire { + void init (int* argc = null, string** argv = null); + void deinit (); + string get_application_name (); + string get_prgname (); + string get_user_name (); + string get_host_name (); + string get_client_name (); + bool in_valgrind (); + bool check_option (string option, string value); + SPADirection direction_reverse (SPADirection direction); + int set_domain (string domain); + string get_domain (); + + [CCode (cname = "enum spa_direction", has_type_id = false, cprefix = "SPA_DIRECTION_")] + public enum SPADirection { + INPUT, + OUTPUT + } + + + [CCode (cprefix = "pw_debug_")] + namespace Debug { + bool is_category_enabled (string name); + } +} diff --git a/vapi/lilv-0.vapi b/vapi/lilv-0.vapi new file mode 100644 index 00000000..3142c51b --- /dev/null +++ b/vapi/lilv-0.vapi @@ -0,0 +1,279 @@ +/* + Copyright 2007-2011 David Robillard + Copyright 2011 Artem Popov + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +// vala port of lv2jack.c + +[CCode(cheader_filename="lilv/lilv.h", cprefix="Lilv", lower_case_cprefix="lilv_")] +namespace Lilv { + + [CCode (cname = "LilvUISupportedFunc", has_target = false)] + public delegate uint UISupportedFunc (string container_type_uri, string ui_type_uri); + + [CCode (cprefix = "LILV")] + namespace NS { + public const string DOAP; + public const string FOAF; + public const string LILV; + public const string LV2; + public const string RDF; + public const string RDFS; + public const string XSD; + } + + [CCode (cprefix = "LILV")] + namespace URI { + public const string AUDIO_PORT; + public const string CONTROL_PORT; + public const string EVENT_PORT; + public const string INPUT_PORT; + public const string MIDI_EVENT; + public const string OUTPUT_PORT; + public const string PORT; + } + + [CCode (cprefix = "LILV")] + namespace OPTION { + public const string FILTER_LANG; + public const string DYN_MANIFEST; + } + + public static unowned string uri_to_path(string uri); + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class Plugin { + public bool verify(); + public unowned Node get_uri(); + public unowned Node get_bundle_uri(); + public unowned Nodes get_data_uris(); + public unowned Node get_library_uri(); + public Node get_name(); + public unowned PluginClass get_class(); + public Nodes get_value(Node predicate); + public bool has_feature(Node feature_uri); + public bool has_extension_data(Node uri); + public Nodes get_supported_features(); + public Nodes get_required_features(); + public Nodes get_optional_features(); + public uint32 get_num_ports(); + public void get_port_ranges_float(ref float[] min_values, ref float[] max_values, ref float[] def_values); + public uint32 get_num_ports_of_class(Node class_1, ...); + public bool has_latency(); + public uint32 get_latency_port_index(); + public unowned Port get_port_by_index(uint32 index); + public unowned Port get_port_by_symbol(Node symbol); + public Node? get_author_name(); + public Node? get_author_email(); + public Node? get_author_homepage(); + public bool is_replaced(); + + public Instance? instantiate(double sample_rate, + [CCode (array_length = false, array_null_terminated = true)] LV2.Feature*[] features); + public UIs get_uis(); + } + + [Compact] + [CCode (free_function = "")] + public class PluginClass { + [CCode (cname = "lilv_plugin_class_get_parent_uri")] + public unowned Node get_parent_uri(); + [CCode (cname = "lilv_plugin_class_get_uri")] + public unowned Node get_uri(); + [CCode (cname = "lilv_plugin_class_get_label")] + public unowned Node get_label(); + [CCode (cname = "lilv_plugin_class_get_children")] + public PluginClasses get_children(); + } + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class Port { + [CCode (instance_pos=1.5)] + public unowned Node get_node (Plugin plugin); + [CCode (instance_pos=1.5)] + public Nodes get_value (Plugin plugin, Node predicate); + [CCode (cname="lilv_plugin_get", instance_pos=1.5)] + public unowned Node get_property (Plugin plugin, Node predicate); + [CCode (instance_pos=1.5)] + public Nodes get_properties (Plugin plugin); + [CCode (instance_pos=1.5)] + public bool has_property (Plugin plugin, Node property); + [CCode (instance_pos=1.5)] + public bool supports_event (Plugin plugin, Node event_type); + [CCode (instance_pos=1.5)] + public uint32 get_index (Plugin plugin); + [CCode (instance_pos=1.5)] + public unowned Node get_symbol (Plugin plugin); + [CCode (instance_pos=1.5)] + public unowned Node get_name (Plugin plugin); + [CCode (instance_pos=1.5)] + public unowned Nodes get_classes (Plugin plugin); + [CCode (instance_pos=1.5)] + public bool is_a (Plugin plugin, Node port_class); + [CCode (instance_pos=1.5)] + public void get_range (Plugin plugin, out Node def, out Node min, out Node max); + [CCode (instance_pos=1.5)] + public ScalePoints get_scale_points (Plugin plugin); + } + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class ScalePoint { + public unowned Node get_label(); + public unowned Node get_value(); + } + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class UI { + public unowned Node get_uri(); + public unowned Nodes get_classes(); + public bool is_a(Node class_uri); + public uint is_supported(UISupportedFunc supported_func, Node container_type, out Node ui_type); + public unowned Node get_bundle_uri(); + public unowned Node get_binary_uri(); + } + + [Compact] + [CCode (free_function = "lilv_node_free")] + public class Node { + [CCode(cname="lilv_new_uri")] + public Node.uri(World world, string uri); + [CCode(cname="lilv_new_string")] + public Node.string(World world, string str); + [CCode(cname="lilv_new_int")] + public Node.int(World world, int val); + [CCode(cname="lilv_new_float")] + public Node.float(World world, float val); + [CCode(cname="lilv_new_bool")] + public Node.bool(World world, bool val); + [CCode(cname="lilv_file_uri_parse")] + public static string file_uri_parse (string uri, [CCode (array_length = false, array_null_terminated = true)] string[]? hostname = null); + + public Node duplicate(); + public bool equals(Node other); + public string get_turtle_token(); + + public bool is_uri(); + public unowned string as_uri(); + public bool is_blank(); + public unowned string as_blank(); + public bool is_literal(); + public bool is_string(); + public unowned string as_string(); + public bool is_float(); + public float as_float(); + public bool is_int(); + public int as_int(); + public bool is_bool(); + public bool as_bool(); + } + + [Compact] + [CCode (free_function = "lilv_world_free")] + public class World { + public World(); + public void set_option(string uri, Node value); + public void load_all(); + public void load_bundle(Node bundle_uri); + public unowned PluginClass get_plugin_class(); + public unowned PluginClasses get_plugin_classes(); + public unowned Plugins get_all_plugins(); + public Nodes find_nodes(Node subject, Node predicate, Node object); + } + + [Compact] + [CCode (free_function = "lilv_instance_free")] + public class Instance { + public unowned string get_uri(); + public void connect_port(uint32 port_index, void* data_location); + public void activate(); + public void run(uint32 sample_count); + public void deactivate(); + public void* get_extension_data(string uri); + public unowned LV2.Descriptor get_descriptor(); + public unowned LV2.Handle get_handle(); + } + + // Collections + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class Iter { + } + + [Compact] + [CCode (free_function = "lilv_plugin_classes_free")] + public class PluginClasses { + public uint size(); + public Iter begin(); + public unowned PluginClass? get(Iter i); + public Iter next(Iter i); + public bool is_end(Iter i); + public unowned PluginClass? get_by_uri(Node uri); + } + + [Compact] + [Immutable] + [CCode (free_function = "")] + public class Plugins { + public uint size(); + public Iter begin(); + public unowned Plugin? get(Iter i); + public Iter next(Iter i); + public bool is_end(Iter i); + public unowned Plugin? get_by_uri(Node uri); + } + + [Compact] + [CCode (free_function = "lilv_scale_points_free")] + public class ScalePoints { + public uint size(); + public Iter begin(); + public unowned ScalePoint? get(Iter i); + public Iter next(Iter i); + public bool is_end(Iter i); + } + + [Compact] + [CCode (free_function = "lilv_uis_free")] + public class UIs { + public uint size(); + public Iter begin(); + public unowned UI? get(Iter i); + public Iter next(Iter i); + public bool is_end(Iter i); + public unowned UI? get_by_uri(Node uri); + } + + [Compact] + [CCode (free_function = "lilv_nodes_free")] + public class Nodes { + public uint size(); + public Iter begin(); + public unowned Node? get(Iter i); + public Iter next(Iter i); + public bool is_end(Iter i); + public Node? get_first(); // unowned? + public bool contains(Node value); + } +} diff --git a/vapi/lv2.vapi b/vapi/lv2.vapi new file mode 100644 index 00000000..ad5af79e --- /dev/null +++ b/vapi/lv2.vapi @@ -0,0 +1,959 @@ +/* + * Copyright 2020-2023 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ +/* + * This file incorporates work covered by the following copyright and + * permission notices: + * + * --- + * + Copyright 2006-2012 Steve Harris, David Robillard. + Copyright 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + * + * --- + */ + +// LV2 Core //////////////////////////////////////////////////////////////////// +[CCode(cheader_filename="lv2.h", cprefix="LV2_", lower_case_cprefix="lv2_")] +namespace LV2 { + [CCode(cname="LV2_Feature", has_destroy_function=false, has_copy_function=false)] + public struct Feature { + string URI; + void* data; + } + + public struct Descriptor { + string URI; + } + + [SimpleType] + public struct Handle { + } + + public class Core { + public const string URI; + public const string PREFIX; + + public const string _AllpassPlugin; + public const string _AmplifierPlugin; + public const string _AnalyserPlugin; + public const string _AudioPort; + public const string _BandpassPlugin; + public const string _CVPort; + public const string _ChorusPlugin; + public const string _CombPlugin; + public const string _CompressorPlugin; + public const string _ConstantPlugin; + public const string _ControlPort; + public const string _ConverterPlugin; + public const string _DelayPlugin; + public const string _DistortionPlugin; + public const string _DynamicsPlugin; + public const string _EQPlugin; + public const string _EnvelopePlugin; + public const string _ExpanderPlugin; + public const string _ExtensionData; + public const string _Feature; + public const string _FilterPlugin; + public const string _FlangerPlugin; + public const string _FunctionPlugin; + public const string _GatePlugin; + public const string _GeneratorPlugin; + public const string _HighpassPlugin; + public const string _InputPort; + public const string _InstrumentPlugin; + public const string _LimiterPlugin; + public const string _LowpassPlugin; + public const string _MixerPlugin; + public const string _ModulatorPlugin; + public const string _MultiEQPlugin; + public const string _OscillatorPlugin; + public const string _OutputPort; + public const string _ParaEQPlugin; + public const string _PhaserPlugin; + public const string _PitchPlugin; + public const string _Plugin; + public const string _PluginBase; + public const string _Point; + public const string _Port; + public const string _PortProperty; + public const string _Resource; + public const string _ReverbPlugin; + public const string _ScalePoint; + public const string _SimulatorPlugin; + public const string _SpatialPlugin; + public const string _Specification; + public const string _SpectralPlugin; + public const string _UtilityPlugin; + public const string _WaveshaperPlugin; + public const string _appliesTo; + public const string _binary; + public const string _connectionOptional; + public const string _control; + public const string _default; + public const string _designation; + public const string _documentation; + public const string _enabled; + public const string _enumeration; + public const string _extensionData; + public const string _freeWheeling; + public const string _hardRTCapable; + public const string _inPlaceBroken; + public const string _index; + public const string _integer; + public const string _isLive; + public const string _latency; + public const string _maximum; + public const string _microVersion; + public const string _minimum; + public const string _minorVersion; + public const string _name; + public const string _optionalFeature; + public const string _port; + public const string _portProperty; + public const string _project; + public const string _prototype; + public const string _reportsLatency; + public const string _requiredFeature; + public const string _sampleRate; + public const string _scalePoint; + public const string _symbol; + public const string _toggled; + } +} + + + +// Extensions ////////////////////////////////////////////////////////////////// + +/** + * User interfaces of any type for plugins. + * See for details. + */ +[CCode (cheader_filename = "lv2/lv2plug.in/ns/extensions/ui/ui.h")] +namespace LV2.UI { + public const string URI; + + public const string PREFIX; + + public const string _CocoaUI; + public const string _Gtk3UI; + public const string _GtkUI; + public const string _PortNotification; + public const string _PortProtocol; + public const string _Qt4UI; + public const string _Qt5UI; + public const string _UI; + public const string _WindowsUI; + public const string _X11UI; + public const string _binary; + public const string _fixedSize; + public const string _idleInterface; + public const string _noUserResize; + public const string _notifyType; + public const string _parent; + public const string _plugin; + public const string _portIndex; + public const string _portMap; + public const string _portNotification; + public const string _portSubscribe; + public const string _protocol; + public const string _requestValue; + public const string _floatProtocol; + public const string _peakProtocol; + public const string _resize; + public const string _showInterface; + public const string _touch; + public const string _ui; + public const string _updateRate; + public const string _windowTitle; + public const string _scaleFactor; + public const string _foregroundColor; + public const string _backgroundColor; + + [CCode (cname = "LV2UI_INVALID_PORT_INDEX")] + public const uint32 INVALID_PORT_INDEX; + + [SimpleType] + [CCode (cname = "LV2UI_Widget")] + public struct Widget { + } + + [SimpleType] + [CCode (cname = "LV2UI_Handle")] + public struct Handle { + } +} + + +[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/urid/urid.h")] +namespace LV2.URID { + [SimpleType] + [CCode (cname = "LV2_URID_Map_Handle")] + public struct MapHandle { + } + + [SimpleType] + [CCode (cname = "LV2_URID_Unmap_Handle")] + public struct UnmapHandle { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "LV2_URID", has_type_id = false)] + public struct Urid { + } + + [CCode(instance_pos=0)] + public delegate Urid UridMapFunc (string uri); + [CCode(instance_pos=0)] + public delegate string UridUnmapFunc (Urid urid); + + [CCode (cname = "LV2_URID_Map", destroy_function = "")] + public struct UridMap { + [CCode (cname = "handle")] + public MapHandle handle; + [CCode (cname = "map", has_target = false, delegate_target_cname = "handle")] + public unowned UridMapFunc map; + } + + [CCode (cname = "LV2_URID_Unmap", destroy_function = "")] + public struct UridUnmap { + [CCode (cname = "handle")] + public UnmapHandle handle; + [CCode (cname = "unmap", has_target = false, delegate_target_cname = "handle")] + public unowned UridUnmapFunc unmap; + } + + public const string URI; + public const string PREFIX; + + public const string _map; + public const string _unmap; +} + + +[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/atom/atom.h")] +namespace LV2.Atom { + public const string URI; + + public const string PREFIX; + + public const string _Atom; + public const string _AtomPort; + public const string _Blank; + public const string _Bool; + public const string _Chunk; + public const string _Double; + public const string _Event; + public const string _Float; + public const string _Int; + public const string _Literal; + public const string _Long; + public const string _Number; + public const string _Object; + public const string _Path; + public const string _Property; + public const string _Resource; + public const string _Sequence; + public const string _Sound; + public const string _String; + public const string _Tuple; + public const string _URI; + public const string _URID; + public const string _Vector; + public const string _atomTransfer; + public const string _beatTime; + public const string _bufferType; + public const string _childType; + public const string _eventTransfer; + public const string _frameTime; + public const string _supports; + public const string _timeUnit; + + [CCode (cname = "LV2_ATOM_CONTENTS", generic_type_pos = 0)] + public static unowned void* contents (T atom); + + [CCode (cname = "LV2_ATOM_BODY", generic_type_pos = 0)] + public static unowned void* body (Atom atom); + + [CCode (cname = "LV2_Atom", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Atom { + uint32 size; + uint32 type; + } + + [CCode (cname = "LV2_Atom_Int", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Int { + Atom atom; + int32 body; + } + + [CCode (cname = "LV2_Atom_Long", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Long { + Atom atom; + int64 body; + } + + [CCode (cname = "LV2_Atom_Float", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Float { + Atom atom; + float body; + } + + [CCode (cname = "LV2_Atom_Double", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Double { + Atom atom; + double body; + } + + [SimpleType] + [CCode (cname = "LV2_Atom_Bool", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Bool : Int {} + + [CCode (cname = "LV2_Atom_URID", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct URID { + Atom atom; + uint32 body; + } + + [CCode (cname = "LV2_Atom_String", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct String { + Atom atom; + } + + [CCode (cname = "LV2_Atom_Literal_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct LiteralBody { + uint32 datatype; + uint32 lang; + } + + [CCode (cname = "LV2_Atom_Literal", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Literal { + Atom atom; + LiteralBody body; + } + + [CCode (cname = "LV2_Atom_Tuple", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Tuple { + Atom atom; + } + + [CCode (cname = "LV2_Atom_Vector_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct VectorBody { + uint32 child_size; + uint32 child_type; + } + + [CCode (cname = "LV2_Atom_Vector", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Vector { + Atom atom; + VectorBody body; + } + + [CCode (cname = "LV2_Atom_Property_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct PropertyBody { + uint32 key; + uint32 context; + Atom value; + } + + [CCode (cname = "LV2_Atom_Property", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Property { + Atom atom; + PropertyBody body; + } + + [CCode (cname = "LV2_Atom_Object_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct ObjectBody { + uint32 id; + uint32 otype; + } + + [CCode (cname = "LV2_Atom_Object", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Object { + Atom atom; + ObjectBody body; + } + + [CCode (cname = "LV2_Atom_Event", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Event { + [CCode (cname = "time.frames")] + int64 time_frames; + [CCode (cname = "time.beats")] + double time_beats; + Atom body; + } + + + [CCode (cname = "LV2_Atom_Sequence_Body", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct SequenceBody { + uint32 unit; + uint32 pad; + } + + [CCode (cname = "LV2_Atom_Sequence", destroy_function = "", has_type_id = false, has_copy_function = false)] + public struct Sequence { + Atom atom; + SequenceBody body; + } +} + +[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/midi/midi.h")] +namespace LV2.MIDI { + public const string URI; + + public const string PREFIX; + + public const string _ActiveSense; + public const string _Aftertouch; + public const string _Bender; + public const string _Chunk; + public const string _Continue; + public const string _Controller; + public const string _MidiEvent; + public const string _NoteOff; + public const string _NoteOn; + public const string _ProgramChange; + public const string _QuarterFrame; + public const string _Reset; + public const string _SongPosition; + public const string _SongSelect; + public const string _Start; + public const string _Stop; + public const string _SystemCommon; + public const string _SystemExclusive; + public const string _SystemMessage; + public const string _SystemRealtime; + public const string _Tick; + public const string _TuneRequest; + public const string _VoiceMessage; + public const string _benderValue; + public const string _binding; + public const string _byteNumber; + public const string _channel; + public const string _chunk; + public const string _controllerNumber; + public const string _controllerValue; + public const string _noteNumber; + public const string _pressure; + public const string _programNumber; + public const string _property; + public const string _songNumber; + public const string _songPosition; + public const string _status; + public const string _statusMask; + public const string _velocity; + + [CCode (ctype="inline")] + public static bool is_voice_message (uint8 msg); + + [CCode (ctype="inline")] + public static bool is_system_message (uint8 msg); + + [CCode (ctype="inline")] + public static uint8 message_type (uint8 msg); +} + +[CCode(cheader_filename="lv2/lv2plug.in/ns/ext/worker/worker.h")] +namespace LV2.Worker { + public const string URI; + + public const string PREFIX; + + public const string _interface; + public const string _schedule; + + [CCode (cname = "interface_work_t", has_target = false)] + public delegate Status InterfaceWorkFunc (LV2.Handle instance, RespondFunc respond, RespondHandle handle, uint32 size, [CCode (type="const void*")] void* data); + + [CCode (cname = "interface_work_reponse_t", has_target = false)] + public delegate Status InterfaceWorkResponseFunc (LV2.Handle instance, uint32 size, [CCode (type="const void*")] void* body); + + [CCode (cname = "interface_end_run_t", has_target = false)] + public delegate Status InterfaceEndRunFunc (LV2.Handle instance); + + [Compact] + [SimpleType] + [CCode (cname = "LV2_Worker_Interface", has_type_id = false, free_function = "")] + public class Interface { + [CCode (cname = "work", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned InterfaceWorkFunc work; + [CCode (cname = "work_response", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned InterfaceWorkResponseFunc work_response; + [CCode (cname = "end_run", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned InterfaceEndRunFunc end_run; + } + + /* Status code for worker functions. */ + [CCode (cname = "LV2_Worker_Status", has_type_id = false, cprefix = "LV2_WORKER_")] + public enum Status { + /** Completed successfully. */ + SUCCESS = 0, + /** Unknown error. */ + ERR_UNKNOWN = 1, + /** Failed due to lack of space. */ + ERR_NO_SPACE = 2 + } + + [SimpleType] + [CCode (cname = "LV2_Worker_Respond_Handle")] + public struct RespondHandle { + } + + [SimpleType] + [CCode (cname = "LV2_Worker_Respond_Function", has_target = false)] + public delegate Status RespondFunc (RespondHandle handle, uint32 size, [CCode (type="const void*")] void* data); + + [SimpleType] + [CCode (cname = "LV2_Worker_Schedule_Handle")] + public struct ScheduleHandle { + } + + [CCode (instance_pos = 0)] + public delegate Status SchedulerFunc (uint32 size, void* data); + + [CCode (cname = "LV2_Worker_Schedule", destroy_function = "")] + public struct Schedule { + [CCode (cname = "handle")] + public ScheduleHandle handle; + [CCode (cname = "schedule_work", has_target = false, delegate_target_cname = "handle")] + public unowned SchedulerFunc schedule_work; + } + +} + + +[CCode(cheader_filename="lv2/units/units.h")] +namespace LV2.Units { + public const string URI; + + public const string PREFIX; + + public const string _Conversion; + public const string _Unit; + public const string _bar; + public const string _beat; + public const string _bpm; + public const string _cent; + public const string _cm; + public const string _coef; + public const string _conversion; + public const string _db; + public const string _degree; + public const string _frame; + public const string _hz; + public const string _inch; + public const string _khz; + public const string _km; + public const string _m; + public const string _mhz; + public const string _midiNote; + public const string _mile; + public const string _min; + public const string _mm; + public const string _ms; + public const string _name; + public const string _oct; + public const string _pc; + public const string _prefixConversion; + public const string _render; + public const string _s; + public const string _semitone12TET; + public const string _symbol; + public const string _unit; +} + + +[CCode(cheader_filename="lv2/options/options.h")] +namespace LV2.Options { + public const string URI; + + public const string PREFIX; + + public const string _Option; + public const string _interface; + public const string _options; + public const string _requiredOption; + public const string _supportedOption; + + /** + * The context of an Option, which defines the subject it applies to. + */ + [CCode (cname = "LV2_Options_Context", has_type_id = false, cprefix = "LV2_OPTIONS_")] + public enum Context { + /** + * This option applies to the instance itself. + * + * The subject must be ignored. + */ + INSTANCE, + /** + * This option applies to some named resource. + * + * The subject is a URI mapped to an integer (a LV2_URID, like the key) + */ + RESOURCE, + /** + * This option applies to some blank node. + * + * The subject is a blank node identifier, which is valid only within the current local scope. + */ + BLANK, + /** + * This option applies to a port on the instance. + * + * The subject is the port's index. + */ + PORT + } + + /** + * A status code for option functions. + */ + [CCode (cname = "LV2_Options_Status", has_type_id = false, cprefix = "LV2_OPTIONS_")] + public enum Status { + SUCCESS, + ERR_UNKNOWN, + ERR_BAD_SUBJECT, + ERR_BAD_KEY, + ERR_BAD_VALUE + } + + /** + * An option. + * + * ---------- + * This is a property with a subject, also known as a triple or statement. + * + * This struct is useful anywhere a statement needs to be passed where no memory ownership issues are present + * (since the value is a const pointer). + * + * Options can be passed to an instance via the feature `LV2_OPTIONS__options` with data pointed to an array of + * options terminated by a zeroed option, or accessed/manipulated using `LV2_Options_Interface`. + */ + [SimpleType] + [CCode (cname = "LV2_Options_Option")] + public struct Option { + public Context context; + public uint32 subject; + public URID.Urid key; + public uint32 size; + public URID.Urid type; + public void* value; + } + + [CCode (cname = "lv2_options_interface_get_t", has_target = false)] + public delegate uint32 InterfaceGetFunc (LV2.Handle instance, out Option options); + + [CCode (cname = "lv2_options_interface_set_t", has_target = false)] + public delegate uint32 InterfaceSetFunc (LV2.Handle instance, Option options); + + /** + * Interface for dynamically setting options `(LV2_OPTIONS__interface)`. + */ + [Compact] + [SimpleType] + [CCode (cname = "LV2_Options_Interface", has_type_id = false, free_function = "")] + public class Interface { + /** + * Get the given options. + * + * ---------------------- + * Each element of the passed options array MUST have type, subject, and key set. All other fields (size, type, + * value) MUST be initialised to zero, and are set to the option value if such an option is found. + * + * This function is in the "instantiation" LV2 threading class, so no other instance functions may be called + * concurrently. + * + * @returns Bitwise OR of LV2_Options_Status values. + */ + [CCode (cname = "get", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned InterfaceGetFunc get; + /** + * Set the given options. + * + * ---------------------- + * This function is in the "instantiation" LV2 threading class, so no other instance functions may be called concurrently. + * + * @returns Bitwise OR of LV2_Options_Status values. + */ + [CCode (cname = "set", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned InterfaceSetFunc set; + } +} + + +[CCode(cheader_filename="lv2/parameters/parameters.h")] +namespace LV2.Parameters { + public const string URI; + + public const string PREFIX; + + public const string _CompressorControls; + public const string _ControlGroup; + public const string _EnvelopeControls; + public const string _FilterControls; + public const string _OscillatorControls; + public const string _amplitude; + public const string _attack; + public const string _bypass; + public const string _cutoffFrequency; + public const string _decay; + public const string _delay; + public const string _dryLevel; + public const string _frequency; + public const string _gain; + public const string _hold; + public const string _pulseWidth; + public const string _ratio; + public const string _release; + public const string _resonance; + public const string _sampleRate; + public const string _sustain; + public const string _threshold; + public const string _waveform; + public const string _wetDryRatio; + public const string _wetLevel; +} + + +[CCode(cheader_filename="lv2/buf-size/buf-size.h")] +namespace LV2.BufSize { + public const string URI; + + public const string PREFIX; + + public const string _boundedBlockLength; + public const string _coarseBlockLength; + public const string _fixedBlockLength; + public const string _maxBlockLength; + public const string _minBlockLength; + public const string _nominalBlockLength; + public const string _powerOf2BlockLength; + public const string _sequenceSize; +} + + +[CCode(cheader_filename="lv2/log/log.h")] +namespace LV2.Log { + public const string URI; + + public const string PREFIX; + + public const string _Entry; + public const string _Error; + public const string _Note; + public const string _Trace; + public const string _Warning; + public const string _log; + + [SimpleType] + [CCode (cname = "LV2_Log_Handle")] + public struct LogHandle { + } + + [CCode (instance_pos = 0)] + public delegate int PrintFunc (URID.Urid type, string fmt, ...); + + [CCode (instance_pos = 0)] + public delegate int VPrintFunc (URID.Urid type, string fmt, va_list ap); + + [CCode (cname = "LV2_Log_Log", destroy_function = "")] + public struct Log { + [CCode (cname = "handle")] + public LogHandle handle; + [CCode (cname = "printf", has_target = false, delegate_target_cname = "handle")] + public unowned PrintFunc printf; + [CCode (cname = "vprintf", has_target = false, delegate_target_cname = "handle")] + public unowned VPrintFunc vprintf; + } +} + + +[CCode(cheader_filename="lv2/patch/patch.h")] +namespace LV2.Patch { + public const string URI; + + public const string PREFIX; + + public const string _Ack; + public const string _Delete; + public const string _Copy; + public const string _Error; + public const string _Get; + public const string _Message; + public const string _Move; + public const string _Patch; + public const string _Post; + public const string _Put; + public const string _Request; + public const string _Response; + public const string _Set; + public const string _accept; + public const string _add; + public const string _body; + public const string _context; + public const string _destination; + public const string _property; + public const string _readable; + public const string _remove; + public const string _request; + public const string _subject; + public const string _sequenceNumber; + public const string _value; + public const string _wildcard; + public const string _writable; +} + + +[CCode(cheader_filename="lv2/time/time.h")] +namespace LV2.Time { + public const string URI; + + public const string PREFIX; + + public const string _Time; + public const string _Position; + public const string _Rate; + public const string _position; + public const string _barBeat; + public const string _bar; + public const string _beat; + public const string _beatUnit; + public const string _beatsPerBar; + public const string _beatsPerMinute; + public const string _frame; + public const string _framesPerSecond; + public const string _speed; +} + + +[CCode(cheader_filename="lv2/port-groups/port-groups.h")] +namespace LV2.PortGroups { + public const string URI; + + public const string PREFIX; + + public const string _DiscreteGroup; + public const string _Element; + public const string _FivePointOneGroup; + public const string _FivePointZeroGroup; + public const string _FourPointZeroGroup; + public const string _Group; + public const string _InputGroup; + public const string _MidSideGroup; + public const string _MonoGroup; + public const string _OutputGroup; + public const string _SevenPointOneGroup; + public const string _SevenPointOneWideGroup; + public const string _SixPointOneGroup; + public const string _StereoGroup; + public const string _ThreePointZeroGroup; + public const string _center; + public const string _centerLeft; + public const string _centerRight; + public const string _element; + public const string _group; + public const string _left; + public const string _lowFrequencyEffects; + public const string _mainInput; + public const string _mainOutput; + public const string _rearCenter; + public const string _rearLeft; + public const string _rearRight; + public const string _right; + public const string _side; + public const string _sideChainOf; + public const string _sideLeft; + public const string _sideRight; + public const string _source; + public const string _subGroupOf; +} + + +[CCode(cheader_filename="lv2/port-props/port-props.h")] +namespace LV2.PortProps { + public const string URI; + + public const string PREFIX; + + public const string _causesArtifacts; + public const string _continuousCV; + public const string _discreteCV; + public const string _displayProperty; + public const string _expensive; + public const string _hasStrictBounds; + public const string _logarithmic; + public const string _notAutomatic; + public const string _notOnGUI; + public const string _rangeSteps; + public const string _supportsStrictBounds; + public const string _trigger; +} + + +[CCode(cheader_filename="lv2/presets/presets.h")] +namespace LV2.Presets { + public const string URI; + + public const string PREFIX; + + public const string _Bank; + public const string _Preset; + public const string _bank; + public const string _preset; + public const string _value; +} + + +[CCode(cheader_filename="lv2/resize-port/resize-port.h")] +namespace LV2.ResizePort { + public const string URI; + + public const string PREFIX; + + public const string _asLargeAs; + public const string _minimumSize; + public const string _resize; + + /** + * A status code for state functions. + */ + [CCode (cname = "LV2_Resize_Port_Status", has_type_id = false, cprefix = "LV2_RESIZE_PORT_")] + public enum Status { + SUCCESS, + ERR_UNKNOWN, + ERR_NO_SPACE + } + + [SimpleType] + [CCode (cname = "LV2_Resize_Port_Feature_Data")] + public struct FeatureData { + } + + [CCode (cname = "lv2_port_resize_func_t", has_target = false)] + public delegate Status ResizeFunc (FeatureData data, uint32 index, size_t size); + + [Compact] + [SimpleType] + [CCode (cname = "LV2_Resize_Port_Resize", has_type_id = false, free_function = "")] + public class PortResize { + FeatureData data; + [CCode (cname = "resize", has_target = false, delegate_target_cname = "", simple_generics = true)] + public unowned ResizeFunc resize; + } +} diff --git a/vapi/portmidi.vapi b/vapi/portmidi.vapi new file mode 100644 index 00000000..2038da2c --- /dev/null +++ b/vapi/portmidi.vapi @@ -0,0 +1,193 @@ +/* + Copyright (C) 2013 Roman Soumin + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +[CCode (cprefix = "Pm", lower_case_cprefix = "", cheader_filename = "portmidi.h")] +namespace PortMidi { + + public struct DeviceID: int {} + public struct Timestamp: long {} + + [CCode (cname = "pmNoDevice")] + public const DeviceID NO_DEVICE; + + [Compact] + public class DeviceInfo { + [CCode (cname = "Pm_GetDeviceInfo")] + public static unowned DeviceInfo from_id(DeviceID id); + [CCode (cname = "structVersion")] + public int struct_version; + public string interf; + public string name; + public bool input; + public bool output; + public bool opened; + } + + public enum Error { + [CCode (cname = "FALSE")] FALSE, + [CCode (cname = "TRUE")] TRUE, + [CCode (cname = "pmNoError")] NO_ERROR, + [CCode (cname = "pmNoData")] NO_DATA, + [CCode (cname = "pmGotData")] GOT_DATA, + [CCode (cname = "pmHostError")] HOST_ERROR, + [CCode (cname = "pmInvalidDeviceId")] INVALID_DEVICE_ID, + [CCode (cname = "pmInsufficientMemory")] INSUFFICIENT_MEMORY, + [CCode (cname = "pmBufferTooSmall")] BUFFER_TOO_SMALL, + [CCode (cname = "pmBufferOverflow")] BUFFER_OVERFLOW, + [CCode (cname = "pmBadPtr")] BAD_PTR, + [CCode (cname = "pmBadData")] BAD_DATA, + [CCode (cname = "pmInternalError")] INTERNAL_ERROR, + [CCode (cname = "pmBufferMaxSize")] BUFFER_MAX_SIZE + } + + public struct Message: long { + [CCode (cname = "Pm_Message")] + public Message(int status, int data1, int data2); + [CCode (cname = "Pm_MessageStatus")] + public int status(); + [CCode (cname = "Pm_MessageData1")] + public int data1(); + [CCode (cname = "Pm_MessageData2")] + public int data2(); + } + + public struct Event { + Message message; + Timestamp timestamp; + } + + [Compact] + [CCode (free_function = "Pm_Close")] + class Stream { + public struct Filters: ulong {} + + [CCode (cname = "PM_FILT_ACTIVE")] + public const Filters FILT_ACTIVE; + [CCode (cname = "PM_FILT_SYSEX")] + public const Filters FILT_SYSEX; + [CCode (cname = "PM_FILT_CLOCK")] + public const Filters FILT_CLOCK; + [CCode (cname = "PM_FILT_PLAY")] + public const Filters FILT_PLAY; + [CCode (cname = "PM_FILT_TICK")] + public const Filters FILT_TICK; + [CCode (cname = "PM_FILT_FD")] + public const Filters FILT_FD; + [CCode (cname = "PM_FILT_UNDEFINED")] + public const Filters FILT_UNDEFINED; + [CCode (cname = "PM_FILT_RESET")] + public const Filters FILT_RESET; + [CCode (cname = "PM_FILT_REALTIME")] + public const Filters FILT_REALTIME; + [CCode (cname = "PM_FILT_NOTE")] + public const Filters FILT_NOTE; + [CCode (cname = "PM_FILT_CHANNEL_AFTERTOUCH")] + public const Filters FILT_CHANNEL_AFTERTOUCH; + [CCode (cname = "PM_FILT_POLY_AFTERTOUCH")] + public const Filters FILT_POLY_AFTERTOUCH; + [CCode (cname = "PM_FILT_AFTERTOUCH")] + public const Filters FILT_AFTERTOUCH; + [CCode (cname = "PM_FILT_PROGRAM")] + public const Filters PM_FILT_PROGRAM; + [CCode (cname = "PM_FILT_CONTROL")] + public const Filters FILT_CONTROL; + [CCode (cname = "PM_FILT_PITCHBEND")] + public const Filters FILT_PITCHBEND; + [CCode (cname = "PM_FILT_MTC")] + public const Filters FILT_MTC; + [CCode (cname = "PM_FILT_SONG_POSITION")] + public const Filters FILT_SONG_POSITION; + [CCode (cname = "PM_FILT_SONG_SELECT")] + public const Filters FILT_SONG_SELECT; + [CCode (cname = "PM_FILT_TUNE")] + public const Filters FILT_TUNE; + [CCode (cname = "PM_FILT_SYSTEMCOMMON")] + public const Filters FILT_SYSTEMCOMMON; + + public delegate Timestamp TimeProc(); + + [CCode (cname = "Pm_OpenInput")] + public static Error open_input(out Stream stream, + DeviceID inputDevice, + void* inputDriverInfo, + long bufferSize, + TimeProc? time_proc); + + [CCode (cname = "Pm_OpenOutput")] + public static Error open_output(out Stream stream, + DeviceID outputDevice, + void* outputDriverInfo, + long bufferSize, + TimeProc? time_proc, + long latency); + + [CCode (cname = "Pm_HasHostError")] + bool has_host_error(); + + [CCode (cname = "Pm_SetFilter")] + public Error set_filter(Filters filters); + + [CCode (cname = "Pm_SetChannelMask")] + public Error set_channel_mask(int mask); + + [CCode (cname = "Pm_Abort")] + public Error abort(); + + [CCode (cname = "Pm_Read")] + public int read(Event[] buffer); + + [CCode (cname = "Pm_Poll")] + public Error poll(); + + [CCode (cname = "Pm_Write")] + public Error write(Event[] buffer); + + [CCode (cname = "Pm_WriteShort")] + public Error write_short(Timestamp when, long msg); + + [CCode (cname = "Pm_WriteSysEx")] + public Error write_sys_ex(Timestamp when, string msg); + } + + + [CCode (cname = "Pm_Initialize")] + public Error initialize(); + [CCode (cname = "Pm_Terminate")] + public Error terminate(); + [CCode (cname = "Pm_GetErrorText")] + public string get_error_text(Error errorNum); + [CCode (cname = "Pm_CountDevices")] + public int count_devices(); + [CCode (cname = "Pm_GetDefaultInputDeviceID")] + public DeviceID get_default_input_device_id(); + [CCode (cname = "Pm_GetDefaultOutputDeviceID")] + public DeviceID get_default_output_device_id(); + [CCode (cname = "Pm_Channel")] + public int channel_mask(uint channel); +} diff --git a/vapi/suil-0.vapi b/vapi/suil-0.vapi new file mode 100644 index 00000000..93ff79eb --- /dev/null +++ b/vapi/suil-0.vapi @@ -0,0 +1,91 @@ +/* + Copyright 2011 David Robillard + Copyright 2011 Artem Popov + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +[CCode(cheader_filename="suil/suil.h", cprefix="Suil", lower_case_cprefix="suil_")] +namespace Suil { + + [CCode (cname = "SuilArg", cprefix = "SUIL_ARG_", has_type_id = false)] + public enum SuilArgs { + NONE + } + + public static void init (int* argc, string*[] argv, SuilArgs key, ...); + + public static uint ui_supported(string host_type_uri, string ui_type_uri); + + [CCode (cname = "SuilPortWriteFunc", has_target = false)] + public delegate void PortWriteFunc(Controller controller, + uint32 port_index, + uint32 buffer_size, + uint32 protocol, + void* buffer); + + [CCode (cname = "SuilPortIndexFunc", has_target = false)] + public delegate uint32 PortIndexFunc(Controller controller, string port_symbol); + + [CCode (cname = "SuilPortSubscribeFunc", has_target = false)] + public delegate uint32 PortSubscribeFunc(Controller controller, + uint32 port_index, + uint32 protocol, + LV2.Feature** features); + + [CCode (cname = "SuilPortUnsubscribeFunc", has_target = false)] + public delegate uint32 PortUnsubscribeFunc(Controller controller, + uint32 port_index, + uint32 protocol, + LV2.Feature** features); + + [Compact] + [CCode (cname="void")] + public class Widget { + } + + [Compact] + [CCode (cname="void")] + public class Controller { + } + + [Compact] + [CCode (free_function = "suil_host_free")] + public class Host { + public Host(PortWriteFunc write_func, + PortIndexFunc index_func, + PortSubscribeFunc subscribe_func, + PortUnsubscribeFunc unsubscribe_func); + } + + [Compact] + [CCode (free_function = "suil_instance_free")] + public class Instance { + public Instance(Host host, + Controller controller, + string container_type_uri, + string plugin_uri, + string ui_uri, + string ui_type_uri, + string ui_bundle_path, + string ui_binary_path, + LV2.Feature** features); + + public Widget get_widget(); + public void port_event(uint32 port_index, + uint32 buffer_size, + uint32 format, + void* buffer); + public unowned void* extension_data(string uri); + } +} diff --git a/vapi/zix-0.vapi b/vapi/zix-0.vapi new file mode 100644 index 00000000..0cb22e75 --- /dev/null +++ b/vapi/zix-0.vapi @@ -0,0 +1,138 @@ +/* + * Copyright 2023-2023 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ +/* + * This file incorporates work covered by the following copyright and + * permission notice: + * + * --- + * + Copyright 2011-2022 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + * + * --- + */ + +[CCode (cprefix="ZIX_", lower_case_cprefix="zix_")] +namespace Zix { + /** A status code returned by functions. */ + [CCode (cname = "ZixStatus", has_type_id = false, cprefix = "ZIX_STATUS_")] + public enum Status { + /** Success. */ + SUCCESS, + /** Unknown Error. */ + ERROR, + /** Out of memory. */ + NO_MEM, + /** Not found. */ + NOT_FOUND, + /** Exists. */ + EXISTS, + /** Bad Argument. */ + BAD_ARG, + /** Bad Permissions. */ + BAD_PERMS, + /** Reached end. */ + REACHED_END, + /** Timeout. */ + TIMEOUT, + /** Overflow. */ + OVERFLOW, + /** Not Supported. */ + NOT_SUPPORTED, + /** Resource unavailable. */ + UNAVAILABLE, + /** Out of storage space. */ + NO_SPACE, + /** Too many links. */ + MAX_LINKS + } + + [Compact] + [CCode (cheader_filename = "zix/allocator.h", cname = "ZixAllocator", cprefix = "zix_", free_function = "zix_free", has_type_id = false)] + public class Allocator { + + } + + [Compact] + [CCode (cheader_filename = "zix/ring.h", cname = "ZixRing", cprefix = "zix_ring_", free_function = "zix_ring_free", has_type_id = false)] + public class Ring { + // Setup + /** + * Creates a new `Ring` instance. + * + * At most size - 1 bytes may be stored in the ring at once. + * + * @param allocator allocator for the ring object and its array + * @param size size of the ring in bytes (note this may be rounded up) + */ + public Ring (Allocator? allocator, uint32 size); + /** + * Lock the ring data into physical memory. + * + * This function is NOT thread safe or real-time safe, but it should be + * called after zix_ring_new() to lock all ring memory to avoid page + * faults while using the ring. + */ + public Status mlock (); + public void reset (); + public uint32 capacity (); + + // Reading + public uint32 read_space (); + public uint32 peak (void* dst, uint32 size); + public uint32 read (void* dst, uint32 size); + public uint32 skip (uint32 size); + + // Writing + [SimpleType] + [CCode (cname = "ZixRingTransaction", cprefix = "", free_function = "", destroy_function = "", has_type_id = false)] + public struct Transaction { + uint32 read_head; + uint32 write_head; + } + + public uint32 write_space (); + public uint32 write ([CCode (type="const void*")] void* src, uint32 size); + public Transaction begin_write (); + public Status amend_write (Transaction? tx, [CCode (type="const void*")] void* src, uint32 size); + public Status commit_write (Transaction? tx); + + } + + [CCode (cheader_filename = "zix/sem.h", cname = "ZixSem", cprefix = "zix_sem_", destroy_function = "", has_type_id = false)] + public struct Sem { + public static Status init (out Sem sem, uint initial); + public Status destroy (); + public Status post (); + public Status wait (); + public Status try_wait (); + public Status timed_wait (uint32 seconds, uint32 nanoseconds); + } + + [SimpleType] + [CCode (cheader_filename = "zix/thread.h", cname = "ZixThread", cprefix = "zix_thread_", destroy_function = "", has_type_id = false)] + public struct Thread { + public static Status create (out Thread thread, size_t stack_size, ThreadFunc function); + public Status join (); + } + + [SimpleType] + [CCode (cheader_filename = "zix/thread.h", cname = "ZixThreadResult")] + public struct ThreadResult { + } + + public delegate ThreadResult ThreadFunc (); +} From 8948e5cf89fdf5d4264089f494d757f4eb23ebfa Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Sun, 23 Jun 2024 23:31:26 +0530 Subject: [PATCH 35/37] Add beta icons --- .../128/com.github.ensemblesaw.ensembles.svg | 624 ++++++++++++------ .../24/com.github.ensemblesaw.ensembles.svg | 130 ++-- .../32/com.github.ensemblesaw.ensembles.svg | 268 ++++---- .../48/com.github.ensemblesaw.ensembles.svg | 276 ++++---- .../64/com.github.ensemblesaw.ensembles.svg | 315 +++++---- ...ithub.ensemblesaw.ensembles.appdata.xml.in | 2 +- meson.build | 6 +- src/Services.vala | 4 + subprojects/libvinject.wrap | 2 +- 9 files changed, 946 insertions(+), 681 deletions(-) diff --git a/data/Icons/128/com.github.ensemblesaw.ensembles.svg b/data/Icons/128/com.github.ensemblesaw.ensembles.svg index f833964e..97506b32 100644 --- a/data/Icons/128/com.github.ensemblesaw.ensembles.svg +++ b/data/Icons/128/com.github.ensemblesaw.ensembles.svg @@ -1,464 +1,698 @@ - + - - - + + + - - + + - - - - - + + + + + - - - + + + + - + - - - + + + - - - + + + + - + - - + + - - + + - - - - + + - - + + - - + + - + + + + + + + - + - + - + - + - - + + - - + + - - - + + - - + + - - + + - + + + + - + - + - + - + - - + + + - - + + - - + + - - + + + + - - - + + + - + - - + + - - + + - + - - + + - - + + + + + + + + + - + - - + + - - + + - + - - + + - - + + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + - + - + - - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + + - + + + + + + + + - + - + - - + + - + - + - - + + - - + + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - - - + + + - + - - + + + + + + + + + + + - + - + - - - + + + - + - - + + + + + + + + + + - + - + - + - + - + + + + + + + + + + + diff --git a/data/Icons/24/com.github.ensemblesaw.ensembles.svg b/data/Icons/24/com.github.ensemblesaw.ensembles.svg index 03762cef..a391ad43 100644 --- a/data/Icons/24/com.github.ensemblesaw.ensembles.svg +++ b/data/Icons/24/com.github.ensemblesaw.ensembles.svg @@ -1,184 +1,184 @@ - - - + + + - - + + - - - - + + + + - - + + - - + + - + - + - + - + - + - + - - - - - - + + + + + + - - - + + + - + - - + + - - + + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + diff --git a/data/Icons/32/com.github.ensemblesaw.ensembles.svg b/data/Icons/32/com.github.ensemblesaw.ensembles.svg index dfcb9f14..d1fb3870 100644 --- a/data/Icons/32/com.github.ensemblesaw.ensembles.svg +++ b/data/Icons/32/com.github.ensemblesaw.ensembles.svg @@ -1,308 +1,308 @@ - - - + + + - - + + - - - - - + + + + + - - - - - - + + + + + + - - + + - + - + - - + + - - + + - + - - + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - + + - + - + - - - + + + - - - - + + + + - + - - + + - - - + + + - + - - + + - - + + - + - - + + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/data/Icons/48/com.github.ensemblesaw.ensembles.svg b/data/Icons/48/com.github.ensemblesaw.ensembles.svg index 55f68f9f..2984d8f6 100644 --- a/data/Icons/48/com.github.ensemblesaw.ensembles.svg +++ b/data/Icons/48/com.github.ensemblesaw.ensembles.svg @@ -1,329 +1,329 @@ - - - + + + - + - - + + - - - + + + - - - + + + - - - - - + + + + + - - - + + + - - + + - + - - + + - + - + - + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - + - - + + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + - - + + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/data/Icons/64/com.github.ensemblesaw.ensembles.svg b/data/Icons/64/com.github.ensemblesaw.ensembles.svg index ad42eba1..4b65e5c3 100644 --- a/data/Icons/64/com.github.ensemblesaw.ensembles.svg +++ b/data/Icons/64/com.github.ensemblesaw.ensembles.svg @@ -1,337 +1,362 @@ - - - + + + - - + + - + - - + + - - - + + + + - + - - + + - - - + + + - - - - + + + + - + - - + + - + - - + + - + - - + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - + + - - - + + + - - - + + + + - + - - + + - - + + - + - - + + - - + + + + + + + + + - + - - + + - - + + - + - - + + - - + + + + + + + + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - - + + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + - - + + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - - + + + + + + - + - + - + - + - - + + - + - + - + - + - + + + + + + diff --git a/data/com.github.ensemblesaw.ensembles.appdata.xml.in b/data/com.github.ensemblesaw.ensembles.appdata.xml.in index 8ed6c5ab..357be380 100644 --- a/data/com.github.ensemblesaw.ensembles.appdata.xml.in +++ b/data/com.github.ensemblesaw.ensembles.appdata.xml.in @@ -1,5 +1,5 @@ - + com.github.ensemblesaw.ensembles CC0-1.0 diff --git a/meson.build b/meson.build index 6864be9e..d7933656 100644 --- a/meson.build +++ b/meson.build @@ -71,10 +71,12 @@ dependencies = [ dependency ('json-glib-1.0', required: false), dependency ('Vinject-0.0.0', fallback: ['libvinject', 'vinject_dep']), dependency ('enstl-0', fallback: ['enstl', 'enstl_dep']), - dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep']), + dependency ('ens-shell-cli-0', fallback: ['ens-shell-cli', 'ens_shell_cli_dep'], + default_options: ['profile=' + profile]), dependency ('ens-shell-gtk-0', fallback: ['ens-shell-gtk', 'ens_shell_gtk_dep'], default_options: ['profile=' + profile]), - dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep']) + dependency ('ens-aw-core-0', fallback: ['ens-aw-core', 'ens_aw_core_dep'], + default_options: ['profile=' + profile]) ] datadir = get_option ('datadir') diff --git a/src/Services.vala b/src/Services.vala index 2789a5f7..980c8ff1 100644 --- a/src/Services.vala +++ b/src/Services.vala @@ -1,6 +1,10 @@ using Vinject; using Ensembles.ArrangerWorkstation; +/* + * What's happening here is that `Services` is a namespace shared among + * all the modules. It's where all the dependency injection stuff lives. + */ namespace Ensembles.Services { static Injector di_container; } diff --git a/subprojects/libvinject.wrap b/subprojects/libvinject.wrap index 71e0cacf..8148bb69 100644 --- a/subprojects/libvinject.wrap +++ b/subprojects/libvinject.wrap @@ -1,6 +1,6 @@ [wrap-git] url=https://gitlab.com/geeky_endeavours/vinject.git -revision=9.1-unit-tests-using-boxed-values-fix +revision = main depth=1 [provide] From 5d9de12ea3a542aad3fda393f04d02db5b164f04 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 24 Jun 2024 21:36:39 +0530 Subject: [PATCH 36/37] Fix flatpak build --- com.github.ensemblesaw.ensembles.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.github.ensemblesaw.ensembles.yml b/com.github.ensemblesaw.ensembles.yml index cccc7e51..299fcdba 100644 --- a/com.github.ensemblesaw.ensembles.yml +++ b/com.github.ensemblesaw.ensembles.yml @@ -25,7 +25,7 @@ modules: sources: - type: git url: https://gitlab.com/geeky_endeavours/vinject.git - branch: 9.1-unit-tests-using-boxed-values-fix + branch: main # Adds support for lv2 virtual instruments and effects plugins From d04738424f22d6e6e436a25d9341faf19ff2ea62 Mon Sep 17 00:00:00 2001 From: SubhadeepJasu Date: Mon, 24 Jun 2024 21:58:43 +0530 Subject: [PATCH 37/37] Fix appstream metadata --- ...m.github.ensemblesaw.ensembles.appdata.xml.in | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data/com.github.ensemblesaw.ensembles.appdata.xml.in b/data/com.github.ensemblesaw.ensembles.appdata.xml.in index 357be380..45ef0eac 100644 --- a/data/com.github.ensemblesaw.ensembles.appdata.xml.in +++ b/data/com.github.ensemblesaw.ensembles.appdata.xml.in @@ -28,37 +28,37 @@ #FFFFFF 0 - com.github.subhadeepjasu.ensembles + com.github.ensemblesaw.ensembles Subhadeep Jasu https://subhadeepjasu.github.io/#/project/ensembles https://github.com/SubhadeepJasu/ensembles/issues https://github.com/SubhadeepJasu/ensembles/issues subhadeep107@proton.me - com.github.subhadeepjasu.ensembles.desktop + com.github.ensemblesaw.ensembles.desktop Instant Playback - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/Screenshot.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/Screenshot.png Style Menu - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotStyles.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/ScreenshotStyles.png Per Channel Modulators - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotChannelModulators.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/ScreenshotChannelModulators.png Master Knob LFO - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotLFO.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/ScreenshotLFO.png Multi-track Recorder - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotMultiTrackRecorder.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/ScreenshotMultiTrackRecorder.png Voice Menu and MIDI File Player - https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotVoice.png + https://raw.githubusercontent.com/ensemblesaw/ensembles-app/master/screenshots/ScreenshotVoice.png

    {y)S-(&Zdr34gjw^`f7zrR29 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 z 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 >Fxn7sF8d3$u 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 Y_kSlpW6|cXpTo@$WAXn0>;C}%*)_;zM*si- diff --git a/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg.back b/data/Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg.back deleted file mode 100644 index 49fed51709aa7fd6a0590c965cbc6c9335e9ff41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90591 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 bdvU}a>3E&pZ7_23k7Rva - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/Themes/Application.css b/data/Themes/Application.css deleted file mode 100644 index 855e0950..00000000 --- a/data/Themes/Application.css +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -.panel { - padding: 4px; -} - -.can-be-blurred { - filter: blur(0) brightness(1); - transition: filter 0.5s cubic-bezier(0, 0, 0, 1); -} - -.blurred { - filter: blur(16px) brightness(0.9); - transition: filter 0.2s ease-out; -} - -button { - outline: 0; - box-shadow: none; -} - -button.pulse { - animation: pulse 3s linear infinite; -} - -button.pulse-fill { - animation: pulse-alt 1s linear infinite; -} - -@keyframes pulse { - 0% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 5% { - background-color: alpha(@accent_color, 0.7); - box-shadow: inset 0 0 8px @accent_color; - } - - 25% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 30% { - background-color: alpha(@accent_color, 0.5); - box-shadow: inset 0 0 8px @accent_color; - } - - 50% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 55% { - background-color: alpha(@accent_color, 0.7); - box-shadow: inset 0 0 8px @accent_color; - } - - 75% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 80% { - background-color: alpha(@accent_color, 0.5); - box-shadow: inset 0 0 8px @accent_color; - } - - 100% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } -} - -@keyframes pulse-alt { - 0% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 5% { - background-color: alpha(@accent_color_complimentary, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary; - } - - 10% { - background-color: alpha(@accent_color_complimentary_alternate, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary_alternate; - } - - 25% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 30% { - background-color: alpha(@accent_color_complimentary, 0.5); - box-shadow: inset 0 0 8px @accent_color_complimentary; - } - - 35% { - background-color: alpha(@accent_color_complimentary_alternate, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary_alternate; - } - - 50% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 55% { - background-color: alpha(@accent_color_complimentary, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary; - } - - 60% { - background-color: alpha(@accent_color_complimentary_alternate, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary_alternate; - } - - 75% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } - - 80% { - background-color: alpha(@accent_color_complimentary, 0.5); - box-shadow: inset 0 0 8px @accent_color_complimentary; - } - - 85% { - background-color: alpha(@accent_color_complimentary_alternate, 0.7); - box-shadow: inset 0 0 8px @accent_color_complimentary_alternate; - } - - 100% { - background-color: @bg-color; - box-shadow: inset 0 0 0 1px alpha(#000, 0.1); - } -} - - -.beat-counter-0 { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/beat_counter_map"); -} - -.beat-counter-1 { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/beat_counter_map"); - background-position: 0px -32px; -} - -.beat-counter-2 { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/beat_counter_map"); - background-position: 0px -64px; -} - -.beat-counter-3 { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/beat_counter_map"); - background-position: 0px -96px; -} - -.beat-counter-4 { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/beat_counter_map"); - background-position: 0px -128px; -} - -.adw-listbox>row { - margin: 8px; - padding: 12px; - border-radius: 8px; - border: 1px solid #0002; - box-shadow: 0 2px 4px #0003, inset 0 0 0 1px #fff1; - transition: all 0.4s cubic-bezier(0, 0, 0, 1); -} - -.adw-listbox>row:selected { - background: alpha(@accent_color, 0.2); - box-shadow: 0 2px 4px alpha(shade(@accent_color, 0.6), 0.5), inset 0 0 0 1px #fff1; -} - -.adw-listbox>row>.header>.title>.subtitle { - font-size: small; - opacity: 0.5; -} - -dimming { - background: #0001; -} - -flap>.adw-listbox { - border-right: 1px solid #0004; -} - -.folded>.adw-listbox { - border-right: 1px solid #0006; - box-shadow: 0px 0px 32px 32px #0004; -} - -flap>stack { - filter: blur(0); - transform: scale(1); - transition: all 0.4s cubic-bezier(0, 0, 0, 1); -} - -stack.dimmed { - filter: blur(4px); -} - -/* KEYBOARD */ - -.keyboard { - background: shade(@bg_color, 0.9); - border-top: 1px solid #0006; - background-image: linear-gradient( - shade(@bg_color, 1.8) 0, - shade(@bg_color, 0.9) 16px, - alpha(shade(@bg_color, 0.4), 0.3) 17px, - shade(@bg_color, 1.8) 34px, #000 35px - ); -} - -.keyboard-info-bar button { - opacity: 0.5; - -gtk-icon-shadow: 0 0 0 #fff0; - transition: all 0.2s ease-out; -} - -.keyboard-info-bar button:hover { - opacity: 1; - -gtk-icon-shadow: 0 0 8px #fff; -} - -.key { - background: @bg_color; - background-image: linear-gradient(alpha(shade(@bg_color, 2), 0.5), alpha(shade(@bg_color, 0.8), 0.5)); - border-radius: 0px 0px 6px 6px; - border: 2px solid #000; - filter: none; - box-shadow: inset 0 0 0 1px #fff2; - transition: all 1s ease-out; -} - -.key.black { - background: @fg_color; - background-image: linear-gradient(alpha(shade(@bg_color, 2), 0.4), alpha(shade(@bg_color, 0.3), 0.5)); - box-shadow: inset 0 0 0 1px #fff2; - border-radius: 0px 0px 5px 5px; - transition: all 1s ease-out; -} - -.key:hover { - box-shadow: inset 0 0 0 1px #fff2, inset 0 -4px 12px #fff4; - filter: brightness(1.1); - transition: all 0.1s linear; -} - - -.key.black.activated { - box-shadow: inset 0 0 0 1px shade(@accent_color, 1.2), inset 0 -4px 12px alpha(shade(@accent_color, 1.5), 0.6), 0 0 12px alpha(@accent_color, 0.5); - background-color: mix(@accent_color, @fg_color, 0.2); - filter: brightness(1); - transition: all 0.1s linear; -} - -.key.activated { - box-shadow: inset 0 0 0 1px shade(@accent_color, 1.2), inset 0 -4px 12px alpha(shade(@accent_color, 1.5), 0.6), 0 0 12px alpha(@accent_color, 0.5); - background-color: @accent_color; - filter: brightness(1); - transition: all 0.1s linear; -} - -.display { - background: #000; - border-radius: 12px; - box-shadow: inset 0 1px 0 #0004, 0 1px 0 #fff3; - border: 2px solid #000; -} - -.display.fill { - box-shadow: 0 0 0 4px #000; - border-radius: 0; - border: none; -} - -.ensembles-logo-splash { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/display/splash_screen"); - background-position: center; - background-size: contain; - background-repeat: no-repeat; -} - -.splash-screen-background { - background-color: #202020; - background-position: center; - background-size: cover; - animation: ripple 1s 0.2s; - filter: brightness(1); - transition: filter 0.5s ease-in; - color: #fff; -} - -.splash-screen-background.fade-black { - filter: brightness(0); -} - -.splash-screen-text { - color: #fff; -} - -@keyframes ripple { - from { - background-image: radial-gradient(circle, #202020 0, #333 5%, #202020 6%); - } - - to { - background-image: radial-gradient(circle, #202020 0, #202020 90%, #202020 100%); - } -} - -.pseudowindow { - border-radius: 8px; - box-shadow: inset 0 0 0 2px #fff2, inset 0 0 0 1px #000; - padding: 8px; - background-image: linear-gradient(@bg_color, @bg_color), linear-gradient(@window_bg_color, @window_bg_color), linear-gradient(grey, grey); - box-shadow: 0 12px 24px #0008; - text-shadow: 0 1px #fff6, 0 -1px #0004; -} - -.pseudowindow-actual { - background: linear-gradient(#0004, #0004), url("resource://com/github/subhadeepjasu/ensembles/images/display/home_background_default_blurred"); - background-size: cover; - background-position: center; - border: none; - box-shadow: none; -} - -@import url("resource://com/github/subhadeepjasu/ensembles/theme/Display.css"); diff --git a/data/Themes/Display/Display.css b/data/Themes/Display/Display.css deleted file mode 100644 index e95a6316..00000000 --- a/data/Themes/Display/Display.css +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright 2020-2023 Subhadeep Jasu - * SPDX-License-Identifier: GPL-3.0-or-later - */ -/* Do not edit this file */ - -/* ///////////////////////////////////////////////////////////////////////////// -Mother class for the central display section -*/ - -.display { - font-family: "Exo2"; -} - -.display .display-stack { - filter: brightness(1); - transform: scale(1); - transition: filter 1.2s cubic-bezier(0, 0, 0, 1), transform 1.2s cubic-bezier(0, 0, 0, 1); -} - -.display .display-stack.fade-black { - transform: scale(0.9); - filter: brightness(0); -} - - -/* ///////////////////////////////////////////////////////////////////////////// -General Gtk Widgets -*/ -/* -Buttons -*/ -.display button { - border: 1px solid rgba(255, 255, 255, 0.2); - background: rgba(255, 255, 255, 0.1); - border-radius: 6px; - box-shadow: none; - text-shadow: none; - opacity: 0.6; - color: #fff; - padding: 0 0; - margin: 0; - transition: opacity 0.3s ease-out; -} - -.display button.accented { - border: 1px solid shade(@accent_color, 1); - background: shade(@accent_color, 0.75); - color: shade(@accent_color, 1.3); -} - -.display button:hover { - opacity: 1; -} - -.display button:active { - background: alpha(#fff, 0.07); -} - -.display .flat, -.display .image-button { - border: none; - background: alpha(#fff, 0.0); -} - -.display .flat:hover, -.display .image-button:disabled {} - -.display .flat:focus, -.display .image-button:focus {} - -.display .flat:hover, -.display .image-button:hover {} - -.display .linked button { - border-radius: 0; -} - -.display .linked button:first-child { - border-radius: 6px 0 0 6px; - border-right: transparent; -} - -.display .linked button:last-child { - border-radius: 0 6px 6px 0; -} - -/* -Switches -*/ - -.display switch { - background: linear-gradient(#6668, mix(#6668, @accent_color, 0.2)); - box-shadow: inset 0 0 0 1px alpha(mix(#ccc, @accent_color, 0.4), 0.2); - border: 1px solid #000; -} - -.display switch slider { - background: linear-gradient(45deg, #666, alpha(mix(#333, @accent_color, 0.7), 0.2)); - box-shadow: 4px -8px 28px #fff0, -4px 8px 32px #fff0, inset 0 0 0 1px #fff2, 0 4px 8px #0002; - outline: 0; - margin: 2px; - border: none; - transition: all 0.4s cubic-bezier(0, 0, 0, 1); -} - -.display switch:checked { - background: linear-gradient(45deg, #6668, mix(#6668, @accent_color, 0.2)); - box-shadow: inset 0 0 0 1px alpha(mix(#ccc, @accent_color, 0.4), 0.2), inset 1px 0 0 alpha(@accent_color, 0.6), - inset -1px 0 0 @accent_color_complimentary; -} - -.display switch:checked slider { - background: linear-gradient(45deg, @accent_color, @accent_color_complimentary); - box-shadow: 4px -8px 28px alpha(@accent_color_complimentary, 0.75), -4px 8px 32px alpha(@accent_color, 0.75), inset 0 0 0 1px #fff4, 0 4px 8px #0002; -} - -/* -Custom Widgets -*/ -/* -Knobs -*/ - -.display .knob { - background: none; - border-radius: 50%; - box-shadow: inset 0 0 0 1px #0008, inset 0 3px 6px #0008, 0 1px 0 #fff3, 0 8px 16px #0004, 0 -8px 16px #fff2; -} - -.display .knob-cover { - background: radial-gradient(75% 75% at 50% 25%, #444, #2227); - box-shadow: 0 0 0 12px #2228, 0 2px 8px #000a, inset 0 1px 1px #fff4, inset 0 -1px 1px #0008; - border: none; - border-radius: 50%; - margin: 12px; - transition: background 0.2s linear; -} - -.display .knob:hover .knob-cover { - background: radial-gradient(75% 75% at 50% 25%, #555, #3337); -} - -.display .knob.small { - background: rgba(255, 255, 255, 0.1); - border-radius: 50%; - opacity: 0.6; - box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2); -} - -.display .knob.small .knob-cover { - background: #fff1; - box-shadow: 0 0 0 2px #fff2; - border: none; - border-radius: 50%; - margin: 8px; - transition: background 0.2s linear; -} - -.display .knob.small:hover { - opacity: 1; -} - - -.display .knob.small:hover .knob-cover { - background: #fff3; - box-shadow: 0 0 0 2px #0004; -} - -/* ///////////////////////////////////////////////////////////////////////////// -HomeScreen -*/ - -.display .homescreen { - background: radial-gradient(112% 112% at 50% 105%, mix(shade(@accent_color_complimentary, 0.6), #222, 0.84) 0%, #000 100%); -} - -.display .homescreen .homescreen-links-section { - background-image: linear-gradient(88deg, alpha(shade(@accent_color, 0.6), 0.75), alpha(shade(@accent_color_complimentary, 0.5), 0.75)), url("resource://com/github/subhadeepjasu/ensembles/images/display/home_background_default"); - background-position: center; - background-size: auto 100%; -} - -.homescreen-link-panel-top { - background: linear-gradient(92deg, - shade(@accent_color, 0.54) 12%, - mix(shade(@accent_color, 0.65), shade(@accent_color_complimentary, 0.5), 0.25) 18%, - mix(shade(@accent_color, 0.5), shade(@accent_color_complimentary, 0.5), 0.5) 74%, - mix(shade(@accent_color, 0.4), shade(@accent_color_complimentary, 0.55), 0.6) 100%); - margin: 8px; - border-radius: 6px; - border: 1px solid #fff2; - padding: 2px; - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.25); -} - -.display .homescreen-link-panel-top-button { - background: none; - opacity: 1; - border: 0; - padding: 0; - box-shadow: none; - outline: none; - text-shadow: none; - text-decoration: none; - border-radius: 2px; - color: #fff; - margin: 2px; - transition: all 0.2s ease-out; -} - -.display .homescreen-link-panel-top-button:hover { - background: linear-gradient(91.74deg, alpha(@accent_color, 0.5), alpha(@accent_color, 0.3)); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); -} - -.display .homescreen-link-panel-top-button:active { - background: linear-gradient(91.74deg, alpha(@accent_color_complimentary, 0.5), alpha(@accent_color, 0.75)); -} - -.display .homescreen-link-panel-top-button-header { - font-size: 14px; - font-weight: 700; - margin-top: 8px; -} - -.display .homescreen-link-panel-top-button-subheader { - font-size: 12px; -} - -.display .homescreen-link-panel-bottom-button { - background: #fff0; - border: none; - border-radius: 0; - font-weight: 700; - opacity: 1; - text-shadow: 0 1px 8px #0002; - color: shade(@accent_color, 1.3); - font-size: 13px; - padding: 4px; - padding-left: 0px; - transition: all 0.4s ease; -} - -.display .homescreen-link-panel-bottom-button-status { - background: #fff0; - font-weight: 400; - opacity: 0.5; - transition: all 0.4s ease; -} - -.display .homescreen-link-panel-bottom-button:hover { - background: #fff0; - color: #fff; -} - -.display .homescreen-link-panel-bottom-button separator { - background: shade(@accent_color, 1.3); - opacity: 0; - border: none; - border-radius: 2px; - margin-right: 8px; - padding: 1px; - transform: translateX(0); - transition: all 0.4s ease; -} - -.display .homescreen-link-panel-bottom-button:hover .homescreen-link-panel-bottom-button-status { - opacity: 1; - color: shade(@accent_color, 1.3); -} - -.display .homescreen-link-panel-bottom-button:hover separator { - opacity: 1; - transform: translateX(4px); -} - -.display .homescreen-panel-status { - border-top: 1px solid alpha(#000, 0.5); - padding-top: 8px; -} - -.display .homescreen-panel-status-header { - padding: 4px; - font-weight: 700; - opacity: 0.75; - font-size: 14px; - color: @accent_color; -} - -.display .homescreen-panel-status-label { - padding: 4px; - padding-top: 0; - opacity: 0.75; - color: #fff; - font-family: 'Michroma'; - font-weight: 400; - font-size: 24px; - color: shade(@accent_color, 2); -} - -.display .homescreen-panel-status-label-small { - font-weight: 600; - font-size: 14px; - font-style: italic; - color: shade(@accent_color, 2); -} - -/* ///////////////////////////////////////////////////////////////////////////// -Display Window -*/ - -.display .display-window-background { - background: radial-gradient(13.25% 17.73% at 8.54% 9.2%, alpha(@accent_color, 0.25) 0%, alpha(@accent_color, 0) 100%), - radial-gradient(17.27% 44.85% at 55.57% 47.73%, alpha(@accent_color_complimentary, 0.15) 0%, alpha(@accent_color_complimentary, 0) 100%), - radial-gradient(112% 112% at 50% 105%, mix(shade(@accent_color_complimentary, 0.6), #222, 0.84) 0%, #000 100%); - color: #fff; -} - -.display .display-window-header-bar { - padding: 18px; - box-shadow: none; - border-bottom: none; - background: none; - color: #fff; - text-shadow: none; - -gtk-icon-shadow: none; - border: none; - border-radius: 0; -} - -.display .display-window-header-bar .title { - font-size: 20px; - color: #fff; - font-weight: 500; -} - -.display .display-window-header-bar .subtitle { - font-size: 12px; - font-weight: 400; - opacity: 0.75; - color: shade(@accent_color, 1.5); -} - - -/* ///////////////////////////////////////////////////////////////////////////// -Menu -*/ - -.display .menu-box { - background: none; - color: #fff; - padding-left: 20px; - padding-right: 20px; -} - -.display .menu-box>.activatable { - color: #fff; - border-bottom: 1px solid alpha(@accent_color_complimentary, 0.1); -} - -.display .menu-box>.activatable:selected { - box-shadow: none; - background: linear-gradient(270deg, alpha(@accent_color_complimentary, 0) 0%, alpha(@accent_color_complimentary, 0.25) 51.04%, alpha(@accent_color_complimentary, 0) 100%); - background-size: 100% 54px; - background-repeat: no-repeat; - background-position: 0 100%; -} - -.display .menu-item-name { - font-size: 16px; -} - -.display .menu-box>.activatable:selected .menu-item-label { - text-shadow: none; -} - -.display .menu-item-index { - font-size: 13px; - font-family: 'Michroma'; -} - -.display .menu-item-description { - font-size: 0.8em; - margin-top: 8px; -} - -.display .menu-item-icon { - border: none; - box-shadow: none; -} - -.display .menu-item-category { - background: none; - color: @accent_color_complimentary; - border-radius: 0; - padding-left: 8px; - padding-top: 4px; - padding-bottom: 4px; - margin-bottom: 4px; - margin-left: -8px; - font-size: 16px; - font-weight: 900; - letter-spacing: 0.12em; - border-bottom: 1px solid alpha(@accent_color_complimentary, 0.5); -} - - -/* Plugin Menu ///////////////////////////////////////////////////////////////*/ -.display .plugin-flap dimming { - background: none; -} - -.display .plugin-list { - background: none; -} - -.display .plugin-item { - margin: 12px; - margin-right: 18px; - padding: 8px; - border-radius: 6px 24px 7px 6px; - border: 1px solid #000a; - background: linear-gradient(#444, #345); - box-shadow: 0 4px 12px #0002, inset 0 0 0 1px #fff2; - color: #fffc; - font-weight: bold; - font-size: 1.1rem; - text-shadow: 0 0 16px #fff0, 0 0 8px #fff7; - transition: all 1s ease-out; -} - -.display .plugin-item-info { - font-size: 0.82em; - text-shadow: none; - line-height: normal; -} - -.display .plugin-item:hover { - color: #fff; - background: linear-gradient(#444, #356); - box-shadow: 0 4px 12px #0002, inset 0 0 0 1px #fff2, inset 0 -1px #47a; - text-shadow: 0 0 16px #fffa, 0 0 8px #fffd; - transition: all 0.2s ease; -} - - -.display .plugin-item-insert-button { - background: #fff2; - border-radius: 50px; - padding: 8px; - border: 1px solid #fff4; -} - -.display .plugin-item-insert-button:hover { - background: #59b; - border-radius: 50px; - padding: 8px; - border: 1px solid #6bd; - outline: 0; -} - -.display .plugin-item-insert-button:active { - background: rgb(168, 187, 85); - border-radius: 50px; - padding: 8px; - border: 1px solid rgb(170, 221, 102); - outline: 0; -} - -.display .plugin-item-protocol { - filter: brightness(3); - opacity: 0.75; -} - -.display .menu-item.capture-attention { - animation: capture_attention 1s ease; -} - -@keyframes capture_attention { - 0% { - transform: rotateZ(0) scale(1); - background: #333; - box-shadow: 0 0 24px rgba(100, 187, 85, 0); - } - - 10% { - transform: rotateZ(-2deg) scale(1.2); - } - - 20% { - transform: rotateZ(2deg) scale(1.2); - } - - 30% { - transform: rotateZ(-2deg) scale(1.2); - } - - 40% { - transform: rotateZ(2deg) scale(1.2); - } - - 50% { - transform: rotateZ(0) scale(1.1); - background: rgb(100, 187, 85); - box-shadow: 0 0 24px rgb(100, 187, 85); - } - - 100% { - transform: rotateZ(0) scale(1); - background: #333; - box-shadow: 0 0 24px rgba(100, 187, 85, 0); - } -} - -.display .menu-item button { - border: 1px solid rgba(255, 255, 255, 0.2); - background: rgba(255, 255, 255, 0.1); -} - -.display .card { - background-image: linear-gradient(#444, mix(@accent_color_complimentary, #444, 0.9)); - border-radius: 16px; - border: 1px solid mix(@accent_color_complimentary, #666, 0.9); - outline: 0; - box-shadow: 0 12px 36px alpha(@accent_color_complimentary, 0.1), 0 2px 8px #0004; - color: mix(@accent_color_complimentary, #ccc, 0.8); - transition: all 1.2s cubic-bezier(0, 0, 0, 1); -} - -.display .card:hover { - background-image: linear-gradient(#444, mix(@accent_color_complimentary, #444, 0.75)); - border: 1px solid mix(@accent_color_complimentary, #666, 0.75); - box-shadow: 0 12px 36px alpha(@accent_color_complimentary, 0.5), 0 2px 12px #0008; - color: #fff; - transform: scale(1); -} - -.display .menu-item check { - background: rgba(255, 255, 255, 0.14); - opacity: 0.6; - color: #fff; - box-shadow: none; - padding: 6px; - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 50%; - transition: all 0.3s ease-out; -} - -.display .menu-item check:hover { - opacity: 1; -} - - -.display .menu-item check:checked { - border: 1px solid alpha(shade(@accent_color, 1.3), 0.5); - background: alpha(@accent_color, 0.5); - opacity: 1; - box-shadow: 0px 6px 32px alpha(@accent_color, 0.75); -} - -.display .audio-switch check { - -gtk-icon-source: -gtk-icontheme("system-shutdown-symbolic"); - -gtk-icon-shadow: none; -} - -.display .menu-item.p-8 { - padding-top: 8px; - padding-bottom: 8px; -} diff --git a/data/com.github.subhadeepjasu.ensembles.appdata.xml.in b/data/com.github.ensemblesaw.ensembles.appdata.xml.in similarity index 99% rename from data/com.github.subhadeepjasu.ensembles.appdata.xml.in rename to data/com.github.ensemblesaw.ensembles.appdata.xml.in index e4eb3358..8ed6c5ab 100644 --- a/data/com.github.subhadeepjasu.ensembles.appdata.xml.in +++ b/data/com.github.ensemblesaw.ensembles.appdata.xml.in @@ -1,7 +1,7 @@ - com.github.subhadeepjasu.ensembles + com.github.ensemblesaw.ensembles CC0-1.0 GPL-3.0+ Ensembles diff --git a/data/com.github.subhadeepjasu.ensembles.desktop.in b/data/com.github.ensemblesaw.ensembles.desktop.in similarity index 67% rename from data/com.github.subhadeepjasu.ensembles.desktop.in rename to data/com.github.ensemblesaw.ensembles.desktop.in index c259a0fa..ca692cfa 100644 --- a/data/com.github.subhadeepjasu.ensembles.desktop.in +++ b/data/com.github.ensemblesaw.ensembles.desktop.in @@ -4,9 +4,9 @@ GenericName=Arranger Workstation Comment=Play and arrange music live as a one-person band Categories=Audio;AudioVideo;Music;Midi;Education;GTK; MimeType=audio/midi -Exec=com.github.subhadeepjasu.ensembles %U -Icon=com.github.subhadeepjasu.ensembles +Exec=com.github.ensemblesaw.ensembles %U +Icon=com.github.ensemblesaw.ensembles Terminal=false Type=Application Keywords=midi;virtual;music;arranger;piano;keyboard;workstation; -X-GNOME-Gettext-Domain=com.github.subhadeepjasu.ensembles +X-GNOME-Gettext-Domain=com.github.ensemblesaw.ensembles diff --git a/data/com.github.subhadeepjasu.ensembles.kiosk.desktop b/data/com.github.ensemblesaw.ensembles.kiosk.desktop similarity index 76% rename from data/com.github.subhadeepjasu.ensembles.kiosk.desktop rename to data/com.github.ensemblesaw.ensembles.kiosk.desktop index b0352396..40029b8a 100644 --- a/data/com.github.subhadeepjasu.ensembles.kiosk.desktop +++ b/data/com.github.ensemblesaw.ensembles.kiosk.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Name=Ensembles Comment=This session launches Ensembles Arranger Workstation in kiosk mode -Exec=com.github.subhadeepjasu.ensembles --kiosk +Exec=com.github.ensemblesaw.ensembles --kiosk Icon= DesktopNames=Ensembles Type=Application diff --git a/data/com.github.subhadeepjasu.ensembles.gresource.xml b/data/com.github.subhadeepjasu.ensembles.gresource.xml deleted file mode 100644 index 5ae12cf2..00000000 --- a/data/com.github.subhadeepjasu.ensembles.gresource.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - Themes/Application.css - Themes/Display/Display.css - - - - Icons/scalable/actions/style-break-symbolic.svg - Icons/scalable/actions/style-sync-start-symbolic.svg - Icons/scalable/actions/plugin-add-symbolic.svg - Icons/scalable/emblems/plugin-audio-lv2-symbolic.svg - - - - Images/beat_counter.svg - - - - Images/Display/splash_screen.png - Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash.jpg - Images/Display/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg - - diff --git a/data/com.github.subhadeepjasu.ensembles.gschema.xml.in b/data/com.github.subhadeepjasu.ensembles.gschema.xml.in deleted file mode 100644 index 497dae8b..00000000 --- a/data/com.github.subhadeepjasu.ensembles.gschema.xml.in +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - '0.0.0' -