Tchick/Source/Metronome.h
2026-02-04 11:51:22 +01:00

135 lines
4.7 KiB
C++

#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 <JuceHeader.h>
#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<bool> 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<int> measures{ 4 }; // nombre de temps par mesure
juce::Atomic<int> bpm{ 72 }; // tempo
juce::Atomic<float> gain{ 1.0f }; // volume sonore
juce::Atomic<FigureType> 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<MeasureTick> 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
};