#pragma once /* ============================================================================== Copyright 2022 Nicolas Chambert This program is free software : you can redistribute itand /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 < http://www.gnu.org/licenses/>. ============================================================================== */ /* ============================================================================== Moteur de l'application. Gère la lecture des samples Callé sur le bon tempo. ============================================================================== */ #include #include "Config.h" class Config; // Défini les 3 niveaux de clic utilisés par le métronome // high marque le premier temps de la mesure. correspond au sample High*.wav // low marque les autres temps de la mesure. correspond au sample Low*.wav // lowlow est utilisé pour les clics intermédiares (croches,...). correspond au sample Low*.wav avec une vélocité réduite // mute permet de marquer un silence sur le temps lorsqu'on bat la mesure à la blanche enum class NoteType { high = 0, low = 1, lowLow = 2, mute = 3 }; // Les figures rythmiques disponibles : blanche, noire, croche, triolet, double croche // la figure swing (ou shuffle) est construite sur un triolet avec un click sur le temps et un sur le 2/3 de temps. // suivant l'interprétation, le swing devrait su situer entre le triolet et la double croche mais c'est moi qui décide. enum class FigureType { blanche = 0, noire = 1, croche = 2, triolet = 3, doubleCroche = 4, swing = 5 }; // structure de base pour définir la structure rythmique de la mesure struct MeasureTick { // position du click dans la mesure en valeur absolu // pour une mesure de 5 temps measPos est dans l'intervale [0, 5[ float measPos; // type de click NoteType type; }; // Bat la mesure class Metronome { public: Metronome(Config& configuration); ~Metronome(); juce::Atomic signal; // méthodes de gestion du lecteur void prepareToPlay (double sampleRate); void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill); // reinitialise le lecteur sur le stop void reset(); // recharge les son high et low void loadSounds(std::string high, std::string low); // accesseurs int getBPM() const noexcept { return bpm.get(); } void setBPM(int value); int getMeasures() const noexcept { return measures.get(); } void setMeasures(int value) { int coerce = juce::jlimit(1, 9, value); // On limite le nombre de mesure à 9 measures.set(coerce); initMeasure(); // reconstruit la structure de la mesure signal.set(true); // signale à la GUI de se metre à jours } int getCurrentMeasure() const; void setGain(float value) { gain.set(value); } float getGain() { return gain.get(); } void setFigure(int value) { figure.set((FigureType)value); initMeasure(); // reconstruit la structure de la mesure } FigureType getFigure() { return figure.get(); } private: // variables réglables depuis l'UI (d'ou le Atomic) juce::Atomic measures{ 4 }; // nombre de temps par mesure juce::Atomic bpm{ 72 }; // tempo juce::Atomic gain{ 1.0f }; // volume sonore juce::Atomic figure{ FigureType::noire }; // type de figure utilisé pour construire la mesure // variables internes double sampleRate { 0 }; // nombre de sample par secondes int updateInterval{ 0 }; // nombre de sample entre 2 temps : 60/bpm*sr int lastPos{ 0 }; // indice du dernier sample traité lors de l'appel getNextAudioBlock. Valeur réinitialisé à chaque mesure modulo la taille de la mesure std::vector measStruct; // structure de la mesure, contient tout les clicks en fonction du nombre de mesure et de la figure courante juce::AudioFormatManager formatManager; // chargement des fichier wav juce::Synthesiser synth; // la gestion direct du remplissage du buffer via getNextAudioBlock est trop compliqué // On passe par un Synthé avec un fichier par note, on déclenche la lecture par un evenement midi déclenché précisément void initMeasure(); // reconstruit la structure de la mesure };