diff --git a/README.md b/README.md index 5bea93a1..1ba7d50d 100644 --- a/README.md +++ b/README.md @@ -45,36 +45,45 @@ You can install Ensembles by compiling it from source, here's a list of required - `io.elementary.Platform>=6` (flatpak) - `io.elementary.Sdk>=6` (flatpak) - `elementary-sdk` - - `gtk+-3.0>=3.18` - - `granite>=5.3.0` + - `gtk+-3.0>=3.24` + - `granite>=6.1.2` - `glib-2.0` - `gobject-2.0` - `meson` - - `libhandy-1` + - `libhandy-1>=1.2` + - `json-glib-1.0>=1.4.4` + - `lv2` + - `lilv-0` + - `suil-0` - `fluidsynth>=2.2.1` - `portmidi` -Clone repository and change directory +**Clone repository and change directory** ``` git clone https://github.com/SubhadeepJasu/ensembles.git cd ensembles ``` -Compile, install using flatpak and start Ensembles on your system *(Recommended)* + +**Compile, install using flatpak and start Ensembles on your system** *(Recommended)* ``` flatpak-builder build com.github.subhadeepjasu.ensembles.yml --user --install --force-clean flatpak run com.github.subhadeepjasu.ensembles ``` -_OR_ using meson *(Requires GIT-LFS)* +**_OR_ using meson** *(Requires GIT-LFS)* + ``` meson _build --prefix=/usr cd _build sudo ninja install com.github.subhadeepjasu.ensembles ``` +Don't forget to also install the soundfont from https://gitlab.com/SubhadeepJasu/ensemblesgmsoundfont, if you are doing meson build ## Realtime Audio Performance -The software does require quite a lot of CPU power. If you notice bad delay or stuttering audio, launch the app from terminal; check to see if there is any error messages stating that fluidsynth was unable to set realtime priority. In that case, edit the file- `/etc/security/limits.conf` and add the following lines: +You can tweak audio settings in Ensembles and select one of the two drivers (**Alsa** or **PulseAudio**). Increasing buffer size will reduce system load but too much increase in buffer-size may also cause sounds to go out of sync. So, feel free to tinker a little until you find your sweet spot in terms of performance. + +Even after all that, while using **PulseAudio**, if you notice bad delay or stuttering audio, launch the app from terminal; check to see if there is any error messages stating that fluidsynth was unable to set realtime priority. In that case, edit the file- `/etc/security/limits.conf` and add the following lines: ``` @audio - rtprio 90 @audio - memlock unlimited @@ -82,6 +91,10 @@ The software does require quite a lot of CPU power. If you notice bad delay or s The problem currently usually happens with the flatpak version. +**PipeWire** support is planned and Ensembles will detect if you have it installed and it will modify the PulseAudio driver settings internally to better utilise PipeWire-Pulse if that is available. + +**Jack** is also an option but it currently only works from outside the flatpak soundbox, ie. when you compile it natively. + ## Discussions If you want to ask any questions or provide feedback, you can make issues in this repository or use the discussions section of this repository. @@ -89,7 +102,7 @@ If you want to ask any questions or provide feedback, you can make issues in thi Feel free to send pull requests to this repository with your code, or other types of assets like soundfont voices, style files, etc. Soundfont in this repo is no longer updated and its available in a different repository https://gitlab.com/SubhadeepJasu/ensemblesgmsoundfont due to LFS concerns. ## Plug-In Development -Ensembles will have support for sampled voice, voice synthesis and DSP plug-ins. Plug-ins may support their own UI which can be accessed from within Ensembles. You can create plug-ins and distribute them over Flathub or elementary OS AppCenter. +Ensembles will have support for effects and instrument plug-ins. Plug-ins may support their own UI which can be accessed from within Ensembles. There is partial support for LV2 plug-ins and it will be while before that is fleshed out properly. You can create plug-ins and distribute them over Flathub or elementary OS AppCenter, provided they follow the usual standards. ## External Files Ensembles supports creation and distribution of external soundfonts (SF2), style files and MIDI recordings. External content can be placed in special folders in user's document folder. Style files from other formats like *STY*, *AC7*, etc. are not compatible with Ensembles. Ensembles has its own style format *ENSTL*, check out styles Readme file in your documents folder for style specifications (Check: https://github.com/SubhadeepJasu/Ensembles/blob/master/data/Styles/README.md). External MIDI recordings may have reserved copyrights. diff --git a/com.github.subhadeepjasu.ensembles.yml b/com.github.subhadeepjasu.ensembles.yml index a634ab9a..a01af700 100644 --- a/com.github.subhadeepjasu.ensembles.yml +++ b/com.github.subhadeepjasu.ensembles.yml @@ -1,6 +1,6 @@ app-id: com.github.subhadeepjasu.ensembles runtime: io.elementary.Platform -runtime-version: '6' +runtime-version: '6.1' sdk: io.elementary.Sdk command: com.github.subhadeepjasu.ensembles finish-args: @@ -138,8 +138,8 @@ modules: - '*.so' sources: - type: archive - url: https://github.com/FluidSynth/fluidsynth/archive/refs/tags/v2.2.1.tar.gz - sha256: 1c56660f23f6c406b36646cc619fc2d2a5265d1d3290e79bcef4505bcd985fdd + url: https://github.com/FluidSynth/fluidsynth/archive/v2.2.4.tar.gz + sha256: 83cb1dba04c632ede74f0c0717018b062c0e00b639722203b23f77a961afd390 # MIDI controller support - name: portmidi diff --git a/data/Images/ensembles_splash.svg b/data/Images/ensembles_splash.svg index 6c60e093..9428e736 100644 --- a/data/Images/ensembles_splash.svg +++ b/data/Images/ensembles_splash.svg @@ -1,5 +1,4 @@ - - - - + + + diff --git a/data/Application.css b/data/Themes/Application.css similarity index 59% rename from data/Application.css rename to data/Themes/Application.css index 79aa99d8..35b84f37 100644 --- a/data/Application.css +++ b/data/Themes/Application.css @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -23,134 +9,21 @@ } .splash-background { - background: #202020; + background-color: #202020; + animation: ripple 1s 0.2s; } -.display-background { - background-color: #000; -} - -.home-screen-background { - background-image: url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash.jpg"); - background-size: auto 100%; - background-position: 50%; -} - -.home-screen-panel-top { - background-image: linear-gradient(alpha(#007367, 0.6),alpha(#007367, 0.6)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); - background-size: auto 600%; - background-position: 50% 0; - border-bottom: 1px solid alpha(#000, 0.5); -} - -.display-top-panel-header { - font-size: 1.11em; - margin-top: 4px; -} - -.display-top-panel-subheader { - font-size: 0.8em; - margin-bottom: 6px; -} - -.display-top-panel-button { - background: none; - border: 0; - padding: 0; - box-shadow: none; - outline: none; -} - -.display-top-panel-button:hover { - background-color: alpha(#fff, 0.1); -} - -.home-screen-panel-bottom { - background-image: linear-gradient(alpha(#273445, 0.6),alpha(#273445, 0.6)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); - background-size: auto 250%; - background-position: 50% 100%; - border-top: 1px solid alpha(#000, 0.5); -} - -.home-screen-eq-labels { - margin-top: -5px; -} - -.home-screen-eq-labels > * { - font-size: 0.7em; - color: #CAE974; - border-top: 1px solid #6C9104; -} - - -.channel-modulator-screen { - background-image: linear-gradient(alpha(#273445, 0.6), alpha(#273445, 0.6)), url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); - background-size: auto 100%; - background-position: 50%; - padding: 8px; -} -.channel-modulator-close-button { - background-color: #007367; - border-radius: 2px 0 0 2px; - margin-right: -2px; -} -.channel-modulator-close-button:hover { - background-color: #02A594; -} -.channel-modulator-header { - font-size: 1.8em; - margin-left: 4px; - background-image:linear-gradient(90deg, #007367, alpha(#007367, 0)); - padding: 4px; -} - -.channel-modulator-grid > * { - border: 1px solid #111; - border-radius: 0; - box-shadow: none; - color: #f3f3f3; -} -.channel-modulator-grid > spinbutton { - background-color: alpha (#333, 0.4); - border-radius: 0; - box-shadow: none; - color: #00E9D0; -} - -.channel-configure-button { - background-color: rgba (255, 255, 255, 0); - color: rgba (255, 255, 255, 0.4); +.splash-text { + color: #fff; } -.channel-configure-button:hover { - background-color: rgba (255, 255, 255, 0.2); - color: rgba (255, 255, 255, 1); -} -.channel-modulator-button { - background-color: rgba (50, 80, 50, 1); - outline: 0; -} -.channel-modulator-assignable { - background-color: rgba (50, 80, 50, 1); - background-image: -gtk-icontheme('insert-link-symbolic'); - background-repeat: no-repeat; - background-position: 120% 90%; - background-size: 14px; - box-shadow: inset 0 0 4px rgba (0, 204, 102, 1); -} -.channel-modulator-assignable:hover { - background-color: rgba (100, 80, 0, 1); - background-image: -gtk-icontheme('insert-link-symbolic'); - background-repeat: no-repeat; - background-position: 97% 90%; -} -.channel-modulator-lock { - background-color: rgba (0, 204, 102, 1); - background-image: -gtk-icontheme('changes-allow-symbolic'); - background-repeat: no-repeat; - background-size: 14px; - background-position: 97% 90%; - color: #000; +@keyframes ripple { + from { + background-image:radial-gradient(#202020 0%, #333 5%, #202020 6%); + } + to { + background-image:radial-gradient(#202020 0%, #202020 90%, #202020 100%); + } } .slider-assignable > contents > trough { @@ -201,97 +74,10 @@ } } -.display-bottom-panel-header { - font-size: 0.8em; - font-weight: bold; - color: #bbb; -} - .font-bold { font-weight: bold; } -.display-bottom-panel-label { - font-size: 0.9em; - color: #A4FFFA; -} - -.display-bottom-panel-label-small { - font-size: 0.75em; - color: #A4FFFA; - margin-top: -2px; - margin-bottom: -2px; -} - - -.menu-background { - background-color: #f3f3f3; - color: #333; -} - -.menu-header { - box-shadow: 0 1px alpha(black, 0.1), 0 -1px alpha(white, 0.5); - border-bottom: 1px solid alpha(black, 0.2); - background-color: #e5e5e5; - color: #222; - text-shadow: 0 1px #fff; -} - -.menu-header .title { - text-shadow: 0 1px #fff; -} - -.menu-header > * { - color: #333; - text-shadow: 0 1px #fff; -} - -.menu-header > * > * > * { - color: #333; - text-shadow: 0 1px #fff; -} - -.menu-box { - background-color: #d4d4d4; - color: #f3f3f3; - border: 1px solid #485a6c; -} -.menu-box > .activatable { - padding: 4px; - padding-left: 8px; - color: #333; - border-top: 1px solid alpha(#333, 0.5); -} -.menu-box > .activatable:selected{ - border-top: 1px solid #cc3b02; - box-shadow: inset 0 1px 0 0 #ffa154, - inset 0 -2px 0 0 alpha(#fff, 0.1), - inset 0 -1px 0 0 #a62100; - - background-image: linear-gradient(#f06819, #d94b0a); - color: #fff; -} -.menu-item-label { - font-size: 1.2em; -} -.menu-box > .activatable:selected .menu-item-label { - text-shadow: 0 1px #a62100; -} -.menu-item-description { - font-size: 0.8em; - margin-top: 8px; -} - -.menu-item-annotation { - background-color: alpha(#fff, 0.7); - color: #333; - padding-left: 8px; - padding-right: 8px; - margin-right: -4px; - border-radius: 3px 0 0 3px; - box-shadow: 0 2px 4px alpha(#000, 0.5); -} - .queue-measure { animation: pulse 3s linear infinite; } @@ -521,43 +307,43 @@ } .super-knob-connected-1 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.1) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.1) 40%, #333); } .super-knob-connected-2 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.2) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.2) 40%, #333); } .super-knob-connected-3 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.3) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.3) 40%, #333); } .super-knob-connected-4 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.4) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.4) 40%, #333); } .super-knob-connected-5 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.5) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.5) 40%, #333); } .super-knob-connected-6 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.6) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.6) 40%, #333); } .super-knob-connected-7 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.7) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.7) 40%, #333); } .super-knob-connected-8 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.8) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.8) 40%, #333); } .super-knob-connected-9 { - background-image:radial-gradient(mix(@accent_color, shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), 0.9) 40%, #333); + background-image:radial-gradient(mix(@accent_color, @accent_color_complimentary, 0.9) 40%, #333); } .super-knob-connected-10 { - background-image:radial-gradient(shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2) 40%, #333); + background-image:radial-gradient(@accent_color_complimentary 40%, #333); } @@ -587,28 +373,36 @@ .white-key-normal > * { padding: 0; margin: -8px; - margin-top: -172px; -} -.white-key-normal:active { - background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); - box-shadow: 0 -12px 8px -8px @accent_color, inset 0 -1px 4px @accent_color; + margin-top: -42px; } -.white-key-active { - background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); - box-shadow: 0 -12px 8px -8px @accent_color, inset 0 -1px 4px @accent_color; - outline: 0; +.white-key-normal > *:focus { + background-color: rgba(0,0,0,0); } .white-key-split { background-image:linear-gradient(#585858, #2e2e2e); border: 2px solid #000; } .white-key-split:active { - background-image:linear-gradient(shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.4), shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.0)); - box-shadow: 0 -12px 8px -8px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), inset 0 -1px 4px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2); + background-image:linear-gradient(shade(@accent_color_complimentary, 0.7), shade(@accent_color_complimentary, 0.5)); + box-shadow: 0 -12px 8px -8px alpha(@accent_color_complimentary, 0.7), inset 0 -1px 4px @accent_color_complimentary; } .white-key-split-active { - background-image:linear-gradient(shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.4), shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.0)); - box-shadow: 0 -12px 8px -8px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), inset 0 -1px 4px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2); + background-image:linear-gradient(shade(@accent_color_complimentary, 0.7), shade(@accent_color_complimentary, 0.5)); + box-shadow: 0 -12px 8px -8px alpha(@accent_color_complimentary, 0.7), inset 0 -1px 4px @accent_color_complimentary; +} +.white-key-active-auto { + background-image:linear-gradient(shade(@accent_color_complimentary_alternate, 0.7), shade(@accent_color_complimentary_alternate, 0.5)); + box-shadow: 0 -12px 8px -8px alpha(@accent_color_complimentary_alternate, 0.65), inset 0 -1px 4px @accent_color_complimentary_alternate; + outline: 0; +} +.white-key-normal:active { + background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); + box-shadow: 0 -12px 8px -8px alpha(@accent_color, 0.65), inset 0 -1px 4px @accent_color; +} +.white-key-active { + background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); + box-shadow: 0 -12px 8px -8px alpha(@accent_color, 0.65), inset 0 -1px 4px @accent_color; + outline: 0; } .black-key-normal { background-image:linear-gradient(#444, #141414); @@ -618,15 +412,10 @@ .black-key-normal > * { padding: 0; margin: -8px; - margin-top: -110px; + margin-top: -42px; } -.black-key-normal:active{ - background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); - box-shadow: 0 -14px 12px -6px @accent_color, inset 0 -1px 4px @accent_color; -} -.black-key-active{ - background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); - box-shadow: 0 -14px 12px -6px @accent_color, inset 0 -1px 4px @accent_color; +.black-key-normal > *:focus { + background-color: rgba(0,0,0,0); } .black-key-split { background-image:linear-gradient(#444, #141414); @@ -634,12 +423,42 @@ outline: 0; } .black-key-split:active { - background-image:linear-gradient(shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.4), shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.0)); - box-shadow: 0 -12px 8px -8px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), inset 0 -1px 4px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2); + background-image:linear-gradient(shade(@accent_color_complimentary, 0.7), shade(@accent_color_complimentary, 0.5)); + box-shadow: 0 -14px 12px -6px alpha(@accent_color_complimentary, 0.7), inset 0 -1px 4px @accent_color_complimentary; } .black-key-split-active { - background-image:linear-gradient(shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.4), shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 1.0)); - box-shadow: 0 -12px 8px -8px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2), inset 0 -1px 4px shade(mix(mix(@accent_color, rgb(0, -255, 0), 0.1), rgb(-255, 0, -255), 0.3), 2); + background-image:linear-gradient(shade(@accent_color_complimentary, 0.7), shade(@accent_color_complimentary, 0.5)); + box-shadow: 0 -14px 12px -6px alpha(@accent_color_complimentary, 0.7), inset 0 -1px 4px @accent_color_complimentary; +} +.black-key-active-auto{ + background-image:linear-gradient(shade(@accent_color_complimentary_alternate, 0.7), shade(@accent_color_complimentary_alternate, 0.5)); + box-shadow: 0 -14px 12px -6px alpha(@accent_color_complimentary_alternate, 0.7), inset 0 -1px 4px @accent_color_complimentary_alternate; +} +.black-key-normal:active{ + background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); + box-shadow: 0 -14px 12px -6px alpha(@accent_color, 0.7), inset 0 -1px 4px @accent_color; +} +.black-key-active{ + background-image:linear-gradient(shade(@accent_color, 0.7), shade(@accent_color, 0.5)); + box-shadow: 0 -14px 12px -6px alpha(@accent_color, 0.7), inset 0 -1px 4px @accent_color; +} + +.key_label_primary { + background: @accent_color; + border-radius: 50%; + border: 2px solid #222; +} + +.key_label_secondary { + background: @accent_color_complimentary; + border-radius: 50%; + border: 2px solid #222; +} + +.key_label_auto { + background: @accent_color_complimentary_alternate; + border-radius: 50%; + border: 2px solid #222; } .common-key-split > *{ @@ -670,7 +489,7 @@ } .keyboard-background { - background-image:linear-gradient(#505050 0%, #383838 23px, #000 24px, #333); + background-image:linear-gradient(#666 0%, #333 15px, #222 17px, #333 31px, #000 32px, #333); border-top: 1px solid #222; } @@ -759,97 +578,6 @@ } - -.welcome { - background: #f3f3f3; -} -.welcome > .vertical > .h1 { - color: #333; - font-size: 2em; -} -.welcome > .vertical > .h2 { - color: #333; - font-size: 1.5em; -} -.welcome > .vertical > .vertical > * { - color: #333; -} - -/* MultiTrack Recorder */ -.recorder-background { - background: #333; - border-radius: 6px; -} - -.recorder-background > .activatable > * > image { - opacity: 0; - transition: opacity 0.5s ease; -} - -.recorder-background > .activatable:selected > * > image { - opacity: 1; -} - -.recorder-track { - background: linear-gradient(#666, #444); - border: 1px solid alpha (#fff, 0.4); - border-radius: 4px; - margin: 2px; -} - -.recorder-track > * > * { - color: #fff; -} - -.recorder-track:hover { - background: linear-gradient(#888, #555); - border: 1px solid alpha (#fff, 0.8); -} - -.recorder-track-mute { - box-shadow: 0 0 4px #333; - background: #666; - background-image: -gtk-icontheme('window-close-symbolic'); - opacity: 0.5; - } - -.track-0 { - box-shadow: inset -2px 4px 18px #a56de2; -} -.track-1 { - box-shadow: inset -2px 4px 18px #485a6c; -} -.track-2 { - box-shadow: inset -2px 4px 18px #3689e6; -} -.track-3 { - box-shadow: inset -2px 4px 18px #f9c440; -} -.track-4{ - box-shadow: inset -2px 4px 18px #715344; -} -.track-5 { - box-shadow: inset -2px 4px 18px #de3e80; -} -.track-6 { - box-shadow: inset -2px 4px 18px #68b723; -} -.track-7 { - box-shadow: inset -2px 4px 18px #c6262e; -} -.track-8 { - box-shadow: inset -2px 4px 18px #f37329; -} -.track-9 { - box-shadow: inset -2px 4px 18px #28bca3; -} - - -.recorder-progress-line { - box-shadow: inset -6px 0 4px alpha (#0f0, 0.4); - border-right: 1px solid alpha (#0f0, 0.8); -} - .setings-input-item-key-label { color: #f3f3f3; background: alpha(#000, 0.5); @@ -879,3 +607,53 @@ .input-key-box > .activatable:selected > .horizontal > .keycap { color: #666; } + + +.keyboard-background scrollbar.horizontal slider { + min-height: 15px; + border: none; + margin-bottom: -1px; + border-top: 2px solid @accent_color; + border-radius: 0; + background: alpha(#000, 0); + } + +.keyboard-background scrollbar.horizontal:hover slider { + min-height: 30px; + border: none; + border-top: 0px solid alpha(@accent_color, 0); + margin-bottom: 4px; + background-image:linear-gradient(90deg, alpha(@accent_color, 0.0), alpha(@accent_color, 0.3), alpha(@accent_color, 0.0)); +} + +.keyboard-background scrollbar.horizontal trough { + background: none; + border: none; +} + +.keyboard-background scrolledwindow overshoot.right { + background-image: none; + +} +.keyboard-background scrolledwindow overshoot.left { + background-image: none; +} + +.central-display-preview > * { + border-radius: 8px; + box-shadow: inset 0 1px alpha(#fff, 0.25), inset 0 -1px alpha(#fff, 0.1); +} + +.central-display-preview > * > * { + border-radius: 4px; + margin: 8px; + border: none; + margin-top: -1px; + margin-bottom: -1px; +} + +.central-display-preview { + border-radius: 8px; + box-shadow: 0 4px 8px alpha(#000, 0.75); + border: 1px solid #000; +} diff --git a/data/Themes/DisplayUnit.css b/data/Themes/DisplayUnit.css new file mode 100644 index 00000000..f625418a --- /dev/null +++ b/data/Themes/DisplayUnit.css @@ -0,0 +1,419 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ +/* Do not edit this file */ + + +/* /////////////////////////////////////////////////////////////// +Mother class for the central display section +*/ +.ensembles-central-display { + background-color: #333; + background-image:linear-gradient(#222, #024740, #000, #444); + box-shadow: inset 0 0 0 2px #000; +} + +/* ////////////////////////////////////////////////////////////// +General Gtk Widgets +*/ +/* +Buttons +*/ +.ensembles-central-display button { + border: 1px solid #000; + border-radius: 0; + background: alpha(#007367, 0.6); + box-shadow: none; + text-shadow: none; +} + +.ensembles-central-display button:hover { + background: alpha(#007367, 0.8); +} + +.ensembles-central-display button:active { + background: #007367; +} + +.ensembles-central-display .flat, .ensembles-central-display .image-button { + border: none; + background: alpha(#fff, 0.0); + border-radius: 0; +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:disabled { + opacity: 0.5; +} +.ensembles-central-display .flat:focus, .ensembles-central-display .image-button:focus{ + border: none; + background: alpha(#fff, 0.0); + border-radius: 0; + box-shadow: inset 0 -2px 0 0 #02A594; +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:hover { + background: alpha(#fff, 0.1); + opacity: 1; +} + +/* Entry */ +.ensembles-central-display entry { + background-color: #151515; + background-clip: padding-box; + border: 1px solid #000; + border-radius: 0; + box-shadow: none; + color: #fff; +} + +/* Spin Button */ +.ensembles-central-display spinbutton { + background-color: alpha (#000, 0.2); +} + +.ensembles-central-display spinbutton { + background-color: alpha (#000, 0.4); +} + +.ensembles-central-display spinbutton entry { + background-color: alpha (#000, 0); + border: none; +} + +.ensembles-central-display spinbutton button { + background-color: alpha(#333, 0.5); + border: none; + border-left: 1px solid #222; +} + +.ensembles-central-display spinbutton button:hover { + background-color: #333; + border: none; + border-left: 1px solid #222; +} +.ensembles-central-display spinbutton button:disabled { + background-color: #222; + color: #444; +} + +/* +Terminal +*/ +.ensembles-central-display .terminal { + background-color: #111; + color: #666; + border-radius: 0; +} + +/* ///////////////////////////////////////////////////////////////// +The screen which is shown by default +*/ +.ensembles-central-display .home-screen-background { + background-image: url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash.jpg"); + background-size: auto 100%; + background-position: 50%; +} + +.ensembles-central-display .home-screen-panel-top { + background-image: linear-gradient(alpha(#007367, 0.6),alpha(#007367, 0.6)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 600%; + background-position: 50% 0; + border-bottom: 1px solid alpha(#000, 0.5); +} + +.ensembles-central-display .home-screen-top-panel-header { + font-size: 1.11em; + margin-top: 4px; +} + +.ensembles-central-display .home-screen-top-panel-subheader { + font-size: 0.8em; + margin-bottom: 6px; +} + +.ensembles-central-display .home-screen-top-panel-button { + background: none; + border: 0; + padding: 0; + box-shadow: none; + outline: none; +} + +.ensembles-central-display .home-screen-top-panel-button:hover { + background-color: alpha(#fff, 0.1); +} + +.ensembles-central-display .home-screen-panel-bottom { + background-image: linear-gradient(alpha(#273445, 0.6),alpha(#273445, 0.6)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 250%; + background-position: 50% 100%; + border-top: 1px solid alpha(#000, 0.5); +} + +.ensembles-central-display .home-screen-bottom-panel-header { + font-size: 0.8em; + font-weight: bold; + color: #bbb; +} + +.ensembles-central-display .home-screen-bottom-panel-label { + font-size: 0.9em; + color: #A4FFFA; +} + +.ensembles-central-display .home-screen-bottom-panel-label-small { + font-size: 0.75em; + color: #A4FFFA; + margin-top: -2px; + margin-bottom: -2px; +} + +.ensembles-central-display .home-screen-eq-labels { + margin-top: -5px; +} + +.ensembles-central-display .home-screen-eq-labels > * { + font-size: 0.7em; + color: #CAE974; + border-top: 1px solid #6C9104; +} +.ensembles-central-display .home-screen-channel-button { + background-color: rgba (255, 255, 255, 0); + color: rgba (255, 255, 255, 0.4); +} + +.ensembles-central-display .home-screen-channel-button:hover { + background-color: rgba (255, 255, 255, 0.2); + color: rgba (255, 255, 255, 1); +} + + +/* ///////////////////////////////////////////////////////////////////// +Quick mods are the screens for tempo, modulators and lfo +*/ + +.ensembles-central-display .quick-mod { + background-image: linear-gradient(alpha(#273445, 0.6), alpha(#273445, 0.6)), url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 100%; + background-position: 50%; + padding: 8px; +} +.ensembles-central-display .quick-mod-close-button { + background-color: #007367; + border-radius: 2px 0 0 2px; + margin-right: -2px; +} +.ensembles-central-display .quick-mod-close-button:hover { + background-color: #02A594; +} +.ensembles-central-display .quick-mod-header { + font-size: 1.8em; + margin-left: 4px; + background-image:linear-gradient(90deg, #007367, alpha(#007367, 0)); + padding: 4px; +} +.ensembles-central-display .quick-mod-grid > * { + border: 1px solid #111; + border-radius: 0; + box-shadow: none; + color: #f3f3f3; +} +.ensembles-central-display .quick-mod-grid > spinbutton { + background-color: alpha (#333, 0.4); + border-radius: 0; + box-shadow: none; + color: #00E9D0; +} +.ensembles-central-display .quick-mod-button { + background-color: rgba (50, 80, 50, 1); + outline: 0; +} +.ensembles-central-display .quick-mod-button-assignable { + background-color: rgba (50, 80, 50, 1); + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 120% 90%; + background-size: 14px; + box-shadow: inset 0 0 4px rgba (0, 204, 102, 1); +} +.ensembles-central-display .quick-mod-button-assignable:hover { + background-color: rgba (100, 80, 0, 1); + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 97% 90%; +} +.ensembles-central-display .quick-mod-button-locked { + background-color: rgba (0, 204, 102, 1); + background-image: -gtk-icontheme('changes-allow-symbolic'); + background-repeat: no-repeat; + background-size: 14px; + background-position: 97% 90%; + color: #000; +} + +/* ///////////////////////////////////////////////////////////////////// +Style for Menus like the Style menu, Voice menu or the Recorder +*/ + +.ensembles-central-display .menu-background { + background-color: #222; + color: #fff; +} + +.ensembles-central-display .menu-header { + box-shadow: none; + border-bottom: none; + background-color: #007367; + color: #fff; + text-shadow: 0 1px #fff; +} + +.ensembles-central-display .menu-header .title { + text-shadow: none; +} + +.ensembles-central-display .menu-header > * { + color: #fff; + text-shadow: none; + -gtk-icon-shadow: none; +} + +.ensembles-central-display .menu-header > * > * > * { + color: #fff; + text-shadow: none; + -gtk-icon-shadow: none; +} + +.ensembles-central-display .menu-box { + background-color: #333; + color: #f3f3f3; + border: 1px solid #000000; +} +.ensembles-central-display .menu-box > .activatable { + padding: 4px; + padding-left: 8px; + color: #aaa; + border-top: 1px solid alpha(#000, 0.2); + border-bottom: 1px solid alpha(#000, 0.2); +} +.ensembles-central-display .menu-box > .activatable:selected{ + border-top: 1px solid #000; + border-bottom: 1px solid #000; + box-shadow: none; + background-image: none; + background-color: rgba (100, 80, 0, 1); + color: #fff; +} +.ensembles-central-display .menu-item-label { + font-size: 1.2em; +} +.ensembles-central-display .menu-box > .activatable:selected .menu-item-label { + text-shadow: none; +} +.ensembles-central-display .menu-item-description { + font-size: 0.8em; + margin-top: 8px; +} + +.ensembles-central-display .menu-item-annotation { + background-color: alpha(#fff, 0.7); + color: #333; + padding-left: 8px; + padding-right: 8px; + margin-right: -4px; + border-radius: 3px 0 0 3px; + box-shadow: 0 2px 4px alpha(#000, 0.5); +} + + +/* MultiTrack Recorder ///////////////////////////////////////////////////// + */ +.ensembles-central-display .recorder-background { + background: #333; + border-radius: 6px; +} + +.ensembles-central-display .recorder-background > .activatable > * > image { + opacity: 0; + transition: opacity 0.5s ease; +} + +.ensembles-central-display .recorder-background > .activatable:selected > * > image { + opacity: 1; +} + +.ensembles-central-display .recorder-track { + background: linear-gradient(#666, #444); + border: 1px solid alpha (#fff, 0.4); + border-radius: 4px; + margin: 2px; +} + +.ensembles-central-display .recorder-track > * > * { + color: #fff; +} + +.ensembles-central-display .recorder-track:hover { + background: linear-gradient(#888, #555); + border: 1px solid alpha (#fff, 0.8); +} + +.ensembles-central-display .recorder-track-mute { + box-shadow: 0 0 4px #333; + background: #666; + background-image: -gtk-icontheme('window-close-symbolic'); + opacity: 0.5; +} + +.ensembles-central-display .track-0 { + box-shadow: inset -2px 4px 18px #a56de2; +} +.ensembles-central-display .track-1 { + box-shadow: inset -2px 4px 18px #485a6c; +} +.ensembles-central-display .track-2 { + box-shadow: inset -2px 4px 18px #3689e6; +} +.ensembles-central-display .track-3 { + box-shadow: inset -2px 4px 18px #f9c440; +} +.ensembles-central-display .track-4{ + box-shadow: inset -2px 4px 18px #715344; +} +.ensembles-central-display .track-5 { + box-shadow: inset -2px 4px 18px #de3e80; +} +.ensembles-central-display .track-6 { + box-shadow: inset -2px 4px 18px #68b723; +} +.ensembles-central-display .track-7 { + box-shadow: inset -2px 4px 18px #c6262e; +} +.ensembles-central-display .track-8 { + box-shadow: inset -2px 4px 18px #f37329; +} +.ensembles-central-display .track-9 { + box-shadow: inset -2px 4px 18px #28bca3; +} + + +.ensembles-central-display .recorder-progress-line { + box-shadow: inset -6px 0 4px alpha (#0f0, 0.4); + border-right: 1px solid alpha (#0f0, 0.8); +} + +/* Welcome Screen ////////////////////////////////////////////////////// + */ +.ensembles-central-display .welcome { + background: #222; +} +.ensembles-central-display .welcome > .vertical > .h1 { + color: #f3f3f3; + font-size: 1.6em; +} +.ensembles-central-display .welcome > .vertical > .h2 { + color: #f3f3f3; + font-size: 1.2em; +} +.ensembles-central-display .welcome > .vertical > .vertical > * { + color: #f3f3f3; +} diff --git a/data/Themes/DisplayUnitElementaryDark.css b/data/Themes/DisplayUnitElementaryDark.css new file mode 100644 index 00000000..6029d385 --- /dev/null +++ b/data/Themes/DisplayUnitElementaryDark.css @@ -0,0 +1,363 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* /////////////////////////////////////////////////////////////// +Mother class for the central display section +*/ +.ensembles-central-display { + background-color: #333; + background-image:linear-gradient(#111, #333, #000); + box-shadow: inset 0 0 0 2px #000; + color: #f3f3f3; +} + +/* ////////////////////////////////////////////////////////////// +General Gtk Widgets +*/ +/* +Buttons +*/ +.ensembles-central-display spinbutton { +margin-bottom: 8px; +} + +.ensembles-central-display button:hover { + +} + +.ensembles-central-display button:active { + +} + +.ensembles-central-display .flat, .ensembles-central-display .image-button { + +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:disabled { + opacity: 0.5; +} +.ensembles-central-display .flat:focus, .ensembles-central-display .image-button:focus{ + +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:hover { + background: alpha(#fff, 0.1); +} + +/* ///////////////////////////////////////////////////////////////// +The screen which is shown by default +*/ +.ensembles-central-display .home-screen-background { + background-image: url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash.jpg"); + background-size: auto 100%; + background-position: 50%; +} + +.ensembles-central-display .home-screen-panel-top { + background-image: linear-gradient(#444, alpha(#333, 0.6) 50px),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 600%; +box-shadow: inset 0 1px rgba(255,255,255, 0.2), +inset 0 -1px rgba(255,255,255, 0.1), +0 1px alpha(#000, 0.1); + background-position: 50% 0; + border-bottom: 1px solid alpha(#000, 0.5); +} + +.ensembles-central-display .home-screen-top-panel-header { + font-size: 1.11em; + margin-top: 4px; +color: #f3f3f3; +text-shadow: 0 -1px #000; +} + +.ensembles-central-display .home-screen-top-panel-subheader { + font-size: 0.8em; + margin-bottom: 6px; +color: #ccc; +} + +.ensembles-central-display .home-screen-top-panel-button { + background: none; + border: 0; + padding: 0; + box-shadow: none; + outline: none; +border-radius: 0; +} + +.ensembles-central-display .home-screen-top-panel-button:hover { + background-color: alpha(#fff, 0.1); +} + +.ensembles-central-display .home-screen-panel-bottom { + background-image: linear-gradient(alpha(#333, 0.5) 150px,alpha(#222, 0.8)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 250%; + background-position: 50% 100%; + border-top: 1px solid alpha(#000, 0.5); +box-shadow: inset 0 1px rgba(255,255,255, 0.2); +} + +.ensembles-central-display .home-screen-bottom-panel-header { + font-size: 0.8em; + font-weight: bold; + color: #bbb; +} + +.ensembles-central-display .home-screen-bottom-panel-label { + font-size: 0.9em; + color: shade(@accent_color, 1.2); +} + +.ensembles-central-display .home-screen-bottom-panel-label-small { + font-size: 0.75em; + color: shade(@accent_color, 1.2); + margin-top: -2px; + margin-bottom: -2px; +} + +.ensembles-central-display .home-screen-eq-labels { + margin-top: -5px; +} + +.ensembles-central-display .home-screen-eq-labels > * { + font-size: 0.7em; + color: #CAE974; + border-top: 1px solid #6C9104; +} +.ensembles-central-display .home-screen-channel-button { + background-color: rgba (255, 255, 255, 0); + color: rgba (255, 255, 255, 0.4); +} + +.ensembles-central-display .home-screen-channel-button:hover { + background-color: rgba (255, 255, 255, 0.2); + color: rgba (255, 255, 255, 1); +} + + +/* ///////////////////////////////////////////////////////////////////// +Quick mods are the screens for tempo, modulators and lfo +*/ + +.ensembles-central-display .quick-mod { + background-image: linear-gradient(275deg, alpha(#333, 0.5), alpha(#333, 1)), url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 100%; + background-position: 50%; + padding: 8px; +} +.ensembles-central-display .quick-mod-close-button { + background-color: rgba(0,0,0,0); +background-image:linear-gradient(#555, #3f3f3f); +color: #fff; + border-radius: 4px 0 0 4px; +box-shadow: inset 0 1px rgba(255,255,255, 0.2), inset 0 -1px rgba(255,255,255,0.1); +border: 1px solid alpha(#000, 0.5); + margin-right: -2px; +-gtk-icon-shadow: 0 1px #000; +} +.ensembles-central-display .quick-mod-close-button:hover { + background-image:linear-gradient(#666, #3f3f3f); +} +.ensembles-central-display .quick-mod-close-button:active { + background-image:linear-gradient(#555, #444); +border-radius: 4px 0 0 4px; +} +.ensembles-central-display .quick-mod-header { + font-size: 1.8em; + margin-left: 4px; +border-radius: 0 4px 4px 0; + background-image:linear-gradient(#555, #3f3f3f); +box-shadow: inset 0 1px rgba(255,255,255, 0.2), inset 0 -1px rgba(255,255,255,0.1); +border: 1px solid alpha(#000, 0.5); +color: #f3f3f3; + padding: 4px; +text-shadow: 0 -1px #222; +} +.ensembles-central-display .quick-mod-button { +margin-top: 8px; +margin-bottom: 4px; +} +.ensembles-central-display .quick-mod-button-assignable { + background-color: shade(@accent_color_complimentary, 0.8); + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 120% 90%; + background-size: 14px; +} +.ensembles-central-display .quick-mod-button-assignable:hover { + background-color: @accent_color_complimentary; + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 97% 90%; +} +.ensembles-central-display .quick-mod-button-locked { + background-color: @accent_color_complimentary_alternate; + background-image: -gtk-icontheme('changes-allow-symbolic'); + background-repeat: no-repeat; + background-size: 14px; + background-position: 97% 90%; + color: #222; +} + +/* ///////////////////////////////////////////////////////////////////// +Style for Menus like the Style menu, Voice menu or the Recorder +*/ + +.ensembles-central-display .menu-background { +background: #333; +} + +.ensembles-central-display .menu-header { +box-shadow: inset 0 1px alpha(#fff, 0.1), inset 0 -1px alpha(#fff, 0.05); +border-bottom: 1px solid alpha(black, 0.1); +} + +.ensembles-central-display .menu-header .title { + +} + +.ensembles-central-display .menu-header > * { + color: #f3f3f3; +} + +.ensembles-central-display .menu-header > * > * > * { + color: #f3f3f3; +} + +.ensembles-central-display .menu-box { + background-color: #2a2a2a; + border: 1px solid #000; +} +.ensembles-central-display .menu-box > .activatable { + padding: 4px; + padding-left: 8px; + color: #fff; + border-top: 1px solid alpha(#000, 0.2); + border-bottom: 1px solid alpha(#000, 0.2); +} +.ensembles-central-display .menu-box > .activatable:selected{ + border-top: 1px solid shade(@accent_color, 1); + border-bottom: 1px solid shade(@accent_color, 1); + box-shadow: inset 0 1px 0 0 shade(@accent_color, 1.3), + inset 0 -2px 0 0 alpha(#fff, 0.1), + inset 0 -1px 0 0 shade(@accent_color, 0.8); + background-image:linear-gradient(shade(@accent_color, 1.2), shade(@accent_color, 1)); + color: #fff; +text-shadow: 0 1px alpha(black, 0.2); +} +.ensembles-central-display .menu-item-label { + font-size: 1.2em; +text-shadow: 0 1px alpha(black, 0.2); +} +.ensembles-central-display .menu-box > .activatable:selected .menu-item-label { + text-shadow: 0 1px alpha(black, 0.25); +} +.ensembles-central-display .menu-item-description { + font-size: 0.8em; + margin-top: 8px; +} + +.ensembles-central-display .menu-item-annotation { + background-color: alpha(#fff, 0.7); + color: #333; + padding-left: 8px; + padding-right: 8px; + margin-right: -4px; + border-radius: 3px 0 0 3px; + box-shadow: 0 2px 4px alpha(#000, 0.5); +} + + +/* MultiTrack Recorder ///////////////////////////////////////////////////// + */ +.ensembles-central-display .recorder-background { + background: #222; + border-radius: 6px; +} + +.ensembles-central-display .recorder-background > .activatable > * > image { + opacity: 0; + transition: opacity 0.5s ease; +} + +.ensembles-central-display .recorder-background > .activatable:selected > * > image { + opacity: 1; +} + +.ensembles-central-display .recorder-track { + background: linear-gradient(#666, #444); + border: 1px solid alpha (#fff, 0.4); + border-radius: 4px; + margin: 2px; +} + +.ensembles-central-display .recorder-track > * > * { + color: #fff; +} + +.ensembles-central-display .recorder-track:hover { + background: linear-gradient(#888, #555); + border: 1px solid alpha (#fff, 0.8); +} + +.ensembles-central-display .recorder-track-mute { + box-shadow: 0 0 4px #333; + background: #666; + background-image: -gtk-icontheme('window-close-symbolic'); + opacity: 0.5; +} + +.ensembles-central-display .track-0 { + box-shadow: inset -2px 4px 18px #a56de2; +} +.ensembles-central-display .track-1 { + box-shadow: inset -2px 4px 18px #485a6c; +} +.ensembles-central-display .track-2 { + box-shadow: inset -2px 4px 18px #3689e6; +} +.ensembles-central-display .track-3 { + box-shadow: inset -2px 4px 18px #f9c440; +} +.ensembles-central-display .track-4{ + box-shadow: inset -2px 4px 18px #715344; +} +.ensembles-central-display .track-5 { + box-shadow: inset -2px 4px 18px #de3e80; +} +.ensembles-central-display .track-6 { + box-shadow: inset -2px 4px 18px #68b723; +} +.ensembles-central-display .track-7 { + box-shadow: inset -2px 4px 18px #c6262e; +} +.ensembles-central-display .track-8 { + box-shadow: inset -2px 4px 18px #f37329; +} +.ensembles-central-display .track-9 { + box-shadow: inset -2px 4px 18px #28bca3; +} + + +.ensembles-central-display .recorder-progress-line { + box-shadow: inset -6px 0 4px alpha (#0f0, 0.4); + border-right: 1px solid alpha (#0f0, 0.8); +} + +/* Welcome Screen ////////////////////////////////////////////////////// + */ +.ensembles-central-display .welcome { + background: #333; +} +.ensembles-central-display .welcome > .vertical > .h1 { + color: #fff; + font-size: 1.6em; +} +.ensembles-central-display .welcome > .vertical > .h2 { + color: #f3f3f3; + font-size: 1.2em; +} +.ensembles-central-display .welcome > .vertical > .vertical > * { + color: #fff; +opacity: 1; +} diff --git a/data/Themes/DisplayUnitElementaryLight.css b/data/Themes/DisplayUnitElementaryLight.css new file mode 100644 index 00000000..54256cc2 --- /dev/null +++ b/data/Themes/DisplayUnitElementaryLight.css @@ -0,0 +1,432 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* /////////////////////////////////////////////////////////////// +Mother class for the central display section +*/ +.ensembles-central-display { + background-color: #333; + background-image:linear-gradient(#222, #777, #000, #444); + box-shadow: inset 0 0 0 2px #000; + color: #222; +} + +/* ////////////////////////////////////////////////////////////// +General Gtk Widgets +*/ +/* +Buttons +*/ +.ensembles-central-display button { + border: 1px solid alpha(#000, 0.25); +background-color: #fff; +color: #1d1d1d; +border-radius: 4px; +box-shadow: 0 1px 1px alpha(#000, 0.25); +text-shadow: none; +} + +.ensembles-central-display button:hover { + background-color: #fff; +} + +.ensembles-central-display button:active { + background-color: #f3f3f3; +box-shadow: 0 1px alpha(#000, 0.1); +} + +.ensembles-central-display .flat, .ensembles-central-display .image-button { + border: none; + background: alpha(#fff, 0.0); + border-radius: 4px; + box-shadow: none; +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:disabled { + opacity: 0.5; +} +.ensembles-central-display .flat:focus, .ensembles-central-display .image-button:focus{ + border: none; + background: alpha(#fff, 0.0); + border-radius: 4px; + box-shadow: inset 0 0 0 2px @accent_color; +} +.ensembles-central-display .flat:hover, .ensembles-central-display .image-button:hover { + background: alpha(#fff, 0.1); + opacity: 1; +} + +/* Entry */ +.ensembles-central-display entry { + background-color: #fff; + background-clip: padding-box; + border: 1px solid alpha(#000, 0.5); + border-radius: 4px; + box-shadow: inset 0 -1px #666; + color: #333; + caret-color: #666; +} + +/* Spin Button */ +.ensembles-central-display spinbutton { + background-color: #fff; +color: #333; +box-shadow: inset 0 0 1px 1px alpha(#666, 0.2); +border: 1px solid alpha(#000, 0.2); +border-radius: 4px; +margin-bottom: 8px; +} + +.ensembles-central-display spinbutton entry { + background-color: alpha (#000, 0); +color: #333; +border: none; +box-shadow: none; +} + +.ensembles-central-display spinbutton button { + border: none; +background: none; +border-radius: 0 4px 4px 0; +border-left: 1px solid #ccc; +} + +.ensembles-central-display spinbutton button:disabled { + color: #ccc; +} + +/* +Terminal +*/ +.ensembles-central-display .terminal { + background-color: #fdf6e3; + color: #002b36; +} + +/* ///////////////////////////////////////////////////////////////// +The screen which is shown by default +*/ +.ensembles-central-display .home-screen-background { + background-image: url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash.jpg"); + background-size: auto 100%; + background-position: 50%; +} + +.ensembles-central-display .home-screen-panel-top { + background-image: linear-gradient(#eaeaea, alpha(#e9e9e9, 0.6) 50px),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 600%; +box-shadow: inset 0 1px rgba(255,255,255, 0.5), +inset 0 -1px rgba(255,255,255, 0.25), +0 1px alpha(#000, 0.1); + background-position: 50% 0; + border-bottom: 1px solid alpha(#000, 0.5); +} + +.ensembles-central-display .home-screen-top-panel-header { + font-size: 1.11em; + margin-top: 4px; +color: #333; +text-shadow: 0 1px #f3f3f3; +} + +.ensembles-central-display .home-screen-top-panel-subheader { + font-size: 0.8em; + margin-bottom: 6px; +color: #666; +} + +.ensembles-central-display .home-screen-top-panel-button { + background: none; + border: 0; + padding: 0; + box-shadow: none; + outline: none; +} + +.ensembles-central-display .home-screen-top-panel-button:hover { + background-color: alpha(#000, 0.1); +} + +.ensembles-central-display .home-screen-panel-bottom { + background-image: linear-gradient(alpha(#666, 0.5) 150px,alpha(#333, 0.8)),url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 250%; + background-position: 50% 100%; + border-top: 1px solid alpha(#000, 0.5); +box-shadow: inset 0 1px rgba(255,255,255, 0.2); +} + +.ensembles-central-display .home-screen-bottom-panel-header { + font-size: 0.8em; + font-weight: bold; + color: #bbb; +} + +.ensembles-central-display .home-screen-bottom-panel-label { + font-size: 0.9em; + color: shade(@accent_color, 1.2); +} + +.ensembles-central-display .home-screen-bottom-panel-label-small { + font-size: 0.75em; + color: shade(@accent_color, 1.2); + margin-top: -2px; + margin-bottom: -2px; +} + +.ensembles-central-display .home-screen-eq-labels { + margin-top: -5px; +} + +.ensembles-central-display .home-screen-eq-labels > * { + font-size: 0.7em; + color: #CAE974; + border-top: 1px solid #6C9104; +} +.ensembles-central-display .home-screen-channel-button { + background-color: rgba (255, 255, 255, 0); + color: rgba (255, 255, 255, 0.4); +} + +.ensembles-central-display .home-screen-channel-button:hover { + background-color: rgba (255, 255, 255, 0.2); + color: rgba (255, 255, 255, 1); +} + + +/* ///////////////////////////////////////////////////////////////////// +Quick mods are the screens for tempo, modulators and lfo +*/ + +.ensembles-central-display .quick-mod { + background-image: linear-gradient(275deg, alpha(#f3f3f3, 0.5), alpha(#fff, 1)), url("resource://com/github/subhadeepjasu/ensembles/images/display_unit/catalin-sandru-7SxSkCvVM1U-unsplash-blurred.jpg"); + background-size: auto 100%; + background-position: 50%; + padding: 8px; +} +.ensembles-central-display .quick-mod-close-button { + background-color: rgba(0,0,0,0); +background-image:linear-gradient(#eee, #bbb); +color: #333; + border-radius: 4px 0 0 4px; +box-shadow: inset 0 1px rgb(255,255,255), inset 0 -1px rgba(255,255,255,0.5); +border: 1px solid alpha(#000, 0.2); + margin-right: -2px; +-gtk-icon-shadow: 0 1px #fff; +} +.ensembles-central-display .quick-mod-close-button:hover { + background-image:linear-gradient(#f3f3f3, #ccc); +} +.ensembles-central-display .quick-mod-close-button:active { + background-image:linear-gradient(#eee, #ccc); +border-radius: 4px 0 0 4px; +} +.ensembles-central-display .quick-mod-header { + font-size: 1.8em; + margin-left: 4px; +border-radius: 0 4px 4px 0; + background-image:linear-gradient(#eee, #bbb); +box-shadow: inset 0 1px rgb(255,255,255), inset 0 -1px rgba(255,255,255,0.5); +border: 1px solid alpha(#000, 0.2); +color: #333; + padding: 4px; +text-shadow: 0 1px #fff; +} +.ensembles-central-display .quick-mod-button { + border: 1px solid alpha(#000, 0.25); +background-color: #fff; +color: #1d1d1d; +border-radius: 4px; +margin-bottom: 4px; +margin-top: 8px; +box-shadow: 0 1px 2px alpha(#000, 0.25); +} +.ensembles-central-display .quick-mod-button-assignable { + background-color: @accent_color_complimentary; + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 120% 90%; + background-size: 14px; +} +.ensembles-central-display .quick-mod-button-assignable:hover { + background-color: shade(@accent_color_complimentary, 1.1); + background-image: -gtk-icontheme('insert-link-symbolic'); + background-repeat: no-repeat; + background-position: 97% 90%; +} +.ensembles-central-display .quick-mod-button-locked { + background-color: @accent_color_complimentary_alternate; + background-image: -gtk-icontheme('changes-allow-symbolic'); + background-repeat: no-repeat; + background-size: 14px; + background-position: 97% 90%; + color: #000; +} + +/* ///////////////////////////////////////////////////////////////////// +Style for Menus like the Style menu, Voice menu or the Recorder +*/ + +.ensembles-central-display .menu-background { + background-color: #f3f3f3; + color: #1d1d1d; +} + +.ensembles-central-display .menu-header { + box-shadow: 0 1px alpha(black, 0.1), 0 -1px alpha(white, 0.5); + border-bottom: 1px solid alpha(black, 0.2); + background-color: #e5e5e5; + color: #222; + text-shadow: 0 1px #fff; +} + +.ensembles-central-display .menu-header .title { + text-shadow: 0 1px #fff; +} + +.ensembles-central-display .menu-header > * { + color: #222; + text-shadow: none; + -gtk-icon-shadow: none; +} + +.ensembles-central-display .menu-header > * > * > * { + color: #222; + text-shadow: none; + -gtk-icon-shadow: none; +} + +.ensembles-central-display .menu-box { + background-color: #d4d4d4; + border: 1px solid #666; +} +.ensembles-central-display .menu-box > .activatable { + padding: 4px; + padding-left: 8px; + color: #222; + border-top: 1px solid alpha(#000, 0.2); + border-bottom: 1px solid alpha(#000, 0.2); +} +.ensembles-central-display .menu-box > .activatable:selected{ + border-top: 1px solid shade(@accent_color, 1); + border-bottom: 1px solid shade(@accent_color, 1); + box-shadow: inset 0 1px 0 0 shade(@accent_color, 1.3), + inset 0 -2px 0 0 alpha(#fff, 0.1), + inset 0 -1px 0 0 shade(@accent_color, 0.8); + background-image:linear-gradient(shade(@accent_color, 1.2), shade(@accent_color, 1)); + color: #fff; +} +.ensembles-central-display .menu-item-label { + font-size: 1.2em; +} +.ensembles-central-display .menu-box > .activatable:selected .menu-item-label { + text-shadow: none; +} +.ensembles-central-display .menu-item-description { + font-size: 0.8em; + margin-top: 8px; +} + +.ensembles-central-display .menu-item-annotation { + background-color: alpha(#fff, 0.7); + color: #333; + padding-left: 8px; + padding-right: 8px; + margin-right: -4px; + border-radius: 3px 0 0 3px; + box-shadow: 0 2px 4px alpha(#000, 0.5); +} + + +/* MultiTrack Recorder ///////////////////////////////////////////////////// + */ +.ensembles-central-display .recorder-background { + background: #333; + border-radius: 6px; +} + +.ensembles-central-display .recorder-background > .activatable > * > image { + opacity: 0; + transition: opacity 0.5s ease; +} + +.ensembles-central-display .recorder-background > .activatable:selected > * > image { + opacity: 1; +} + +.ensembles-central-display .recorder-track { + background: linear-gradient(#666, #444); + border: 1px solid alpha (#fff, 0.4); + border-radius: 4px; + margin: 2px; +} + +.ensembles-central-display .recorder-track > * > * { + color: #fff; +} + +.ensembles-central-display .recorder-track:hover { + background: linear-gradient(#888, #555); + border: 1px solid alpha (#fff, 0.8); +} + +.ensembles-central-display .recorder-track-mute { + box-shadow: 0 0 4px #333; + background: #666; + background-image: -gtk-icontheme('window-close-symbolic'); + opacity: 0.5; +} + +.ensembles-central-display .track-0 { + box-shadow: inset -2px 4px 18px #a56de2; +} +.ensembles-central-display .track-1 { + box-shadow: inset -2px 4px 18px #485a6c; +} +.ensembles-central-display .track-2 { + box-shadow: inset -2px 4px 18px #3689e6; +} +.ensembles-central-display .track-3 { + box-shadow: inset -2px 4px 18px #f9c440; +} +.ensembles-central-display .track-4{ + box-shadow: inset -2px 4px 18px #715344; +} +.ensembles-central-display .track-5 { + box-shadow: inset -2px 4px 18px #de3e80; +} +.ensembles-central-display .track-6 { + box-shadow: inset -2px 4px 18px #68b723; +} +.ensembles-central-display .track-7 { + box-shadow: inset -2px 4px 18px #c6262e; +} +.ensembles-central-display .track-8 { + box-shadow: inset -2px 4px 18px #f37329; +} +.ensembles-central-display .track-9 { + box-shadow: inset -2px 4px 18px #28bca3; +} + + +.ensembles-central-display .recorder-progress-line { + box-shadow: inset -6px 0 4px alpha (#0f0, 0.4); + border-right: 1px solid alpha (#0f0, 0.8); +} + +/* Welcome Screen ////////////////////////////////////////////////////// + */ +.ensembles-central-display .welcome { + background: #f3f3f3; +} +.ensembles-central-display .welcome > .vertical > .h1 { + color: #222; + font-size: 1.6em; +} +.ensembles-central-display .welcome > .vertical > .h2 { + color: #222; + font-size: 1.2em; +} +.ensembles-central-display .welcome > .vertical > .vertical > * { + color: #222; +} diff --git a/data/com.github.subhadeepjasu.ensembles.appdata.xml.in b/data/com.github.subhadeepjasu.ensembles.appdata.xml.in index 600a04bb..1c89a1fc 100644 --- a/data/com.github.subhadeepjasu.ensembles.appdata.xml.in +++ b/data/com.github.subhadeepjasu.ensembles.appdata.xml.in @@ -56,6 +56,10 @@ Multi-track Recorder https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotMultiTrackRecorder.png + + Voice Menu and MIDI File Player + https://raw.githubusercontent.com/SubhadeepJasu/Ensembles/master/screenshots/ScreenshotVoice.png + none @@ -87,6 +91,37 @@ none + + +

