135 lines
4.7 KiB
C++
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
|
|
};
|