Fixed:

+ +

Improved:

+ +

New:

+ + +

HotFix:

diff --git a/data/com.github.subhadeepjasu.ensembles.gresource.xml b/data/com.github.subhadeepjasu.ensembles.gresource.xml index bd4c1006..babcf741 100644 --- a/data/com.github.subhadeepjasu.ensembles.gresource.xml +++ b/data/com.github.subhadeepjasu.ensembles.gresource.xml @@ -1,7 +1,7 @@ - Application.css + Themes/Application.css diff --git a/data/com.github.subhadeepjasu.ensembles.gschema.xml b/data/com.github.subhadeepjasu.ensembles.gschema.xml index 04b23ef5..f8dc1fed 100644 --- a/data/com.github.subhadeepjasu.ensembles.gschema.xml +++ b/data/com.github.subhadeepjasu.ensembles.gschema.xml @@ -35,6 +35,10 @@ Window maximized If window should be maximized + + "Default" + Display Unit Theme + @@ -47,40 +51,16 @@ Voice Right 1 Main instrument (usually played with right hand if split) - - 0 - Voice Right 1 - - - 0 - Voice Right 1 - 49 Voice Right 2 Instrument played along with main instrument on a layer - - 0 - Voice Right 2 - - - 0 - Voice Right 2 - 33 Voice L Instrument played on the left side of keyboard split - - 0 - Voice Left - - - 0 - Voice Left - 0 Style @@ -108,7 +88,7 @@ Keyboard shifted by entire octaves - 5 + 7 Reverb Level Magnitude of global reverb effect @@ -118,7 +98,7 @@ Global reverb effect - 1 + 2 Chorus Level Magnitude of global chorus effect @@ -174,12 +154,13 @@ Audio interface driver - 0.0 + 0.15 Size of buffer to be processed by the driver + It is a multiplier with range 0 to 1 - 64 - Size of buffer to be processed by the driver + 225 + Previously processed buffer length diff --git a/data/meson.build b/data/meson.build index 224993bd..3c2da69a 100644 --- a/data/meson.build +++ b/data/meson.build @@ -31,26 +31,45 @@ i18n.merge_file ( install_dir: join_paths (get_option ('datadir'), 'metainfo') ) +# Install Settings schema install_data ( meson.project_name() + '.gschema.xml', install_dir: join_paths (get_option ('datadir'), 'glib-2.0', 'schemas') ) +# Install Display theme files +install_data ( + join_paths ('Themes', 'DisplayUnit.css'), + install_dir: join_paths (get_option ('datadir'), meson.project_name (), 'themes') +) +install_data ( + join_paths ('Themes', 'DisplayUnitElementaryLight.css'), + install_dir: join_paths (get_option ('datadir'), meson.project_name (), 'themes') +) +install_data ( + join_paths ('Themes', 'DisplayUnitElementaryDark.css'), + install_dir: join_paths (get_option ('datadir'), meson.project_name (), 'themes') +) + +# Install documents install_subdir ( 'docs', install_dir: join_paths (get_option ('datadir'), meson.project_name ()) ) +# Install Intrument Thumbnails install_subdir( join_paths('Images', 'Instruments'), install_dir: join_paths (get_option ('datadir'), meson.project_name ()) ) +# Install Metronome/LFO patterns install_subdir ( join_paths ('MetronomesAndLFO'), install_dir: join_paths (get_option ('datadir'), meson.project_name ()) ) +# Install accompaniment styles install_subdir ( join_paths ('Styles', 'StyleFiles'), install_dir: join_paths (get_option ('datadir'), meson.project_name ()) diff --git a/meson.build b/meson.build index af64f410..aa4b30be 100644 --- a/meson.build +++ b/meson.build @@ -2,9 +2,14 @@ project ( 'com.github.subhadeepjasu.ensembles', 'c', 'vala', - version: '0.0.16', + version: '0.0.17', ) +# Common Display Version +display_version = 'AW-200' + +message ('Unit Version: ' + display_version) + # GNOME module gnome = import ('gnome') @@ -23,6 +28,7 @@ add_project_arguments ( # 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' ) diff --git a/po/POTFILES b/po/POTFILES index 43b90694..e0586446 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -14,7 +14,7 @@ src/Shell/Views/AppMenuView.vala src/Shell/Views/BeatCounterView.vala src/Shell/Views/ControlPanel.vala src/Shell/Views/JoyStick.vala -src/Shell/Views/KeyboardView.vala +src/Shell/Views/KeyBed.vala src/Shell/Views/RegistryView.vala src/Shell/Views/SamplerPadView.vala src/Shell/Views/SliderBoardView.vala diff --git a/po/com.github.subhadeepjasu.ensembles.pot b/po/com.github.subhadeepjasu.ensembles.pot index d7992437..848e5798 100644 --- a/po/com.github.subhadeepjasu.ensembles.pot +++ b/po/com.github.subhadeepjasu.ensembles.pot @@ -404,19 +404,19 @@ msgstr "" msgid "Y-Assign" msgstr "" -#: src/Shell/Views/KeyboardView.vala:59 +#: src/Shell/Views/KeyBed.vala:59 msgid "SUST" msgstr "" -#: src/Shell/Views/KeyboardView.vala:60 +#: src/Shell/Views/KeyBed.vala:60 msgid "STOP" msgstr "" -#: src/Shell/Views/KeyboardView.vala:66 +#: src/Shell/Views/KeyBed.vala:66 msgid "H O L D" msgstr "" -#: src/Shell/Views/KeyboardView.vala:68 +#: src/Shell/Views/KeyBed.vala:68 msgid "Z O O M" msgstr "" diff --git a/screenshots/Screenshot.png b/screenshots/Screenshot.png index 632aac10..b519c7e5 100644 Binary files a/screenshots/Screenshot.png and b/screenshots/Screenshot.png differ diff --git a/screenshots/ScreenshotChannelModulators.png b/screenshots/ScreenshotChannelModulators.png index 6e4b6f30..70b1e9dc 100644 Binary files a/screenshots/ScreenshotChannelModulators.png and b/screenshots/ScreenshotChannelModulators.png differ diff --git a/screenshots/ScreenshotLFO.png b/screenshots/ScreenshotLFO.png index 6197f33f..e51b3571 100644 Binary files a/screenshots/ScreenshotLFO.png and b/screenshots/ScreenshotLFO.png differ diff --git a/screenshots/ScreenshotMultiTrackRecorder.png b/screenshots/ScreenshotMultiTrackRecorder.png index 6008fa22..58d99652 100644 Binary files a/screenshots/ScreenshotMultiTrackRecorder.png and b/screenshots/ScreenshotMultiTrackRecorder.png differ diff --git a/screenshots/ScreenshotStyles.png b/screenshots/ScreenshotStyles.png index 05778d43..210921ad 100644 Binary files a/screenshots/ScreenshotStyles.png and b/screenshots/ScreenshotStyles.png differ diff --git a/screenshots/ScreenshotVoice.png b/screenshots/ScreenshotVoice.png new file mode 100644 index 00000000..11694cd6 Binary files /dev/null and b/screenshots/ScreenshotVoice.png differ diff --git a/src/Application.vala b/src/Application.vala new file mode 100644 index 00000000..24a3b4aa --- /dev/null +++ b/src/Application.vala @@ -0,0 +1,201 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* + * This file is part of Ensembles + */ + +namespace Ensembles { + public class Application : Gtk.Application { + static Application _instance = null; + + public static Application instance { + get { + if (_instance == null) { + _instance = new Application (); + } + return _instance; + } + } + public static Settings settings; + + // Ensembles Core + public static Core.ArrangerCore arranger_core; + + // Ensembles Shell + public static Shell.MainWindow main_window; + + static Gtk.CssProvider main_css_provider; + static Gtk.CssProvider complimentary_css_provider; + const string COMPLIMENTARY_ACCENT_COLORS = + " + @define-color accent_color_complimentary %s; + @define-color accent_color_complimentary_alternate %s; + "; + + string[] ? arg_file = null; + + construct { + flags |= ApplicationFlags.HANDLES_OPEN; + application_id = "com.github.subhadeepjasu.ensembles"; + settings = new Settings (application_id); + } + + protected override void activate () { + // Make a new Main Window only if none present + if (main_window == null) { + arranger_core = new Core.ArrangerCore (); + Hdy.init (); + Gtk.Settings settings = Gtk.Settings.get_default (); + // Force dark theme + settings.gtk_application_prefer_dark_theme = true; + main_window = new Ensembles.Shell.MainWindow (); + this.add_window (main_window); + + // This enables the use of keyboard media keys to control the style and song player + var media_key_listener = Interfaces.MediaKeyListener.listen (); + media_key_listener.media_key_pressed_play.connect (main_window.media_toggle_play); + media_key_listener.media_key_pressed_pause.connect (main_window.media_pause); + media_key_listener.media_key_pressed_prev.connect (main_window.media_prev); + + // This enables the free-desktop sound indicator integration with style and song player + var sound_indicator_listener = Interfaces.SoundIndicator.listen (main_window); + arranger_core.song_player_state_changed.connect_after (sound_indicator_listener.change_song_state); + + // Initialize theme, before the window has been shown + init_theme (); + + // Show the shell + main_window.present (); + + // ..and then load the data + new Thread ("load-data", arranger_core.load_data); + } + } + + public override void open (File[] files, string hint) { + // Start the app first + activate (); + + // Open file if it's valid and exists + if (files [0].query_exists ()) { + arranger_core.open_file (files [0]); + } + } + + public override int command_line (ApplicationCommandLine cmd) { + string[] args_cmd = cmd.get_arguments (); + unowned string[] args = args_cmd; + + GLib.OptionEntry [] options = new OptionEntry [2]; + options [0] = { "", 0, 0, OptionArg.STRING_ARRAY, ref arg_file, null, "URI" }; + options [1] = { 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 (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; + } + + // Find out if the application is running in a Flatpak sandbox + public static bool get_is_running_from_flatpak () { + var flatpak_info = File.new_for_path ("/.flatpak-info"); + return flatpak_info.query_exists (); + } + + // Initialise main theme of the application + public static void init_theme () { + GLib.Value value = GLib.Value (GLib.Type.STRING); + string theme_color = ""; + Gtk.Settings.get_default ().get_property ("gtk-theme-name", ref value); + theme_color = value.get_string ().replace ("io.elementary.stylesheet.", ""); + if (!value.get_string ().has_prefix ("io.elementary.")) { + Gtk.Settings.get_default ().set_property ("gtk-icon-theme-name", "elementary"); + Gtk.Settings.get_default ().set_property ("gtk-theme-name", "io.elementary.stylesheet.blueberry"); + theme_color = "blueberry"; + } + + // Initialise display theme at launch + var selected_theme = settings.get_string ("display-theme"); + selected_theme = Utils.set_display_theme (selected_theme); + settings.set_string ("display-theme", selected_theme); + + if (main_css_provider == null) { + main_css_provider = new Gtk.CssProvider (); + main_css_provider.load_from_resource ("/com/github/subhadeepjasu/ensembles/Application.css"); + Gtk.StyleContext.add_provider_for_screen ( + Gdk.Screen.get_default (), + main_css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + } + + // Set colors that are complimentary to the accent color for special cases + /* Only works with elementary themes */ + if (complimentary_css_provider == null) { + complimentary_css_provider = new Gtk.CssProvider (); + try { + switch (theme_color) { + case "strawberry": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@ORANGE_500")); + break; + case "orange": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BLUEBERRY_500", "@MINT_500")); + break; + case "banana": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@MINT_500", "@ORANGE_500")); + break; + case "lime": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@BUBBLEGUM_500")); + break; + case "mint": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@SILVER_500")); + break; + case "blueberry": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@MINT_500")); + break; + case "grape": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@BUBBLEGUM_500")); + break; + case "bubblegum": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@MINT_500", "@GRAPE_500")); + break; + case "cocoa": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BANANA_500", "@MINT_500")); + break; + case "silver": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@BLUEBERRY_300", "@STRAWBERRY_300")); + break; + case "slate": + case "black": + complimentary_css_provider.load_from_data (COMPLIMENTARY_ACCENT_COLORS.printf ("@MINT_500", "@BANANA_500")); + break; + + } + } catch (Error e) { + warning (e.message); + } + Gtk.StyleContext.add_provider_for_screen ( + Gdk.Screen.get_default (), + complimentary_css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + } + } + } +} diff --git a/src/Config.vala.in b/src/Config.vala.in index b7a11776..95e47d84 100644 --- a/src/Config.vala.in +++ b/src/Config.vala.in @@ -1,4 +1,6 @@ namespace Constants { + public const string VERSION = @VERSIONSTRING@; + public const string DISPLAYVER = @DISPLAYVER@; public const string PKGDATADIR = @PKGDATADIR@; public const string SF2DATADIR = @SF2DATADIR@; -} \ No newline at end of file +} diff --git a/src/Core/ArrangerCore.vala b/src/Core/ArrangerCore.vala new file mode 100644 index 00000000..7f666167 --- /dev/null +++ b/src/Core/ArrangerCore.vala @@ -0,0 +1,333 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * Copyright © 2019 Alain M. (https://github.com/alainm23/planner) + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* + * This file is part of Ensembles + */ + +namespace Ensembles.Core { + /* + * This is where all the core functionality of Ensembles resides + * Everything responsible for making sounds, recording sounds + * and manipulating sounds are here + */ + public class ArrangerCore : Object { + public Ensembles.Core.Voice[] detected_voices; + public int[] detected_voice_indices; + public Ensembles.Core.Synthesizer synthesizer; + public Ensembles.Core.StylePlayer style_player; + public Ensembles.Core.MetronomeLFOPlayer metronome_player; + public Ensembles.Core.CentralBus bus; + public Ensembles.Core.MidiInputHost midi_input_host; + public Ensembles.Core.SongPlayer song_player; + public Ensembles.Core.Arpeggiator arpeggiator; + public Ensembles.Core.Harmonizer harmonizer; + + // Plugins System + public PlugIns.PlugInManager plugin_manager; + + + // Analysers + VoiceAnalyser voice_analyser; + StyleDiscovery style_discoverer; + + // Path constants + /* + * sf stands for SoundFont (Registered Trademark of Emu Systems) + * sf_loc is location of the actual soundfont file which is also like the sound database + * sf_schema_loc is the location for the csv file that specifies the categorization of the sounds + */ + public string sf_loc = Constants.SF2DATADIR + "/EnsemblesGM.sf2"; + public string sf_schema_loc = Constants.SF2DATADIR + "/EnsemblesGMSchema.csv"; + // lfo stands for Low Frequency Oscillator + public string metronome_lfo_directory = Constants.PKGDATADIR + "/MetronomesAndLFO"; + + // Signals + public signal void song_player_state_changed (string song_name, Core.SongPlayer.PlayerStatus status); + + construct { + make_core_components (); + make_bus_events (); + make_other_core_events (); + } + + void make_core_components () { + Core.AudioDriverSniffer.check_drivers (); + + // Find out which driver was selected in user settings + debug ("STARTUP: Initializing Settings"); + string driver_string = Core.AudioDriverSniffer.get_available_driver (Application.settings.get_string ("driver")); + if (driver_string == "") { + error ("FATAL: No compatible audio drivers found!"); + } + + // Load Central Bus + // Central Bus is a set of variables (memory slots) that track the state of the synthesizer + // It is accessible from various modules + debug ("STARTUP: Loading Central Bus"); + bus = new Core.CentralBus (); + + // Start monitoring MIDI input streamfor devices + debug ("STARTUP: Loading MIDI Input Monitor"); + midi_input_host = new Core.MidiInputHost (); + + // Initialise plugins + debug ("STARTUP: Initializing Plugin System"); + plugin_manager = new PlugIns.PlugInManager (); + + // Load the main audio synthesizer + debug ("STARTUP: Loading Synthesizer"); + synthesizer = new Core.Synthesizer (sf_loc, + driver_string, + Application.settings.get_double ("buffer-length")); + + // Load the style engine + debug ("STARTUP: Loading Style Engine"); + style_player = new Core.StylePlayer (); + + // Load Metronome and LFO engine. Yes, Metronome and LFO are handled together! + debug ("STARTUP: Loading Metronome and LFO Engine"); + metronome_player = new Core.MetronomeLFOPlayer (metronome_lfo_directory); + + // Load arpeggio and auto harmony modules + arpeggiator = new Core.Arpeggiator (); + harmonizer = new Core.Harmonizer (); + + // Create Analysers + voice_analyser = new VoiceAnalyser (); + style_discoverer = new StyleDiscovery (); + } + + // Connect Central Bus events + void make_bus_events () { + bus.clock_tick.connect (() => { + Idle.add (() => { + Application.main_window.beat_counter_panel.sync (); + Application.main_window.style_controller_view.sync (); + Application.main_window.main_display_unit.set_measure_display (Ensembles.Core.CentralBus.get_measure ()); + return false; + }); + if (metronome_player.looping) metronome_player.stop_loop (); + metronome_player.play_measure (Core.CentralBus.get_beats_per_bar (), Core.CentralBus.get_quarter_notes_per_bar ()); + }); + bus.system_halt.connect (() => { + Idle.add (() => { + //style_player.reload_style (); + Application.main_window.beat_counter_panel.halt (); + metronome_player.stop_loop (); + return false; + }); + }); + bus.style_section_change.connect ((section) => { + Application.main_window.style_controller_view.set_style_section (section); + if (Shell.RecorderScreen.sequencer != null && + Shell.RecorderScreen.sequencer.current_state == MidiRecorder.RecorderState.RECORDING) { + var style_part_actual_event = new Core.MidiEvent (); + style_part_actual_event.event_type = Core.MidiEvent.EventType.STYLECONTROLACTUAL; + style_part_actual_event.value1 = section; + + Shell.RecorderScreen.sequencer.record_event (style_part_actual_event); + } + }); + bus.loaded_tempo_change.connect ((tempo) => { + Application.main_window.beat_counter_panel.change_tempo (tempo); + Application.main_window.main_display_unit.set_tempo_display (tempo); + if (metronome_player != null) + metronome_player.set_tempo (tempo); + if (arpeggiator != null) + arpeggiator.change_tempo (tempo); + if (Shell.RecorderScreen.sequencer != null) { + Shell.RecorderScreen.sequencer.initial_settings_tempo = tempo; + } + }); + bus.loaded_time_signature_change.connect ((n, d) => { + if (Application.main_window.beat_counter_panel != null) { + Application.main_window.beat_counter_panel.change_beats_per_bar (n); + Application.main_window.beat_counter_panel.change_qnotes_per_bar (d); + print ("ts: %d\n", d); + } + }); + bus.split_key_change.connect (() => { + Application.main_window.main_keyboard.update_split (); + }); + } + + void make_other_core_events () { + midi_input_host.receive_note_event.connect ((key, on, velocity)=>{ + // debug ("%d %d %d\n", key, on, velocity); + if (Application.settings.get_boolean ("arpeggiator-on")) { + if (Application.settings.get_boolean ("accomp-on")) { + if (key > Core.CentralBus.get_split_key ()) { + arpeggiator.send_notes (key, on, velocity); + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + } else { + arpeggiator.send_notes (key, on, velocity); + } + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + if (Application.settings.get_boolean ("harmonizer-on")) { + if (Application.settings.get_boolean ("accomp-on")) { + if (key > Core.CentralBus.get_split_key ()) { + harmonizer.send_notes (key, on, velocity); + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + } + Application.main_window.main_keyboard.set_note_on (key, (on == 144)); + }); + + arpeggiator.generate_notes.connect ((key, on, velocity) => { + if (Application.settings.get_boolean ("harmonizer-on")) { + if (Application.settings.get_boolean ("accomp-on")) { + if (key > Core.CentralBus.get_split_key ()) { + harmonizer.send_notes (key, on, velocity); + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + } else { + synthesizer.send_notes_realtime (key, on, velocity); + } + }); + arpeggiator.halt_notes.connect (synthesizer.halt_realtime); + harmonizer.generate_notes.connect ((key, on, velocity) => { + if (key > Core.CentralBus.get_split_key ()) { + synthesizer.send_notes_realtime (key, on, velocity); + } + }); + harmonizer.halt_notes.connect (() => { + Application.main_window.main_keyboard.halt_all (); + synthesizer.halt_realtime (true); + }); + + synthesizer.detected_chord.connect ((chord, type) => { + style_player.change_chords (chord, type); + Application.main_window.main_display_unit.set_chord_display (chord, type); + harmonizer.set_chord (chord, type); + }); + + metronome_player.beat_sync.connect (() => { + Application.main_window.beat_counter_panel.sync (); + }); + + voice_analyser.analysis_complete.connect (() => { + detected_voices = voice_analyser.get_all_voices (); + detected_voice_indices = voice_analyser.get_all_category_indices (); + Idle.add (() => { + Application.main_window.main_display_unit.update_voice_list (detected_voices); + return false; + }); + }); + + style_discoverer.analysis_complete.connect (() => { + Idle.add (() =>{ + Application.main_window.main_display_unit.update_style_list (style_discoverer.styles); + return false; + }); + }); + } + + public void garbage_collect () { + debug ("Cleaning up Core"); + debug ("CLEANUP: Unloading MIDI Input Monitor"); + midi_input_host.destroy (); + Thread.usleep (5000); + debug ("CLEANUP: Unloading Metronome and LFO Engine"); + metronome_player.unref (); + debug ("CLEANUP: Unloading Style Engine"); + style_player.unref (); + if (song_player != null) { + debug ("CLEANUP: Unloading Song Player"); + song_player.songplayer_destroy (); + song_player = null; + } + Thread.usleep (5000); + debug ("CLEANUP: Unloading Central Bus"); + bus.unref (); + Thread.usleep (5000); + debug ("CLEANUP: Unloading Synthesizer"); + synthesizer.synthesizer_deinit (); + } + + public void load_data () { + Thread.usleep (500000); + // Load Voices + debug ("LOADING DATA: Voices"); + voice_analyser.analyse (sf_loc, sf_schema_loc); + + // Load Plug-ins + //debug ("LOADING DATA: Plug-ins"); + //plugin_manager.discover (); + //Application.main_window.main_display_unit.update_effect_list (); + + // Load Styles + // Start looking for styles in the app data folder and user styles folder + debug ("LOADING DATA: Styles"); + style_discoverer.load_styles (); + + Idle.add (() => { + Application.main_window.main_display_unit.queue_remove_splash (); + Application.main_window.style_controller_view.ready (); + Application.main_window.ctrl_panel.load_settings (); + return false; + }); + if (Application.main_window != null) { + Application.main_window.main_display_unit.update_splash_text (_("Initialize…")); + } + debug ("System Ready\n"); + Timeout.add (3000, () => { + if (song_player != null) { + song_player.play (); + } + return false; + }); + } + + public void open_file (File file) { + string path = file.get_path (); + queue_song (path); + } + + public void queue_song (string path) { + string song_name = "Unknown"; + try { + Regex regex = new Regex ("[ \\w-]+?(?=\\.)"); + MatchInfo match_info; + if (regex.match (path, 0, out match_info)) { + song_name = match_info.fetch (0); + } + } catch (RegexError e) { + warning (e.message); + } + + if (song_player != null) { + song_player.player_status_changed.disconnect (Application.main_window.update_header_bar); + song_player.songplayer_destroy (); + song_player = null; + } + debug ("Creating new Song Player instance with midi file: %s", path); + song_player = new Core.SongPlayer (sf_loc, path, song_name); + song_player.player_status_changed.connect (Application.main_window.update_header_bar); + int song_tempo = song_player.current_file_tempo; + style_player.change_tempo (song_tempo); + Application.main_window.main_display_unit.set_tempo_display (song_tempo); + if (Shell.RecorderScreen.sequencer != null) { + Shell.RecorderScreen.sequencer.initial_settings_tempo = song_tempo; + } + Application.main_window.custom_title_text.set_text (_("Now Playing - %s").printf (song_name)); + Application.main_window.song_control_panel.set_player_active (); + song_player_state_changed (song_name, Core.SongPlayer.PlayerStatus.READY); + } + } +} diff --git a/src/Core/Arpeggiator.vala b/src/Core/Automators/Arpeggiator.vala similarity index 81% rename from src/Core/Arpeggiator.vala rename to src/Core/Automators/Arpeggiator.vala index 70b10bb1..8a78b8de 100644 --- a/src/Core/Arpeggiator.vala +++ b/src/Core/Automators/Arpeggiator.vala @@ -1,26 +1,12 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ namespace Ensembles.Core { public class Arpeggiator : Object { public signal void generate_notes (int key, int on, int velocity); - public signal void halt_notes (); + public signal void halt_notes (bool all); int[] keys; int[] active_keys; bool arpeggio_playing = false; @@ -39,7 +25,7 @@ namespace Ensembles.Core { if (on == 144) { keys[key - 36] = velocity; if (!arpeggio_playing) { - switch (Shell.EnsemblesApp.settings.get_int ("arpeggiator-type")) { + switch (Ensembles.Application.settings.get_int ("arpeggiator-type")) { case 1: arpeggio (2, true); break; @@ -80,7 +66,7 @@ namespace Ensembles.Core { } } else { keys[key - 36] = -1; - halt_notes (); + halt_notes (true); arpeggio_playing = false; } } @@ -90,7 +76,7 @@ namespace Ensembles.Core { active_keys = find_keys (); int n = active_keys.length; int i = direction ? 0 : int.MAX; - halt_notes (); + halt_notes (true); generate_notes (active_keys[i % n] + 36, 144, keys[active_keys[i % n]]); if (direction) i++; @@ -102,7 +88,7 @@ namespace Ensembles.Core { if (!arpeggio_playing) { return false; } - halt_notes (); + halt_notes (true); generate_notes (active_keys[i % n] + 36, 144, keys[active_keys[i % n]]); if (direction) i++; @@ -116,7 +102,7 @@ namespace Ensembles.Core { active_keys = find_keys (); int n = active_keys.length; int i = 0; - halt_notes (); + halt_notes (true); generate_notes (active_keys[0] + 36, 144, keys[active_keys[0]]); bool direction = true; if (direction) @@ -129,7 +115,7 @@ namespace Ensembles.Core { if (!arpeggio_playing) { return false; } - halt_notes (); + halt_notes (true); generate_notes (active_keys[i % n] + 36, 144, keys[active_keys[i % n]]); if (direction) i++; @@ -148,7 +134,7 @@ namespace Ensembles.Core { active_keys = find_keys (); int n = active_keys.length; int i = 0; - halt_notes (); + halt_notes (true); generate_notes (active_keys[0] + 36, 144, keys[active_keys[0]]); Timeout.add ((uint)((60000 / subdivision) / tempo), () => { active_keys = find_keys (); @@ -156,7 +142,7 @@ namespace Ensembles.Core { if (!arpeggio_playing) { return false; } - halt_notes (); + halt_notes (true); i = Random.int_range (0, n); generate_notes (active_keys[i % n] + 36, 144, keys[active_keys[i % n]]); return arpeggio_playing; diff --git a/src/Core/Harmonizer.vala b/src/Core/Automators/Harmonizer.vala similarity index 87% rename from src/Core/Harmonizer.vala rename to src/Core/Automators/Harmonizer.vala index 33d8b80c..c769484d 100644 --- a/src/Core/Harmonizer.vala +++ b/src/Core/Automators/Harmonizer.vala @@ -1,3 +1,8 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + namespace Ensembles.Core { public class Harmonizer : Object { public signal void generate_notes (int key, int on, int velocity); @@ -13,13 +18,14 @@ namespace Ensembles.Core { } public void set_chord (int chord, int type) { chord_type = type; - int h_type = Shell.EnsemblesApp.settings.get_int ("harmonizer-type"); + int h_type = Ensembles.Application.settings.get_int ("harmonizer-type"); - if (Shell.EnsemblesApp.settings.get_boolean ("harmonizer-on")) { + if (Ensembles.Application.settings.get_boolean ("harmonizer-on")) { if (chord_main != chord) { if (h_type > 4) { halt_notes (); } + stop_notes (); chord_main = chord; if (h_type > 4) { for (int i = 0; i < 60; i++) { @@ -40,8 +46,17 @@ namespace Ensembles.Core { } harmonize (key, on, velocity); } + + private void stop_notes () { + for (int i = 0; i < 60; i++) { + if (keys[i] >= 0) { + generate_notes (i + 36, 128, 0); + keys[i] = -1; + } + } + } private void harmonize (int key, int on, int velocity) { - switch (Shell.EnsemblesApp.settings.get_int ("harmonizer-type")) { + switch (Ensembles.Application.settings.get_int ("harmonizer-type")) { case 1: harmonize_duet_a (key, on, velocity); break; diff --git a/src/Core/CentralBus.vala b/src/Core/ChoppingBlock/CentralBus.vala similarity index 77% rename from src/Core/CentralBus.vala rename to src/Core/ChoppingBlock/CentralBus.vala index 76ff8310..a123c710 100644 --- a/src/Core/CentralBus.vala +++ b/src/Core/ChoppingBlock/CentralBus.vala @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -28,10 +14,6 @@ namespace Ensembles.Core { int loaded_time_sig_n = 4; int loaded_time_sig_d = 4; - - // System Ready Messages - int styles_loaded_ready = 0; - // Voice Split Updates int split_key = 54; @@ -51,8 +33,6 @@ namespace Ensembles.Core { public void clk () { debug ("clk\n"); } - - public signal void system_ready (); int bus_watch () { while (thread_alive) { if (loaded_tempo != central_loaded_tempo && central_loaded_tempo > 10) { @@ -64,15 +44,6 @@ namespace Ensembles.Core { loaded_time_sig_n = central_beats_per_bar; loaded_time_sig_d = central_quarter_notes_per_bar; } - if (styles_loaded_ready != styles_ready) { - styles_loaded_ready = styles_ready; - if (styles_loaded_ready > 0) { - Idle.add (() => { - system_ready (); - return false; - }); - } - } if (central_halt == 1) { central_halt = 0; Idle.add (() => { @@ -104,10 +75,6 @@ namespace Ensembles.Core { return 0; } - public static void set_styles_ready (bool ready) { - styles_ready = ready ? 1 : 0; - } - public static int get_measure () { return central_measure; } @@ -174,9 +141,6 @@ namespace Ensembles.Core { } } -// System Ready Messages -extern int styles_ready; - // Style Engine extern int central_clock; extern int central_halt; diff --git a/src/Core/central_bus.c b/src/Core/ChoppingBlock/central_bus.c similarity index 80% rename from src/Core/central_bus.c rename to src/Core/ChoppingBlock/central_bus.c index 762c8cd6..d715d9a4 100644 --- a/src/Core/central_bus.c +++ b/src/Core/ChoppingBlock/central_bus.c @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ #include "central_bus.h" @@ -36,15 +22,6 @@ void set_central_halt (int value) { central_halt = value; } -// Ready signals -int styles_ready; -int get_styles_ready () { - return styles_ready; -} -void set_styles_ready (int value) { - styles_ready = value; -} - // Metronome & LFO signals int central_metronome_on; int get_central_metronome_on () { diff --git a/src/Core/central_bus.h b/src/Core/ChoppingBlock/central_bus.h similarity index 79% rename from src/Core/central_bus.h rename to src/Core/ChoppingBlock/central_bus.h index cb6808ed..8e253d83 100644 --- a/src/Core/central_bus.h +++ b/src/Core/ChoppingBlock/central_bus.h @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef CENTRAL_BUS_H @@ -26,7 +12,7 @@ */ int get_central_clock (); /** This function allows you to set the value manually, but it's not - * recommended to use this function in your code unless it's for resetting + * recommended to use this function in your code unless it's for resetting * purposes (set to 0) only */ void set_central_clock (int value); @@ -39,24 +25,12 @@ void set_central_clock (int value); * Its also used by the UI to stop UI events where necessary */ /** This function gives you the current value of halt signal - */ + */ int get_central_halt (); /** This is used to rais a halt signal */ void set_central_halt (int value); -/** Ready signals are used to notify the rest of the application that a - * particular module is ready. Useful for controlling certain UI elements - * show based on whether the underlying system is ready. - */ -/** Returns 1 if styles modules are ready - * and 0 if still processing - */ -int get_styles_ready (); -/** set_style_ready (int value) is used to raise styles ready signal - */ -void set_styles_ready (int value); - int get_central_metronome_on (); int get_central_lfo_on (); diff --git a/src/Core/Controller.vala b/src/Core/MidiInput/MidiInputHost.vala similarity index 62% rename from src/Core/Controller.vala rename to src/Core/MidiInput/MidiInputHost.vala index eb36549d..a3a96f73 100644 --- a/src/Core/Controller.vala +++ b/src/Core/MidiInput/MidiInputHost.vala @@ -1,36 +1,18 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ namespace Ensembles.Core { - public struct ControllerDevice { + public struct MidiDevice { string name; int id; bool available; } - public class Controller : Object { - ControllerDevice[] controller_device; + public class MidiInputHost : Object { + MidiDevice[] midi_device; - public Controller () { - controller_init (); - } - - ~Controller () { + public void destroy () { stream_connected = false; controller_destruct (); } @@ -39,18 +21,22 @@ namespace Ensembles.Core { public signal void receive_note_event (int key, int on, int velocity, int channel); - public Ensembles.Core.ControllerDevice[] get_device_list () { + public Ensembles.Core.MidiDevice[] refresh () { + stream_connected = false; + Thread.usleep (200); + controller_destruct (); + controller_init (); int n = controller_query_input_device_count (); - //debug ("Found %d devices...\n", n); - controller_device = new ControllerDevice[n]; + debug ("Found %d devices…\n", n); + midi_device = new MidiDevice[n]; for (int i = 0; i < n; i++) { controller_query_device_info (i); - controller_device[i].name = controller_input_device_name; - controller_device[i].available = controller_input_device_available > 0 ? true : false; - controller_device[i].id = i; - //debug("Found %s device: %s\n", controller_device[i].available ? "input" : "output", controller_device[i].name); + midi_device[i].name = controller_input_device_name; + midi_device[i].available = controller_input_device_available > 0 ? true : false; + midi_device[i].id = i; + debug ("Found %s device: %s\n", midi_device[i].available ? "input" : "output", midi_device[i].name); } - return controller_device; + return midi_device; } int read_device_stream () { @@ -62,7 +48,7 @@ namespace Ensembles.Core { int channel = (message & 0x00000F); double velocity = ((127.0 - 0.0) / (8323072.0 - 65536.0)) * (double)((0xFF0000 & message) - 65536); - print ("Velocity: %d, Key: %d, Type:%d, Channel:%d, Raw: %x\n", + debug ("Velocity: %d, Key: %d, Type:%d, Channel:%d, Raw: %x\n", (int)velocity, key, type, diff --git a/src/Core/controller.c b/src/Core/MidiInput/midi_input_host.c similarity index 59% rename from src/Core/controller.c rename to src/Core/MidiInput/midi_input_host.c index 41a70272..33df8dfa 100644 --- a/src/Core/controller.c +++ b/src/Core/MidiInput/midi_input_host.c @@ -1,32 +1,12 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ - -#include -#include -#include -#include - - +#include "midi_input_host.h" PortMidiStream* controller_input_stream; -gchar* controller_input_device_name; +char* controller_input_device_name; int controller_input_device_available; int controller_input_device_count; int controller_input_device_names_length1 = 2; @@ -53,7 +33,6 @@ controller_query_device_info (int id) { int controller_query_input_device_count () { - //printf("%d\n", Pm_CountDevices ()); return Pm_CountDevices (); } @@ -61,7 +40,6 @@ controller_query_input_device_count () { int controller_connect_device (int id) { if (Pm_OpenInput (&controller_input_stream, id, NULL, 256, NULL, NULL) == 0) { - printf("Connected\n"); return 1; } return 0; diff --git a/src/Core/MidiInput/midi_input_host.h b/src/Core/MidiInput/midi_input_host.h new file mode 100644 index 00000000..1e2052c4 --- /dev/null +++ b/src/Core/MidiInput/midi_input_host.h @@ -0,0 +1,14 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef MIDI_INPUT_HOST_H +#define MIDI_INPUT_HOST_H + +#include +#include +#include +#include + +#endif /* MIDI_INPUT_HOST_H */ diff --git a/src/Core/MetronomeLFOPlayer.vala b/src/Core/MidiPlayers/MetronomeAndLFO/MetronomeLFOPlayer.vala similarity index 76% rename from src/Core/MetronomeLFOPlayer.vala rename to src/Core/MidiPlayers/MetronomeAndLFO/MetronomeLFOPlayer.vala index 3081d7cb..0c18bed1 100644 --- a/src/Core/MetronomeLFOPlayer.vala +++ b/src/Core/MidiPlayers/MetronomeAndLFO/MetronomeLFOPlayer.vala @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ namespace Ensembles.Core { @@ -30,7 +16,7 @@ namespace Ensembles.Core { _lfo_directory_location = lfo_directory_location; metronome_lfo_player_init (); } - ~MetronomeLFOPlayer () { + public override void dispose () { metronome_lfo_player_destruct (); } diff --git a/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.c b/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.c new file mode 100644 index 00000000..29595e87 --- /dev/null +++ b/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.c @@ -0,0 +1,125 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "metronome_lfo_player.h" + +// None of this will be used for actual rendering ///////// +fluid_synth_t* lfo_synth; +fluid_player_t* lfo_player; +/////////////////////////////////////////////////////////// + +int lfo_measure_length = 0; +int lfo_looping = 0; +int lfo_end_of_line = 0; + +char* metronome_file_path; + +int +lfo_parse_midi_events(void *data, fluid_midi_event_t *event) +{ + int type = fluid_midi_event_get_type(event); + int channel = fluid_midi_event_get_channel(event); + int key = fluid_midi_event_get_key(event); + + int lfo_type = get_central_lfo_on(); + if (lfo_type > 0 && lfo_type < 16 && channel < 16) + { + if (lfo_type < 10) + { + if (lfo_type == (channel + 1) && fluid_midi_event_get_control(event) == 16) + { + set_central_lfo_value (fluid_midi_event_get_value(event)); + } + } + else if (lfo_type > 9) + { + if (lfo_type == channel && fluid_midi_event_get_control(event) == 16) + { + set_central_lfo_value (fluid_midi_event_get_value(event)); + } + } + } + if (channel == 9) + { + // Send data to synth + if (get_central_metronome_on()) + { + synthesizer_send_notes_to_metronome(key, type); + } + } + return 0; +} + + +int +lfo_parse_ticks(void* data, int ticks) +{ + if (ticks >= lfo_end_of_line) + { + fluid_player_stop (lfo_player); + } + return 0; +} + + +void +metronome_lfo_player_init() +{ +} + + +void +metronome_lfo_player_change_base(const char* mid_file, int tempo, int eol) +{ + lfo_end_of_line = eol; + if (lfo_player) + { + fluid_player_stop (lfo_player); + delete_fluid_player(lfo_player); + } + lfo_player = new_fluid_player(get_synthesizer(UTILITY)); + fluid_player_set_playback_callback(lfo_player, lfo_parse_midi_events, get_synthesizer(UTILITY)); + fluid_player_set_tick_callback (lfo_player, lfo_parse_ticks, get_synthesizer(UTILITY)); + if (fluid_is_midifile(mid_file)) + { + fluid_player_add(lfo_player, mid_file); + } + fluid_player_set_tempo (lfo_player, FLUID_PLAYER_TEMPO_EXTERNAL_BPM, (double)tempo); + fluid_player_play(lfo_player); +} + +void +metronome_lfo_player_destruct() +{ + /* wait for playback termination */ + fluid_synth_all_sounds_off(get_synthesizer(UTILITY), -1); + if (lfo_player) + { + fluid_player_stop(lfo_player); + fluid_player_join(lfo_player); + delete_fluid_player(lfo_player); + lfo_player = NULL; + } +} + +void +metronome_lfo_player_play() +{ + if (lfo_player) + { + fluid_player_stop (lfo_player); + fluid_player_seek (lfo_player, 0); + fluid_player_play (lfo_player); + } +} + +void +metronome_lfo_player_set_tempo(int tempo) +{ + if (lfo_player) + { + fluid_player_set_tempo (lfo_player, FLUID_PLAYER_TEMPO_EXTERNAL_BPM, (double)tempo); + } +} diff --git a/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.h b/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.h new file mode 100644 index 00000000..eca4b2f9 --- /dev/null +++ b/src/Core/MidiPlayers/MetronomeAndLFO/metronome_lfo_player.h @@ -0,0 +1,21 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#ifndef METRONOME_LFO_PLAYER_H +#define METRONOME_LFO_PLAYER_H + +#include +#include +#include +#include + +#include "../StyleEngine/style_analyser.h" +#include "../../ChoppingBlock/central_bus.h" +#include "../../Synthesizer/synthesizer.h" + +#include "../../Synthesizer/providers/synthesizer_instance.h" + +#endif /* METRONOME_LFO_PLAYER_H */ diff --git a/src/Core/SongPlayer.vala b/src/Core/MidiPlayers/SongPlayer/SongPlayer.vala similarity index 79% rename from src/Core/SongPlayer.vala rename to src/Core/MidiPlayers/SongPlayer/SongPlayer.vala index 4362ad9e..ec0bb7e5 100644 --- a/src/Core/SongPlayer.vala +++ b/src/Core/MidiPlayers/SongPlayer/SongPlayer.vala @@ -1,3 +1,8 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + namespace Ensembles.Core { public class SongPlayer : Object { public enum PlayerStatus { @@ -6,16 +11,21 @@ namespace Ensembles.Core { STOPPING, DONE } + public string name; public int current_file_tempo = 30; public signal void player_status_changed (float fraction, int tempo_bpm, PlayerStatus status); bool monitoring_player = false; string sf_loc; - public SongPlayer (string sf_loc, string midi_file_path) { + public SongPlayer (string sf_loc, string midi_file_path, string name) { + this.name = name; this.sf_loc = sf_loc; music_player_init (sf_loc); current_file_tempo = music_player_load_file (midi_file_path); player_status_changed (0.0f, current_file_tempo, get_status ()); + set_music_note_callback ((note, on) => { + Application.main_window.main_keyboard.set_note_on (note, (on == 144), true); + }); start_monitoring (); } @@ -26,6 +36,7 @@ namespace Ensembles.Core { } public void songplayer_destroy () { monitoring_player = false; + music_player_pause (); music_player_destruct (); } @@ -86,6 +97,10 @@ namespace Ensembles.Core { } return 0; } + + public static void set_note_watch_channel (int chan) { + note_watch_channel = chan; + } } } @@ -97,6 +112,12 @@ extern void music_player_pause (); extern void music_player_seek (int seek_point); extern int music_player_get_status (); + +[CCode (cname = "style_player_change_state", has_target = false)] +extern delegate void music_note_callback (int note, int on); +[CCode (has_target = false)] +extern void set_music_note_callback (music_note_callback function); + extern int note_watch_channel; extern int total_ticks; extern int current_ticks; diff --git a/src/Core/MidiPlayers/SongPlayer/song_player.c b/src/Core/MidiPlayers/SongPlayer/song_player.c new file mode 100644 index 00000000..2fa694bb --- /dev/null +++ b/src/Core/MidiPlayers/SongPlayer/song_player.c @@ -0,0 +1,148 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "song_player.h" +#include "../../Synthesizer/synthesizer.h" + +fluid_player_t* mp_player; + +int note_watch_channel = 0; +int total_ticks = 0; +int current_ticks = 0; + + +gchar* midi_file_path; + +int player_repeat; + +// Note callback +typedef void +(*music_note_callback)(gint note, gint on); + +static music_note_callback music_callback; + +void +set_music_note_callback(music_note_callback callback) +{ + music_callback = callback; +} + +int +mp_parse_midi_events(void *data, fluid_midi_event_t *event) +{ + int type = fluid_midi_event_get_type(event); + int channel = fluid_midi_event_get_channel(event); + int key = fluid_midi_event_get_key(event); + + if (music_callback != NULL && channel == note_watch_channel) + { + if (type == 144 || type == 128) + { + music_callback(key, type); + } + } + fluid_midi_event_t* new_event = new_fluid_midi_event(); + + fluid_midi_event_set_channel(new_event, channel); + fluid_midi_event_set_control(new_event, fluid_midi_event_get_control (event)); + fluid_midi_event_set_pitch(new_event, fluid_midi_event_get_pitch (event)); + fluid_midi_event_set_program(new_event, fluid_midi_event_get_program (event)); + fluid_midi_event_set_value(new_event, fluid_midi_event_get_value (event)); + fluid_midi_event_set_key(new_event, key); + fluid_midi_event_set_velocity(new_event,fluid_midi_event_get_velocity (event)); + fluid_midi_event_set_type(new_event, type); + return handle_events_for_midi_players(new_event, 0); +} + +int +mp_parse_ticks (void* data, int ticks) +{ + current_ticks = ticks; + if (total_ticks < 10) + { + total_ticks = fluid_player_get_total_ticks(mp_player); + } + if (total_ticks > 10 && current_ticks + 10 > total_ticks) + { + if (player_repeat > 0) + { + current_ticks = 0; + return fluid_player_seek(mp_player, 1); + } + else + { + fluid_player_stop(mp_player); + current_ticks = 0; + return fluid_player_seek(mp_player, 1); + } + } + return FLUID_OK; +} + +void +music_player_init() +{ + mp_player = new_fluid_player(get_synthesizer(UTILITY)); + fluid_player_set_playback_callback(mp_player, mp_parse_midi_events, get_synthesizer(UTILITY)); + fluid_player_set_tick_callback(mp_player, mp_parse_ticks, get_synthesizer(UTILITY)); +} + +int +music_player_load_file(gchar* path) +{ + midi_file_path = (char *)malloc(sizeof (char) * strlen(path)); + strcpy (midi_file_path, path); + if (fluid_is_midifile(midi_file_path)) + { + fluid_player_add(mp_player, midi_file_path); + total_ticks = fluid_player_get_total_ticks(mp_player); + return fluid_player_get_bpm(mp_player); + } + return -1; +} + +void +music_player_play() +{ + synthesizer_halt_notes(); + fluid_player_play(mp_player); +} + +void +music_player_pause () +{ + fluid_player_stop(mp_player); + synthesizer_halt_notes(); + fluid_synth_all_notes_off(get_synthesizer(UTILITY), -1); + fluid_synth_all_sounds_off(get_synthesizer(UTILITY), -1); +} + +void +music_player_seek(int seek_point) +{ + fluid_player_seek(mp_player, seek_point); +} + +int +music_player_get_status() +{ + if (mp_player) + { + return fluid_player_get_status(mp_player); + } + return 0; +} + +void +music_player_destruct() +{ + if (mp_player) + { + fluid_player_stop(mp_player); + fluid_player_join(mp_player); + delete_fluid_player(mp_player); + mp_player = NULL; + } +} diff --git a/src/Core/MidiPlayers/SongPlayer/song_player.h b/src/Core/MidiPlayers/SongPlayer/song_player.h new file mode 100644 index 00000000..44f9043e --- /dev/null +++ b/src/Core/MidiPlayers/SongPlayer/song_player.h @@ -0,0 +1,17 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#ifndef SONG_PLAYER_H +#define SONG_PLAYER_H + +#include +#include +#include +#include + +#include "../../Synthesizer/providers/synthesizer_instance.h" + +#endif /* SONG_PLAYER_H */ diff --git a/src/Core/MidiPlayers/StyleEngine/Style.vala b/src/Core/MidiPlayers/StyleEngine/Style.vala new file mode 100644 index 00000000..38c05a9d --- /dev/null +++ b/src/Core/MidiPlayers/StyleEngine/Style.vala @@ -0,0 +1,28 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + namespace Ensembles.Core { + public class Style : Object { + public string path; + public string name; + public string genre; + public int tempo; + public int timesignature_n; + public int timesignature_d; + public Style (string path, + string name, + string genre, + int tempo, + int timesignature_n, + int timesignature_d) { + this.path = path; + this.name = name; + this.genre = genre; + this.tempo = tempo; + this.timesignature_n = timesignature_n; + this.timesignature_d = timesignature_d; + } + } +} diff --git a/src/Core/MidiPlayers/StyleEngine/StyleAnalyser.vala b/src/Core/MidiPlayers/StyleEngine/StyleAnalyser.vala new file mode 100644 index 00000000..d00a5503 --- /dev/null +++ b/src/Core/MidiPlayers/StyleEngine/StyleAnalyser.vala @@ -0,0 +1,27 @@ +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +namespace Ensembles.Core { + public class StyleAnalyser { + public int time_sig_n { + get { + return time_signature_n; + } + } + public int time_sig_d { + get { + return time_signature_d; + } + } + public int analyze_style (string mid_file) { + return style_analyser_analyze (mid_file); + } + } +} + +extern int style_analyser_analyze (string mid_file); + +extern int time_signature_n; +extern int time_signature_d; diff --git a/src/Core/StyleDiscovery.vala b/src/Core/MidiPlayers/StyleEngine/StyleDiscovery.vala similarity index 83% rename from src/Core/StyleDiscovery.vala rename to src/Core/MidiPlayers/StyleEngine/StyleDiscovery.vala index df3d7076..5ebbee43 100644 --- a/src/Core/StyleDiscovery.vala +++ b/src/Core/MidiPlayers/StyleEngine/StyleDiscovery.vala @@ -1,20 +1,6 @@ -/*- - * Copyright (c) 2021-2022 Subhadeep Jasu - * - * 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 3 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 . - * - * Authored by: Subhadeep Jasu +/* + * Copyright 2020-2022 Subhadeep Jasu + * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -30,6 +16,7 @@ namespace Ensembles.Core { Ensembles.Core.StyleAnalyser analyser; public signal void analysis_complete (); + public StyleDiscovery () { in_built_style_path = Constants.PKGDATADIR + "/StyleFiles"; user_style_path = Environment.get_home_dir () + "/Documents/Ensembles/StyleFiles"; @@ -38,7 +25,9 @@ namespace Ensembles.Core { style_genre = new List (); style_tempo = new List (); styles = new List