commit du code source
This commit is contained in:
parent
b92e43ca11
commit
31c19a595b
3
.gitignore
vendored
3
.gitignore
vendored
@ -32,3 +32,6 @@
|
||||
*.out
|
||||
*.app
|
||||
|
||||
JuceLibraryCode/**
|
||||
|
||||
/.vs
|
||||
|
||||
BIN
Assets/Clicks/01 SeikoSQ50/High Seiko SQ50.wav
Normal file
BIN
Assets/Clicks/01 SeikoSQ50/High Seiko SQ50.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/01 SeikoSQ50/Low Seiko SQ50.wav
Normal file
BIN
Assets/Clicks/01 SeikoSQ50/Low Seiko SQ50.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/02 Stick/High Stick.wav
Normal file
BIN
Assets/Clicks/02 Stick/High Stick.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/02 Stick/Low Stick.wav
Normal file
BIN
Assets/Clicks/02 Stick/Low Stick.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/03 Cowbell/High Cowbell.wav
Normal file
BIN
Assets/Clicks/03 Cowbell/High Cowbell.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/03 Cowbell/Low Cowbell.wav
Normal file
BIN
Assets/Clicks/03 Cowbell/Low Cowbell.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/04 vChip Wood/High Wood.wav
Normal file
BIN
Assets/Clicks/04 vChip Wood/High Wood.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/04 vChip Wood/Low Wood.wav
Normal file
BIN
Assets/Clicks/04 vChip Wood/Low Wood.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/05 vChip Claves/HIgh Claves.wav
Normal file
BIN
Assets/Clicks/05 vChip Claves/HIgh Claves.wav
Normal file
Binary file not shown.
BIN
Assets/Clicks/05 vChip Claves/Low Claves.wav
Normal file
BIN
Assets/Clicks/05 vChip Claves/Low Claves.wav
Normal file
Binary file not shown.
229
Makefile
Normal file
229
Makefile
Normal file
@ -0,0 +1,229 @@
|
||||
# Automatically generated makefile, created by the Projucer
|
||||
# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!
|
||||
|
||||
# build with "V=1" for verbose builds
|
||||
ifeq ($(V), 1)
|
||||
V_AT =
|
||||
else
|
||||
V_AT = @
|
||||
endif
|
||||
|
||||
# (this disables dependency generation if multiple architectures are set)
|
||||
DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)
|
||||
|
||||
ifndef PKG_CONFIG
|
||||
PKG_CONFIG=pkg-config
|
||||
endif
|
||||
|
||||
ifndef STRIP
|
||||
STRIP=strip
|
||||
endif
|
||||
|
||||
ifndef AR
|
||||
AR=ar
|
||||
endif
|
||||
|
||||
ifndef CONFIG
|
||||
CONFIG=Debug
|
||||
endif
|
||||
|
||||
JUCE_ARCH_LABEL := $(shell uname -m)
|
||||
|
||||
ifeq ($(CONFIG),Debug)
|
||||
JUCE_BINDIR := build
|
||||
JUCE_LIBDIR := build
|
||||
JUCE_OBJDIR := build/intermediate/Debug
|
||||
JUCE_OUTDIR := build
|
||||
|
||||
ifeq ($(TARGET_ARCH),)
|
||||
TARGET_ARCH :=
|
||||
endif
|
||||
|
||||
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=1" "-DJUCE_USE_DARK_SPLASH_SCREEN=0" "-DJUCE_PROJUCER_VERSION=0x70003" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_JACK=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_B28D=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -IJuceLibraryCode -IJuceLibraryCode/modules $(CPPFLAGS)
|
||||
JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
|
||||
JUCE_TARGET_APP := Tchick
|
||||
|
||||
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS)
|
||||
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++20 $(CXXFLAGS)
|
||||
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS)
|
||||
|
||||
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG),Release)
|
||||
JUCE_BINDIR := build
|
||||
JUCE_LIBDIR := build
|
||||
JUCE_OBJDIR := build/intermediate/Release
|
||||
JUCE_OUTDIR := build
|
||||
|
||||
ifeq ($(TARGET_ARCH),)
|
||||
TARGET_ARCH :=
|
||||
endif
|
||||
|
||||
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=1" "-DJUCE_USE_DARK_SPLASH_SCREEN=0" "-DJUCE_PROJUCER_VERSION=0x70003" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_JACK=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_B28D=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -IJuceLibraryCode -IJuceLibraryCode/modules $(CPPFLAGS)
|
||||
JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
|
||||
JUCE_TARGET_APP := Tchick
|
||||
|
||||
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS)
|
||||
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++20 $(CXXFLAGS)
|
||||
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS)
|
||||
|
||||
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)
|
||||
endif
|
||||
|
||||
OBJECTS_APP := \
|
||||
$(JUCE_OBJDIR)/OptionsPanel_74384d2f.o \
|
||||
$(JUCE_OBJDIR)/TempoPanel_68242652.o \
|
||||
$(JUCE_OBJDIR)/PlayPanel_f7a1c6f1.o \
|
||||
$(JUCE_OBJDIR)/MesurePanel_621c6998.o \
|
||||
$(JUCE_OBJDIR)/Config_df6c736b.o \
|
||||
$(JUCE_OBJDIR)/BPMPanel_fcde4d0e.o \
|
||||
$(JUCE_OBJDIR)/Main_b18eef62.o \
|
||||
$(JUCE_OBJDIR)/Metronome_d2176e73.o \
|
||||
$(JUCE_OBJDIR)/MainComponent_fec15f05.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_basics_854129ea.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_devices_c670bf62.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_formats_7957c261.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_46d0f806.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_ara_80e36097.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_badcdc68.o \
|
||||
$(JUCE_OBJDIR)/include_juce_audio_utils_d9446d36.o \
|
||||
$(JUCE_OBJDIR)/include_juce_core_f75b497b.o \
|
||||
$(JUCE_OBJDIR)/include_juce_data_structures_7e723c43.o \
|
||||
$(JUCE_OBJDIR)/include_juce_events_92002035.o \
|
||||
$(JUCE_OBJDIR)/include_juce_graphics_915442e7.o \
|
||||
$(JUCE_OBJDIR)/include_juce_gui_basics_1fa21125.o \
|
||||
$(JUCE_OBJDIR)/include_juce_gui_extra_fc3dee7a.o \
|
||||
|
||||
.PHONY: clean all strip
|
||||
|
||||
all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP)
|
||||
|
||||
$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES)
|
||||
@command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; }
|
||||
@$(PKG_CONFIG) --print-errors alsa freetype2 libcurl
|
||||
@echo Linking "Tchick - App"
|
||||
-$(V_AT)mkdir -p $(JUCE_BINDIR)
|
||||
-$(V_AT)mkdir -p $(JUCE_LIBDIR)
|
||||
-$(V_AT)mkdir -p $(JUCE_OUTDIR)
|
||||
$(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH)
|
||||
|
||||
$(JUCE_OBJDIR)/OptionsPanel_74384d2f.o: Source/OptionsPanel.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling OptionsPanel.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/TempoPanel_68242652.o: Source/TempoPanel.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling TempoPanel.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/PlayPanel_f7a1c6f1.o: Source/PlayPanel.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling PlayPanel.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/MesurePanel_621c6998.o: Source/MesurePanel.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling MesurePanel.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/Config_df6c736b.o: Source/Config.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling Config.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/BPMPanel_fcde4d0e.o: Source/BPMPanel.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling BPMPanel.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/Main_b18eef62.o: Source/Main.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling Main.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/Metronome_d2176e73.o: Source/Metronome.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling Metronome.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/MainComponent_fec15f05.o: Source/MainComponent.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling MainComponent.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_basics_854129ea.o: JuceLibraryCode/include_juce_audio_basics.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_basics.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_devices_c670bf62.o: JuceLibraryCode/include_juce_audio_devices.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_devices.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_formats_7957c261.o: JuceLibraryCode/include_juce_audio_formats.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_formats.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_46d0f806.o: JuceLibraryCode/include_juce_audio_processors.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_processors.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_ara_80e36097.o: JuceLibraryCode/include_juce_audio_processors_ara.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_processors_ara.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_badcdc68.o: JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_processors_lv2_libs.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_audio_utils_d9446d36.o: JuceLibraryCode/include_juce_audio_utils.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_audio_utils.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_core_f75b497b.o: JuceLibraryCode/include_juce_core.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_core.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_data_structures_7e723c43.o: JuceLibraryCode/include_juce_data_structures.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_data_structures.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_events_92002035.o: JuceLibraryCode/include_juce_events.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_events.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_graphics_915442e7.o: JuceLibraryCode/include_juce_graphics.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_graphics.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_gui_basics_1fa21125.o: JuceLibraryCode/include_juce_gui_basics.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_gui_basics.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
$(JUCE_OBJDIR)/include_juce_gui_extra_fc3dee7a.o: JuceLibraryCode/include_juce_gui_extra.cpp
|
||||
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
|
||||
@echo "Compiling include_juce_gui_extra.cpp"
|
||||
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
|
||||
|
||||
clean:
|
||||
@echo Cleaning Tchick
|
||||
$(V_AT)$(CLEANCMD)
|
||||
|
||||
strip:
|
||||
@echo Stripping Tchick
|
||||
-$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET)
|
||||
|
||||
-include $(OBJECTS_APP:%.o=%.d)
|
||||
11
README.md
11
README.md
@ -1,3 +1,12 @@
|
||||
# Tchick
|
||||
|
||||
Simple metronome
|
||||
A basic metronome application built to test capabilities of [JUCE](https://github.com/juce-framework/JUCE)
|
||||
audio application framework.
|
||||
|
||||
## Build
|
||||
Generate your prefered build chain via Projucer by opening Tchick.sln
|
||||
Visual Studio 2022 and linux makefiles are provided as examples.
|
||||
On linux, you have to copy Assets/Clicks folder in the output directory.
|
||||
|
||||
## Run
|
||||
Run the executable. Click play button. Have fun.
|
||||
10
Source/.continue/mcpServers/new-mcp-server.yaml
Normal file
10
Source/.continue/mcpServers/new-mcp-server.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
name: New MCP server
|
||||
version: 0.0.1
|
||||
schema: v1
|
||||
mcpServers:
|
||||
- name: New MCP server
|
||||
command: npx
|
||||
args:
|
||||
- -y
|
||||
- <your-mcp-server>
|
||||
env: {}
|
||||
5
Source/.continue/rules/new-rule.md
Normal file
5
Source/.continue/rules/new-rule.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
description: A description of your rule
|
||||
---
|
||||
|
||||
Your rule content
|
||||
5
Source/.vscode/settings.json
vendored
Normal file
5
Source/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"continue.enableConsole": true,
|
||||
"continue.enableQuickActions": true,
|
||||
"continue.telemetryEnabled": false
|
||||
}
|
||||
156
Source/BPMPanel.cpp
Normal file
156
Source/BPMPanel.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du tempo.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "BPMPanel.h"
|
||||
|
||||
|
||||
BPMPanel::BPMPanel(juce::Colour c) : backgroundColour(c)
|
||||
{
|
||||
// initialisation de l'interface
|
||||
addComponent(decrement);
|
||||
addComponent(bpm);
|
||||
addComponent(increment);
|
||||
|
||||
addComponent(twice);
|
||||
addComponent(half);
|
||||
addComponent(set60);
|
||||
addComponent(set90);
|
||||
addComponent(set120);
|
||||
addComponent(set150);
|
||||
|
||||
decrement.setRepeatSpeed(300, 100); // On veux pouvoir laisser le bouton appuyé
|
||||
increment.setRepeatSpeed(300, 100);
|
||||
|
||||
bpm.setText("72", juce::dontSendNotification);
|
||||
bpm.getFont().setBold(true);
|
||||
bpm.setColour(juce::Label::textColourId, juce::Colours::black);
|
||||
bpm.setJustificationType(juce::Justification::centred);
|
||||
bpm.setFont(50);
|
||||
}
|
||||
|
||||
void BPMPanel::addComponent(juce::Component& c)
|
||||
{
|
||||
addAndMakeVisible(c);
|
||||
c.setColour(juce::TextButton::buttonColourId, backgroundColour);
|
||||
c.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
}
|
||||
|
||||
void BPMPanel::mouseWheelMove(const juce::MouseEvent&,
|
||||
const juce::MouseWheelDetails& wheel)
|
||||
{
|
||||
// capture des mouseWheel pour invoquer increment/decrement
|
||||
float dir = wheel.deltaY * (wheel.isReversed ? -1.0f : 1.0f);
|
||||
if (dir > 0)
|
||||
{
|
||||
increment.onClick();
|
||||
}
|
||||
else
|
||||
{
|
||||
decrement.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
void BPMPanel::paint(juce::Graphics& g)
|
||||
{
|
||||
g.fillAll(backgroundColour);
|
||||
}
|
||||
|
||||
void BPMPanel::resized()
|
||||
{
|
||||
// Layout à la mano avec une première ligne pour les raccourcis
|
||||
auto area = getLocalBounds();
|
||||
int margin = 3;
|
||||
area.removeFromTop(3*margin);
|
||||
|
||||
{
|
||||
// première ligne accès rapide aux speeds
|
||||
int setLinHeigth = 20;
|
||||
auto setSpeed = area.removeFromTop(setLinHeigth);
|
||||
int butWidth = 64;
|
||||
int marginH = (setSpeed.getWidth() - butWidth * 4) / 2;
|
||||
setSpeed.removeFromLeft(marginH);
|
||||
set60.setBounds(setSpeed.removeFromLeft(butWidth)); setSpeed.removeFromLeft(margin);
|
||||
set90.setBounds(setSpeed.removeFromLeft(butWidth)); setSpeed.removeFromLeft(margin);
|
||||
set120.setBounds(setSpeed.removeFromLeft(butWidth)); setSpeed.removeFromLeft(margin);
|
||||
set150.setBounds(setSpeed.removeFromLeft(butWidth)); setSpeed.removeFromLeft(margin);
|
||||
}
|
||||
|
||||
area.removeFromTop(margin);
|
||||
|
||||
// Et une deuxième ligne avec increment/decrement et le tempo courant
|
||||
{
|
||||
// deuxième ligne BPM inc + dec
|
||||
int butHeigth = 20;
|
||||
int butWidth = 64;
|
||||
int labeSize = 5 * butHeigth;
|
||||
int totalWidth = 2 * butWidth + labeSize;
|
||||
int marginH = (area.getWidth() - totalWidth) / 2;
|
||||
int marginV = (area.getHeight() - labeSize) / 2;
|
||||
decrement.setBounds(area.getX() + marginH, area.getY() + marginV + butHeigth, butWidth, 2 * butHeigth);
|
||||
half.setBounds(area.getX() + marginH, area.getY() + marginV + 3 * butHeigth + margin, butWidth, butHeigth);
|
||||
|
||||
bpm.setBounds(area.getX() + marginH + butWidth, area.getY() + marginV, labeSize, labeSize);
|
||||
|
||||
increment.setBounds(area.getX() + marginH + butWidth + labeSize, area.getY() + marginV + butHeigth, butWidth, 2 * butHeigth);
|
||||
twice.setBounds(area.getX() + marginH + butWidth + labeSize, area.getY() + marginV + 3 * butHeigth + margin, butWidth, butHeigth);
|
||||
}
|
||||
}
|
||||
|
||||
void BPMPanel::init(Metronome & metro)
|
||||
{
|
||||
// On établi les liaisons entre le Metronome et les composants graphique
|
||||
bpm.setText(juce::String(metro.getBPM()), juce::dontSendNotification); // On récupère la valeur initiale du tempo
|
||||
increment.onClick = [&, this]() { inc(metro); };
|
||||
decrement.onClick = [&, this]() { dec(metro); };
|
||||
set60.onClick = [&, this]() { setBPM(metro, 60); };
|
||||
set90.onClick = [&, this]() { setBPM(metro, 90); };
|
||||
set120.onClick = [&, this]() { setBPM(metro, 120); };
|
||||
set150.onClick = [&, this]() { setBPM(metro, 150); };
|
||||
half.onClick = [&, this]() { setBPM(metro, metro.getBPM() / 2); };
|
||||
twice.onClick = [&, this]() { setBPM(metro, metro.getBPM() * 2); };
|
||||
}
|
||||
|
||||
void BPMPanel::inc(Metronome& metro)
|
||||
{
|
||||
// Ajoute 1 au tempo
|
||||
metro.setBPM(metro.getBPM() + 1);
|
||||
bpm.setText(juce::String(metro.getBPM()), juce::dontSendNotification);
|
||||
}
|
||||
|
||||
void BPMPanel::dec(Metronome& metro)
|
||||
{
|
||||
// reduit le tempo de 1
|
||||
metro.setBPM(metro.getBPM() - 1);
|
||||
bpm.setText(juce::String(metro.getBPM()), juce::dontSendNotification);
|
||||
}
|
||||
void BPMPanel::setBPM(Metronome& metro, int value)
|
||||
{
|
||||
// défini la nouvelle valeur du tempo
|
||||
metro.setBPM(value);
|
||||
bpm.setText(juce::String(metro.getBPM()), juce::dontSendNotification);
|
||||
}
|
||||
66
Source/BPMPanel.h
Normal file
66
Source/BPMPanel.h
Normal file
@ -0,0 +1,66 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du tempo.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Metronome.h"
|
||||
|
||||
struct BPMPanel : public juce::Component
|
||||
{
|
||||
explicit BPMPanel(juce::Colour c);
|
||||
|
||||
// Méthode de surcharge JUCE
|
||||
void mouseWheelMove(const juce::MouseEvent&,
|
||||
const juce::MouseWheelDetails& wheel) override; // on prend en charge le mouseWheel pour changer le tempo
|
||||
|
||||
void paint(juce::Graphics& g) override;
|
||||
|
||||
void resized() override;
|
||||
|
||||
// utilitaire graphique
|
||||
void addComponent(juce::Component& c);
|
||||
|
||||
// méthodes de gestion du tempo
|
||||
void init(Metronome& metro);
|
||||
void inc(Metronome& metro);
|
||||
void dec(Metronome& metro);
|
||||
void setBPM(Metronome& metro, int value);
|
||||
|
||||
// composants graphiques
|
||||
juce::Colour backgroundColour;
|
||||
juce::TextButton increment{ "+" };
|
||||
juce::TextButton decrement{ "-" };
|
||||
juce::TextButton twice{ "*2" };
|
||||
juce::TextButton half{ "/2" };
|
||||
juce::TextButton set60{ "60" };
|
||||
juce::TextButton set90{ "90" };
|
||||
juce::TextButton set120{ "120" };
|
||||
juce::TextButton set150{ "150" };
|
||||
juce::Label bpm;
|
||||
};
|
||||
|
||||
104
Source/Config.cpp
Normal file
104
Source/Config.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion de la sauvegarde de la configuration courante.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
// petit singleton
|
||||
Config* Config::instance = nullptr;
|
||||
|
||||
|
||||
Config& Config::Load()
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new Config();
|
||||
|
||||
// On cherche le fichier json dans le repertoire courant
|
||||
juce::File curDir{ juce::File::getSpecialLocation(juce::File::SpecialLocationType::currentExecutableFile).getParentDirectory() };
|
||||
juce::File confFile{ curDir.getChildFile("tchick.json") };
|
||||
|
||||
if (confFile.exists())
|
||||
{
|
||||
// s'il existe, on le charge
|
||||
auto content = juce::JSON::parse(confFile);
|
||||
instance->fromVar(content);
|
||||
}
|
||||
|
||||
return *instance;
|
||||
}
|
||||
|
||||
void Config::Save(Metronome& metro, OptionsPanel& options)
|
||||
{
|
||||
// On initialise les paramètres
|
||||
instance->bpm = metro.getBPM();
|
||||
instance->measures = metro.getMeasures();
|
||||
instance->gain = metro.getGain();
|
||||
instance->figure = (int)metro.getFigure();
|
||||
instance->sound = options.getSoundName();
|
||||
|
||||
// on transforme en var
|
||||
juce::var obj = instance->asVar();
|
||||
|
||||
// on met à jours le fichier
|
||||
juce::File curDir{ juce::File::getSpecialLocation(juce::File::SpecialLocationType::currentExecutableFile).getParentDirectory() };
|
||||
juce::File confFile{ curDir.getChildFile("tchick.json") };
|
||||
juce::FileOutputStream stream(confFile);
|
||||
|
||||
if (stream.openedOk())
|
||||
{
|
||||
// méthode préconisé pour ecraser le fichier existant
|
||||
stream.setPosition(0);
|
||||
stream.truncate();
|
||||
juce::JSON::writeToStream(stream, obj);
|
||||
}
|
||||
}
|
||||
|
||||
juce::var Config::asVar()
|
||||
{
|
||||
// création du var à partir de this
|
||||
juce::DynamicObject* obj = new juce::DynamicObject();
|
||||
juce::NamedValueSet& properties = obj->getProperties();
|
||||
properties.set("bpm", bpm);
|
||||
properties.set("measures", measures);
|
||||
properties.set("gain", gain);
|
||||
properties.set("sound", sound);
|
||||
properties.set("figure", figure);
|
||||
return juce::var(obj);
|
||||
}
|
||||
|
||||
void Config::fromVar(juce::var var)
|
||||
{
|
||||
// chargement des paramètres depuis un var
|
||||
juce::DynamicObject* obj = var.getDynamicObject();
|
||||
juce::NamedValueSet& properties = obj->getProperties();
|
||||
|
||||
if(properties.contains("bpm")) bpm = properties["bpm"];
|
||||
if(properties.contains("measures")) measures = properties["measures"];
|
||||
if(properties.contains("gain")) gain = properties["gain"];
|
||||
if(properties.contains("sound")) sound = properties["sound"];
|
||||
if(properties.contains("figure")) figure = properties["figure"];
|
||||
}
|
||||
67
Source/Config.h
Normal file
67
Source/Config.h
Normal file
@ -0,0 +1,67 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion de la sauvegarde de la configuration courante.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Metronome.h"
|
||||
#include "OptionsPanel.h"
|
||||
|
||||
|
||||
class Metronome;
|
||||
struct OptionsPanel;
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
~Config() {};
|
||||
|
||||
// charge la config depuis le fichier json ou les valeurs par defaut
|
||||
static Config& Load();
|
||||
|
||||
// enregistre la config dans le fichier json
|
||||
static void Save(Metronome& metro, OptionsPanel& options);
|
||||
|
||||
// paramètres sauvegardés
|
||||
int bpm{ 72 }; // default 72
|
||||
int measures{ 4 }; // default 4
|
||||
float gain{ 1.0f }; // default 1.0
|
||||
juce::String sound{ "" }; // default empty
|
||||
int figure{ 1 }; // default 1 (noire)
|
||||
|
||||
|
||||
private:
|
||||
// je crois que c'est pas suffisant mais on devrait toujours passer par les méthodes statiques
|
||||
Config() {};
|
||||
|
||||
// convertisseur paramètre <-> var
|
||||
juce::var asVar();
|
||||
|
||||
void fromVar(juce::var var);
|
||||
|
||||
// seule instance de config
|
||||
static Config* instance;
|
||||
};
|
||||
43
Source/Figures.h
Normal file
43
Source/Figures.h
Normal file
File diff suppressed because one or more lines are too long
118
Source/Main.cpp
Normal file
118
Source/Main.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "MainComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class MetronomeApplication : public juce::JUCEApplication
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MetronomeApplication() {}
|
||||
|
||||
const juce::String getApplicationName() override { return ProjectInfo::projectName; }
|
||||
const juce::String getApplicationVersion() override { return ProjectInfo::versionString; }
|
||||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const juce::String&) override
|
||||
{
|
||||
// This method is where you should put your application's initialisation code..
|
||||
|
||||
mainWindow.reset (new MainWindow (getApplicationName()));
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
// Add your application's shutdown code here..
|
||||
|
||||
mainWindow = nullptr; // (deletes our window)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
// This is called when the app is being asked to quit: you can ignore this
|
||||
// request and let the app carry on running, or call quit() to allow the app to close.
|
||||
quit();
|
||||
}
|
||||
|
||||
void anotherInstanceStarted (const juce::String&) override
|
||||
{
|
||||
// When another instance of the app is launched while this one is running,
|
||||
// this method is invoked, and the commandLine parameter tells you what
|
||||
// the other instance's command-line arguments were.
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
This class implements the desktop window that contains an instance of
|
||||
our MainComponent class.
|
||||
*/
|
||||
class MainWindow : public juce::DocumentWindow
|
||||
{
|
||||
public:
|
||||
MainWindow (juce::String name)
|
||||
: DocumentWindow (name,
|
||||
juce::Desktop::getInstance().getDefaultLookAndFeel()
|
||||
.findColour (juce::ResizableWindow::backgroundColourId),
|
||||
DocumentWindow::allButtons)
|
||||
{
|
||||
setUsingNativeTitleBar (true);
|
||||
setContentOwned (new MainComponent(Config::Load()), true); // On charge la configuration json et on la passe au constructeur de MainComponent
|
||||
|
||||
#if JUCE_IOS || JUCE_ANDROID
|
||||
setFullScreen (true);
|
||||
#else
|
||||
setResizable (false, false);
|
||||
centreWithSize (getWidth(), getHeight());
|
||||
#endif
|
||||
|
||||
setVisible (true);
|
||||
}
|
||||
|
||||
void closeButtonPressed() override
|
||||
{
|
||||
// This is called when the user tries to close this window. Here, we'll just
|
||||
// ask the app to quit when this happens, but you can change this to do
|
||||
// whatever you need.
|
||||
((MainComponent*)getContentComponent())->saveConfig();
|
||||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
/* Note: Be careful if you override any DocumentWindow methods - the base
|
||||
class uses a lot of them, so by overriding you might break its functionality.
|
||||
It's best to do all your work in your content component instead, but if
|
||||
you really have to override any DocumentWindow methods, make sure your
|
||||
subclass also calls the superclass's method.
|
||||
*/
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<MainWindow> mainWindow;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// This macro generates the main() routine that launches the app.
|
||||
START_JUCE_APPLICATION (MetronomeApplication)
|
||||
143
Source/MainComponent.cpp
Normal file
143
Source/MainComponent.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "MainComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
MainComponent::MainComponent(Config& conf) :
|
||||
metronome(conf),
|
||||
measures(juce::Colours::whitesmoke),
|
||||
bpm(juce::Colours::whitesmoke),
|
||||
tempo(juce::Colours::whitesmoke),
|
||||
playButton(juce::Colours::whitesmoke),
|
||||
options(juce::Colours::whitesmoke, conf)
|
||||
{
|
||||
addAndMakeVisible (measures);
|
||||
addAndMakeVisible (bpm);
|
||||
bpm.init(metronome);
|
||||
addAndMakeVisible (tempo);
|
||||
tempo.init(metronome);
|
||||
|
||||
addAndMakeVisible(playButton);
|
||||
playButton.init(metronome);
|
||||
addAndMakeVisible (options);
|
||||
options.init(metronome);
|
||||
|
||||
setSize (400, 600);
|
||||
|
||||
// Some platforms require permissions to open input channels so request that here
|
||||
if (juce::RuntimePermissions::isRequired (juce::RuntimePermissions::recordAudio)
|
||||
&& ! juce::RuntimePermissions::isGranted (juce::RuntimePermissions::recordAudio))
|
||||
{
|
||||
juce::RuntimePermissions::request (juce::RuntimePermissions::recordAudio,
|
||||
[&] (bool granted) { if (granted) setAudioChannels (2, 2); });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Specify the number of input and output channels that we want to open
|
||||
setAudioChannels (0, 2);
|
||||
}
|
||||
|
||||
startTimer(20); // timer pour aller relire les eventuels signaux du métronome
|
||||
}
|
||||
|
||||
MainComponent::~MainComponent()
|
||||
{
|
||||
shutdownAudio();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MainComponent::prepareToPlay (int , double sampleRate)
|
||||
{
|
||||
metronome.prepareToPlay(sampleRate); // passe le sampleRate au métronome
|
||||
}
|
||||
|
||||
void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill)
|
||||
{
|
||||
// netoyage de l'entrée
|
||||
bufferToFill.clearActiveBufferRegion();
|
||||
|
||||
if (playButton.playState == PlayState::playing)
|
||||
{
|
||||
// boucle de lecture du métronome
|
||||
metronome.getNextAudioBlock (bufferToFill);
|
||||
}
|
||||
}
|
||||
|
||||
void MainComponent::releaseResources()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MainComponent::paint (juce::Graphics& g)
|
||||
{
|
||||
g.fillAll (juce::Colours::lightgrey);
|
||||
}
|
||||
|
||||
void MainComponent::resized()
|
||||
{
|
||||
// Comme on à séparé tout en composants, on utilise un simple grille en ligne
|
||||
juce::Grid grid;
|
||||
using Track = juce::Grid::TrackInfo;
|
||||
using Fr = juce::Grid::Fr;
|
||||
grid.templateRows = { Track (Fr (5)), Track (Fr (12)), Track (Fr (8)),Track (Fr (20)), Track (Fr (4)) };
|
||||
grid.templateColumns = { Track (Fr (1)) };
|
||||
|
||||
float margin = 1.0f;
|
||||
grid.items = {
|
||||
juce::GridItem (measures).withMargin(juce::GridItem::Margin(0.0f, 0.0f, margin, 0.0f)),
|
||||
juce::GridItem (bpm).withMargin(juce::GridItem::Margin(margin, 0.0f, margin, 0.0f)),
|
||||
juce::GridItem (tempo).withMargin(juce::GridItem::Margin(margin, 0.0f, margin, 0.0f)),
|
||||
juce::GridItem(playButton).withMargin(juce::GridItem::Margin(margin, 0.0f, margin, 0.0f)),
|
||||
juce::GridItem (options).withMargin(juce::GridItem::Margin(margin, 0.0f, 0.0f, 0.0f)),
|
||||
};
|
||||
|
||||
|
||||
grid.performLayout (getLocalBounds());
|
||||
}
|
||||
|
||||
void MainComponent::timerCallback()
|
||||
{
|
||||
// On regarde si le metronome à des choses à nous dire (changement de mesure)
|
||||
if (metronome.signal.get() == true)
|
||||
{
|
||||
int cur = metronome.getCurrentMeasure();
|
||||
metronome.signal.set(false); // on ferme le signal
|
||||
int meas = metronome.getMeasures();
|
||||
cur = cur > 0 ? cur - 1 : cur;
|
||||
measures.update(meas, cur % meas);
|
||||
if (cur != lastcur)
|
||||
{
|
||||
// On à changé de mesure, on indique au playButton de s'allumer pendant 6 frames
|
||||
playButton.highlightFrames = 6;
|
||||
lastcur = cur;
|
||||
}
|
||||
}
|
||||
|
||||
playButton.highlight(); // le bouton va se redessiner et decrementer son highlightFrames
|
||||
}
|
||||
|
||||
void MainComponent::saveConfig()
|
||||
{
|
||||
// sauvegarde la configuration du metronome à la fermeture
|
||||
Config::Save(metronome, options);
|
||||
}
|
||||
79
Source/MainComponent.h
Normal file
79
Source/MainComponent.h
Normal file
@ -0,0 +1,79 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "MesurePanel.h"
|
||||
#include "BPMPanel.h"
|
||||
#include "TempoPanel.h"
|
||||
#include "PlayPanel.h"
|
||||
#include "OptionsPanel.h"
|
||||
#include "Metronome.h"
|
||||
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
This component lives inside our window, and this is where you should put all
|
||||
your controls and content.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
class MainComponent : private juce::Timer, public juce::AudioAppComponent
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MainComponent(Config& conf);
|
||||
~MainComponent();
|
||||
|
||||
//==============================================================================
|
||||
void prepareToPlay (int , double sampleRate) override;
|
||||
void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override;
|
||||
void releaseResources() override;
|
||||
|
||||
//==============================================================================
|
||||
void paint (juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
void saveConfig();
|
||||
|
||||
private:
|
||||
MesurePanel measures;
|
||||
BPMPanel bpm;
|
||||
PlayPanel playButton;
|
||||
TempoPanel tempo;
|
||||
OptionsPanel options;
|
||||
|
||||
Metronome metronome;
|
||||
|
||||
// conserve la dernière mesure pour déclencher le highlight en cas de changement
|
||||
int lastcur;
|
||||
|
||||
// Utilisation d'un timer pour relire les signaux du metronome
|
||||
// timer de 20ms, largement suffisant pour un retour graphique sans surcharger le processeur (~50fps)
|
||||
void timerCallback() override;
|
||||
|
||||
// permet de faire clignoter le bouton play sur le temps
|
||||
void highlight();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
|
||||
};
|
||||
|
||||
133
Source/MesurePanel.cpp
Normal file
133
Source/MesurePanel.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
#include "MesurePanel.h"
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du nombre de temps par mesure.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void RoundCBLookAndFeel::drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
|
||||
{
|
||||
// dessine un cercle au lieux d'un bouton
|
||||
auto fontSize = juce::jmin(15.0f, (float)button.getHeight() * 0.75f);
|
||||
auto tickWidth = fontSize * 1.1f;
|
||||
|
||||
drawTickBox(g, button, 4.0f, ((float)button.getHeight() - tickWidth) * 0.5f,
|
||||
tickWidth, tickWidth,
|
||||
button.getToggleState(),
|
||||
button.isEnabled(),
|
||||
shouldDrawButtonAsHighlighted,
|
||||
shouldDrawButtonAsDown);
|
||||
}
|
||||
|
||||
void RoundCBLookAndFeel::drawTickBox(juce::Graphics& g, juce::Component& component,
|
||||
float x, float y, float w, float h,
|
||||
bool ticked, bool isEnabled,
|
||||
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
|
||||
{
|
||||
// dessine un cercle au lieux d'un bouton
|
||||
juce::ignoreUnused(isEnabled, shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
|
||||
|
||||
g.setColour(component.findColour(juce::ToggleButton::tickDisabledColourId));
|
||||
g.drawEllipse(x, y, w, h, 1.0f);
|
||||
|
||||
if (ticked)
|
||||
{
|
||||
g.setColour(component.findColour(juce::ToggleButton::tickColourId));
|
||||
g.fillEllipse(x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MesurePanel::MesurePanel(juce::Colour c) : backgroundColour(c)
|
||||
{
|
||||
lef.reset(new RoundCBLookAndFeel());
|
||||
update(4, 0);
|
||||
}
|
||||
|
||||
MesurePanel::~MesurePanel()
|
||||
{
|
||||
// evite une fuite mémoire à la fermeture due au L&F
|
||||
for (auto& tb : buttons)
|
||||
{
|
||||
removeChildComponent(tb);
|
||||
tb->setLookAndFeel(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MesurePanel::paint(juce::Graphics& g)
|
||||
{
|
||||
g.fillAll(backgroundColour);
|
||||
}
|
||||
|
||||
void MesurePanel::update(int nb, int cur)
|
||||
{
|
||||
// Construit autant de bouton qu'il y a de temps
|
||||
if (buttons.size() != nb)
|
||||
{
|
||||
// Si la mesure à changé on reinitialise
|
||||
for (auto& tb : buttons)
|
||||
{
|
||||
removeChildComponent(tb);
|
||||
tb->setVisible(false);
|
||||
|
||||
}
|
||||
|
||||
buttons.clear();
|
||||
for (int i = 0; i < nb; ++i)
|
||||
{
|
||||
auto* tb = new juce::ToggleButton(juce::String(i));
|
||||
addAndMakeVisible(buttons.add(tb));
|
||||
tb->setRadioGroupId(1234);
|
||||
tb->setColour(juce::ToggleButton::tickDisabledColourId, juce::Colours::black);
|
||||
tb->setColour(juce::ToggleButton::tickColourId, juce::Colours::black);
|
||||
tb->setLookAndFeel(lef.get());
|
||||
}
|
||||
}
|
||||
|
||||
// On sélectionne le bouton correpondant au temps courant
|
||||
for (int i = 0; i < nb; ++i)
|
||||
{
|
||||
buttons[i]->setToggleState(i == cur, juce::dontSendNotification);
|
||||
}
|
||||
|
||||
resized();
|
||||
}
|
||||
|
||||
void MesurePanel::resized()
|
||||
{
|
||||
// Layout via une flexbox pour répartir les boutons en ligne
|
||||
juce::FlexBox fb;
|
||||
fb.flexWrap = juce::FlexBox::Wrap::wrap;
|
||||
fb.justifyContent = juce::FlexBox::JustifyContent::center;
|
||||
fb.alignContent = juce::FlexBox::AlignContent::center;
|
||||
|
||||
for (auto* b : buttons)
|
||||
fb.items.add(juce::FlexItem(*b).withMinWidth(40.0f).withMinHeight(40.0f));
|
||||
|
||||
fb.performLayout(getLocalBounds().toFloat());
|
||||
}
|
||||
62
Source/MesurePanel.h
Normal file
62
Source/MesurePanel.h
Normal file
@ -0,0 +1,62 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du nombre de temps par mesure.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
|
||||
// Surcharge les boutons pour un rond plein ou vide
|
||||
struct RoundCBLookAndFeel : public juce::LookAndFeel_V4
|
||||
{
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
||||
|
||||
void drawTickBox(juce::Graphics& g, juce::Component& component,
|
||||
float x, float y, float w, float h,
|
||||
bool ticked, bool isEnabled,
|
||||
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
||||
};
|
||||
|
||||
// Panneau d'affichage de la mesure en cours
|
||||
struct MesurePanel : public juce::Component
|
||||
{
|
||||
explicit MesurePanel(juce::Colour c);
|
||||
|
||||
~MesurePanel();
|
||||
|
||||
// Méthode de surcharge JUCE
|
||||
void paint(juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
// méthodes internes
|
||||
void update(int nb, int cur);
|
||||
|
||||
// composants graphiques
|
||||
juce::Colour backgroundColour;
|
||||
juce::OwnedArray<juce::ToggleButton> buttons;
|
||||
std::unique_ptr <RoundCBLookAndFeel> lef;
|
||||
};
|
||||
246
Source/Metronome.cpp
Normal file
246
Source/Metronome.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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 "Metronome.h"
|
||||
|
||||
Metronome::Metronome(Config& conf)
|
||||
{
|
||||
// on récupère les valeurs de la configuration
|
||||
bpm.set(conf.bpm);
|
||||
measures.set(conf.measures);
|
||||
gain.set(conf.gain);
|
||||
setFigure(conf.figure);
|
||||
|
||||
// on initialise le lecteur wav
|
||||
formatManager.registerBasicFormats();
|
||||
|
||||
// On crée 2 voie sur le synthé
|
||||
for (auto i = 0; i < 2; ++i)
|
||||
synth.addVoice(new juce::SamplerVoice());
|
||||
}
|
||||
|
||||
Metronome::~Metronome()
|
||||
{
|
||||
// libère les sons
|
||||
synth.clearSounds();
|
||||
}
|
||||
|
||||
|
||||
void Metronome::loadSounds(std::string high, std::string low)
|
||||
{
|
||||
// chargement des sons high et low
|
||||
auto mySamplesHigh = juce::File{high};
|
||||
auto mySamplesLow = juce::File{ low };
|
||||
|
||||
jassert(mySamplesHigh.exists());
|
||||
jassert(mySamplesLow.exists());
|
||||
synth.clearSounds();
|
||||
|
||||
juce::BigInteger usedNotes;
|
||||
usedNotes.setRange(0, 1, true);
|
||||
auto formatReaderHigh = formatManager.createReaderFor(mySamplesHigh);
|
||||
synth.addSound(new juce::SamplerSound("High", *formatReaderHigh, usedNotes, 0, 0.0f, 0.0f, 999.0));
|
||||
delete formatReaderHigh;
|
||||
|
||||
juce::BigInteger usedNotes2;
|
||||
usedNotes2.setRange(1, 1, true);
|
||||
auto formatReaderLow = formatManager.createReaderFor(mySamplesLow);
|
||||
synth.addSound(new juce::SamplerSound("Low", *formatReaderLow, usedNotes2, 1, 0.0f, 0.0f, 999.0));
|
||||
delete formatReaderLow;
|
||||
}
|
||||
|
||||
void Metronome::prepareToPlay (double sr)
|
||||
{
|
||||
// Appelé avant de démaré la lecture, on récupère la sr et on initialise le reste du moteur
|
||||
sampleRate = sr;
|
||||
updateInterval = (int)(60.0 / bpm.get() * sampleRate);
|
||||
synth.setCurrentPlaybackSampleRate(sampleRate);
|
||||
initMeasure();
|
||||
}
|
||||
|
||||
void Metronome::getNextAudioBlock(juce::AudioSourceChannelInfo const& bufferToFill)
|
||||
{
|
||||
// Méthode invoqué par le moteur audio. Le but est de remplir bufferToFill avec la waveform que l'on souhaite jouer
|
||||
int const numSamples = bufferToFill.numSamples;
|
||||
|
||||
juce::MidiBuffer midi;
|
||||
int measCount = measures.get();
|
||||
|
||||
int measLength = updateInterval * measCount; // nombre de sample total dans une mesure
|
||||
int start = lastPos; // Le premier index du buffer correspond au lastPos
|
||||
int stop = lastPos + numSamples; // et la dernière position du buffer
|
||||
for (auto cur : measStruct)
|
||||
{
|
||||
// On cherche Si dans notre mesure on a un click entre start et stop
|
||||
int nextTick = (int)(cur.measPos * updateInterval); // le measPos est en relatif, on convertit en équivalent samples
|
||||
if (stop > measLength)
|
||||
{
|
||||
// Dans le cas ou stop se situe sur la mesure suivante, on décale le nextTick d'une mesure
|
||||
nextTick += measLength;
|
||||
}
|
||||
|
||||
if (nextTick >= start && nextTick < stop)
|
||||
{
|
||||
// On à trouvé un tick
|
||||
if (cur.type != NoteType::mute)
|
||||
{
|
||||
// qui est pas mute
|
||||
// on sélectionne la bone note, la bonne vélocité et on génère un événement midi à nextTick - start
|
||||
int note = cur.type == NoteType::high ? 0 : 1;
|
||||
float vel = cur.type == NoteType::lowLow ? 0.2f : 1.0f;
|
||||
midi.addEvent(juce::MidiMessage::noteOn(1, note, vel), nextTick - start);
|
||||
}
|
||||
|
||||
// on signale l'interface (pour marquer le temps même s'il est mute)
|
||||
signal.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
// On incrémente lastPos
|
||||
lastPos = stop;
|
||||
if (lastPos > measLength)
|
||||
{
|
||||
// Et on le remet dans la mesure suivante
|
||||
lastPos -= measLength;
|
||||
}
|
||||
|
||||
// On demande au synthé de remplir le buffer
|
||||
synth.renderNextBlock(*bufferToFill.buffer,
|
||||
midi,
|
||||
0,
|
||||
bufferToFill.numSamples);
|
||||
|
||||
// On reprend la main sur le buffer pour appliquer le gain manuellement
|
||||
float mult = gain.get();
|
||||
for (auto channel = 0; channel < bufferToFill.buffer->getNumChannels(); ++channel)
|
||||
{
|
||||
auto* buffer = bufferToFill.buffer->getWritePointer(channel, bufferToFill.startSample);
|
||||
|
||||
for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
|
||||
buffer[sample] = buffer[sample] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
void Metronome::reset()
|
||||
{
|
||||
// raz
|
||||
lastPos = 0;
|
||||
signal.set(true);
|
||||
}
|
||||
|
||||
void Metronome::setBPM(int value)
|
||||
{
|
||||
// contraint les BPM entre 10 et 400
|
||||
int coerce = juce::jlimit(10, 400, value);
|
||||
bpm.set(coerce);
|
||||
|
||||
int lastInterval = updateInterval;
|
||||
updateInterval = (int)(60.0 / bpm.get() * sampleRate);
|
||||
// En cas de changement de BPM brutal on constate un décalage dans la lecture
|
||||
// Pour remédier à ca on recalibre le lastPos en proportion du nouvel intervale
|
||||
lastPos = (int)(lastPos * (float)updateInterval / (float)lastInterval);
|
||||
}
|
||||
|
||||
int Metronome::getCurrentMeasure() const
|
||||
{
|
||||
// permet à l'UI de savoir sur quel temps de la mesure on se trouve
|
||||
int numTemps = (lastPos + updateInterval - 1) / updateInterval; // nombre de temps depuis le start
|
||||
return numTemps;
|
||||
}
|
||||
|
||||
void Metronome::initMeasure()
|
||||
{
|
||||
// construit la structure de la mesure
|
||||
measStruct.clear();
|
||||
int measCount = measures.get();
|
||||
switch (figure.get())
|
||||
{
|
||||
case FigureType::blanche:
|
||||
// On alterne click/Mute
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
}
|
||||
else
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, NoteType::mute));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case FigureType::noire:
|
||||
// Un click par temps
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
}
|
||||
|
||||
break;
|
||||
case FigureType::croche:
|
||||
// On alterne click/lowlow
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
measStruct.push_back(MeasureTick((float)i + 0.5f, NoteType::lowLow));
|
||||
}
|
||||
|
||||
break;
|
||||
case FigureType::triolet:
|
||||
// On alterne click/lowlow/lowlow
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
measStruct.push_back(MeasureTick((float)i + 1.f / 3.f, NoteType::lowLow));
|
||||
measStruct.push_back(MeasureTick((float)i + 2.f / 3.f, NoteType::lowLow));
|
||||
}
|
||||
break;
|
||||
case FigureType::doubleCroche:
|
||||
// On alterne click/lowlow/lowlow/lowlow
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
measStruct.push_back(MeasureTick((float)i + 0.25f, NoteType::lowLow));
|
||||
measStruct.push_back(MeasureTick((float)i + 0.5f, NoteType::lowLow));
|
||||
measStruct.push_back(MeasureTick((float)i + 0.75f, NoteType::lowLow));
|
||||
}
|
||||
break;
|
||||
case FigureType::swing:
|
||||
// On alterne click/lowlow sur les 2/3 du temps
|
||||
for (size_t i = 0; i < measCount; ++i)
|
||||
{
|
||||
measStruct.push_back(MeasureTick((float)i, i == 0 ? NoteType::high : NoteType::low));
|
||||
measStruct.push_back(MeasureTick((float)i + 2.f / 3.f, NoteType::lowLow));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
134
Source/Metronome.h
Normal file
134
Source/Metronome.h
Normal file
@ -0,0 +1,134 @@
|
||||
#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
|
||||
};
|
||||
319
Source/OptionsPanel.cpp
Normal file
319
Source/OptionsPanel.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion des options figure rythmique et fichier son du tick.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "OptionsPanel.h"
|
||||
#include "Figures.h"
|
||||
|
||||
void ClickSounds::init()
|
||||
{
|
||||
// on récupère tout les sous dossiers dans App/Clicks
|
||||
juce::File curDir{ juce::File::getSpecialLocation(juce::File::SpecialLocationType::currentExecutableFile).getParentDirectory() };
|
||||
juce::File clickDir{ curDir.getChildFile("Clicks")};
|
||||
auto it = clickDir.findChildFiles(juce::File::findDirectories, false);
|
||||
for (int i = 0; i < it.size(); ++i)
|
||||
{
|
||||
juce::File sub = it[i];
|
||||
bool highFile = !sub.findChildFiles(juce::File::TypesOfFileToFind::findFiles, false, "High*.wav").isEmpty();
|
||||
bool lowFile = !sub.findChildFiles(juce::File::TypesOfFileToFind::findFiles, false, "Low*.wav").isEmpty();
|
||||
if (highFile && lowFile)
|
||||
{
|
||||
// On n'ajoute que si on a bien les fichiers High et Low
|
||||
juce::String path = sub.getFullPathName();
|
||||
std::string ss = path.toStdString();
|
||||
sounds.push_back(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ClickSounds::getSoundName(int i) const
|
||||
{
|
||||
// Valeur affiché dans la combo, on récupère le nom du sous dossier
|
||||
juce::File path{ sounds[i] };
|
||||
return path.getFileNameWithoutExtension().toStdString();
|
||||
}
|
||||
|
||||
std::string ClickSounds::getSoundPathHigh(int i) const
|
||||
{
|
||||
// Chemin vers le fichier High
|
||||
juce::File path{ sounds[i] };
|
||||
return path.findChildFiles(juce::File::TypesOfFileToFind::findFiles, false, "High*.wav")[0].getFullPathName().toStdString();
|
||||
}
|
||||
std::string ClickSounds::getSoundPathLow(int i) const
|
||||
{
|
||||
// Chemin vers le fichier Low
|
||||
juce::File path{ sounds[i] };
|
||||
return path.findChildFiles(juce::File::TypesOfFileToFind::findFiles, false, "Low*.wav")[0].getFullPathName().toStdString();
|
||||
}
|
||||
|
||||
int ClickSounds::getIndex(std::string soundName) const
|
||||
{
|
||||
// récupère l'index du fichier à partir de son nom
|
||||
// Utilisé pour restaurer la configuration
|
||||
// Du coup si le son n'est pas trouvé on retourne le premier son
|
||||
for (int i = 0; i < sounds.size(); ++i)
|
||||
{
|
||||
if (getSoundName(i) == soundName)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ComboLookAndFeel::drawPopupMenuBackground(juce::Graphics& g, int width, int height)
|
||||
{
|
||||
// Permet de setter le background du PopupMenu
|
||||
g.fillAll(juce::Colours::whitesmoke);
|
||||
juce::ignoreUnused(width, height);
|
||||
|
||||
#if ! JUCE_MAC
|
||||
g.setColour(juce::Colours::darkgrey.withAlpha(0.6f));
|
||||
g.drawRect(0, 0, width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ComboLookAndFeel::drawPopupMenuItem(juce::Graphics& g, const juce::Rectangle<int>& area,
|
||||
const bool isSeparator, const bool isActive,
|
||||
const bool isHighlighted, const bool isTicked,
|
||||
const bool hasSubMenu, const juce::String& text,
|
||||
const juce::String& shortcutKeyText,
|
||||
const juce::Drawable* icon, const juce::Colour* const textColourToUse)
|
||||
{
|
||||
// Permet de setter le background du PopupMenuItem
|
||||
if (isSeparator)
|
||||
{
|
||||
auto r = area.reduced(5, 0);
|
||||
r.removeFromTop(juce::roundToInt(((float)r.getHeight() * 0.5f) - 0.5f));
|
||||
|
||||
g.setColour(juce::Colours::darkgrey.withAlpha(0.3f));
|
||||
g.fillRect(r.removeFromTop(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto textColour = (textColourToUse == nullptr ? juce::Colours::darkgrey
|
||||
: *textColourToUse);
|
||||
|
||||
auto r = area.reduced(1);
|
||||
|
||||
if (isHighlighted && isActive)
|
||||
{
|
||||
g.setColour(juce::Colours::lightgrey);
|
||||
g.fillRect(r);
|
||||
|
||||
g.setColour(juce::Colours::darkgrey);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setColour(textColour.withMultipliedAlpha(isActive ? 1.0f : 0.5f));
|
||||
}
|
||||
|
||||
r.reduce(juce::jmin(5, area.getWidth() / 20), 0);
|
||||
|
||||
auto font = getPopupMenuFont();
|
||||
|
||||
auto maxFontHeight = (float)r.getHeight() / 1.3f;
|
||||
|
||||
if (font.getHeight() > maxFontHeight)
|
||||
font.setHeight(maxFontHeight);
|
||||
|
||||
g.setFont(font);
|
||||
|
||||
auto iconArea = r.removeFromLeft(juce::roundToInt(maxFontHeight)).toFloat();
|
||||
|
||||
if (icon != nullptr)
|
||||
{
|
||||
icon->drawWithin(g, iconArea, juce::RectanglePlacement::centred | juce::RectanglePlacement::onlyReduceInSize, 1.0f);
|
||||
r.removeFromLeft(juce::roundToInt(maxFontHeight * 0.5f));
|
||||
}
|
||||
else if (isTicked)
|
||||
{
|
||||
auto tick = getTickShape(1.0f);
|
||||
g.fillPath(tick, tick.getTransformToScaleToFit(iconArea.reduced(iconArea.getWidth() / 5, 0).toFloat(), true));
|
||||
}
|
||||
|
||||
if (hasSubMenu)
|
||||
{
|
||||
auto arrowH = 0.6f * getPopupMenuFont().getAscent();
|
||||
|
||||
auto x = static_cast<float> (r.removeFromRight((int)arrowH).getX());
|
||||
auto halfH = static_cast<float> (r.getCentreY());
|
||||
|
||||
juce::Path path;
|
||||
path.startNewSubPath(x, halfH - arrowH * 0.5f);
|
||||
path.lineTo(x + arrowH * 0.6f, halfH);
|
||||
path.lineTo(x, halfH + arrowH * 0.5f);
|
||||
|
||||
g.strokePath(path, juce::PathStrokeType(2.0f));
|
||||
}
|
||||
|
||||
r.removeFromRight(3);
|
||||
g.drawFittedText(text, r, juce::Justification::centredLeft, 1);
|
||||
|
||||
if (shortcutKeyText.isNotEmpty())
|
||||
{
|
||||
auto f2 = font;
|
||||
f2.setHeight(f2.getHeight() * 0.75f);
|
||||
f2.setHorizontalScale(0.95f);
|
||||
g.setFont(f2);
|
||||
|
||||
g.drawText(shortcutKeyText, r, juce::Justification::centredRight, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OptionsPanel::OptionsPanel(juce::Colour c, Config& configuration) : backgroundColour(c)
|
||||
{
|
||||
// initialisation de l'interface
|
||||
clef.reset(new ComboLookAndFeel());
|
||||
addAndMakeVisible(figures);
|
||||
auto doc = juce::XmlDocument::parse(SVGFigures::noire); // on charge la noire par defaut, va être re-initialisé par la configuration
|
||||
auto note = juce::Drawable::createFromSVG(*doc);
|
||||
figures.setImages(note.get());
|
||||
figures.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||
figures.setColour(juce::TextButton::buttonColourId, juce::Colours::whitesmoke);
|
||||
figures.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
figures.onClick = [&]
|
||||
{
|
||||
// génère le dropdown menu des figures
|
||||
juce::PopupMenu menu;
|
||||
|
||||
int width = 70;
|
||||
int height = 48;
|
||||
menu.addCustomItem(1, std::make_unique<FigureButton>(SVGFigures::blanche, width, height, juce::Colours::whitesmoke));
|
||||
menu.addCustomItem(4, std::make_unique<FigureButton>(SVGFigures::triolet, width, height, juce::Colours::whitesmoke));
|
||||
menu.addCustomItem(2, std::make_unique<FigureButton>(SVGFigures::noire, width, height, juce::Colours::whitesmoke));
|
||||
menu.addCustomItem(5, std::make_unique<FigureButton>(SVGFigures::doubles, width, height, juce::Colours::whitesmoke));
|
||||
menu.addCustomItem(3, std::make_unique<FigureButton>(SVGFigures::croches, width, height, juce::Colours::whitesmoke));
|
||||
menu.addCustomItem(6, std::make_unique<FigureButton>(SVGFigures::swing, width, height, juce::Colours::whitesmoke));
|
||||
|
||||
menu.showMenuAsync(juce::PopupMenu::Options{}.withTargetComponent(figures)
|
||||
.withMinimumNumColumns(3), [&](int resultId) { if(resultId > 0) setFigure(resultId - 1); });
|
||||
};
|
||||
|
||||
addAndMakeVisible(sounds);
|
||||
sounds.setLookAndFeel(clef.get());
|
||||
sounds.setColour(juce::ComboBox::backgroundColourId, juce::Colours::whitesmoke);
|
||||
sounds.setColour(juce::ComboBox::outlineColourId, juce::Colours::darkgrey);
|
||||
sounds.setColour(juce::ComboBox::arrowColourId, juce::Colours::darkgrey);
|
||||
sounds.setColour(juce::ComboBox::textColourId, juce::Colours::darkgrey);
|
||||
clicksounds.init(); // charge la liste des sons
|
||||
curSoundID = clicksounds.getIndex(configuration.sound.toStdString()); // récupère le son courant dans la configuration
|
||||
}
|
||||
|
||||
juce::String OptionsPanel::getSoundName()
|
||||
{
|
||||
// Récupère le nom du son courant pour sauver la config
|
||||
return clicksounds.getSoundName(sounds.getSelectedId() - 1);
|
||||
}
|
||||
|
||||
void OptionsPanel::setFigure(int figure)
|
||||
{
|
||||
// MàJ de l'icone de la figure courante
|
||||
juce::String newSVG;
|
||||
switch (figure)
|
||||
{
|
||||
case 0:
|
||||
newSVG = SVGFigures::blanche;
|
||||
break;
|
||||
case 2:
|
||||
newSVG = SVGFigures::croches;
|
||||
break;
|
||||
case 3:
|
||||
newSVG = SVGFigures::triolet;
|
||||
break;
|
||||
case 4:
|
||||
newSVG = SVGFigures::doubles;
|
||||
break;
|
||||
case 5:
|
||||
newSVG = SVGFigures::swing;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
newSVG = SVGFigures::noire;
|
||||
break;
|
||||
}
|
||||
|
||||
auto doc = juce::XmlDocument::parse(newSVG);
|
||||
auto note = juce::Drawable::createFromSVG(*doc);
|
||||
figures.setImages(note.get());
|
||||
setMetroFigure(figure);
|
||||
}
|
||||
|
||||
OptionsPanel::~OptionsPanel()
|
||||
{
|
||||
// evite une fuite mémoire à la fermeture due au L&F
|
||||
sounds.setLookAndFeel(nullptr);
|
||||
figures.setLookAndFeel(nullptr);
|
||||
}
|
||||
|
||||
void OptionsPanel::paint(juce::Graphics& g)
|
||||
{
|
||||
g.fillAll(backgroundColour);
|
||||
}
|
||||
|
||||
void OptionsPanel::resized()
|
||||
{
|
||||
// On utilise un layout grille en 2 colonnes
|
||||
int margin = 3;
|
||||
juce::Grid grid;
|
||||
using Track = juce::Grid::TrackInfo;
|
||||
using Fr = juce::Grid::Fr;
|
||||
grid.templateRows = { Track(Fr(1)) };
|
||||
grid.templateColumns = { Track(Fr(1)), Track(Fr(1)) };
|
||||
grid.items = {
|
||||
juce::GridItem(figures).withMargin(juce::GridItem::Margin(margin)),
|
||||
juce::GridItem(sounds).withMargin(juce::GridItem::Margin(margin)),
|
||||
};
|
||||
|
||||
grid.performLayout(getLocalBounds());
|
||||
}
|
||||
|
||||
void OptionsPanel::init(Metronome& metro)
|
||||
{
|
||||
// On établi les liaisons entre le Metronome et les composants graphique
|
||||
for (int i = 0; i < clicksounds.getSoundCount(); ++i)
|
||||
{
|
||||
sounds.addItem(clicksounds.getSoundName(i), i + 1); // La combo n'autorise pas 0 comme Id, d'ou le + 1
|
||||
}
|
||||
|
||||
sounds.setSelectedId(curSoundID + 1); // toujours ce + 1
|
||||
selectSound(metro); // charge le son courant dans le metronome
|
||||
sounds.onChange = [&, this]() { selectSound(metro); };
|
||||
setMetroFigure = [&](int figure) { metro.setFigure(figure); };
|
||||
setFigure((int)metro.getFigure());
|
||||
}
|
||||
|
||||
void OptionsPanel::selectSound(Metronome& metro)
|
||||
{
|
||||
// charge le son courant dans le metronome
|
||||
std::string high = clicksounds.getSoundPathHigh(sounds.getSelectedId() - 1);
|
||||
std::string low = clicksounds.getSoundPathLow(sounds.getSelectedId() - 1);
|
||||
metro.loadSounds(high, low);
|
||||
}
|
||||
145
Source/OptionsPanel.h
Normal file
145
Source/OptionsPanel.h
Normal file
@ -0,0 +1,145 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion des options figure rythmique et fichier son du tick.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Metronome.h"
|
||||
#include "Config.h"
|
||||
|
||||
class Config;
|
||||
class Metronome;
|
||||
|
||||
// Surcharge les boutons pour afficher l'image de la figure rythmique
|
||||
struct FigureButton : public juce::PopupMenu::CustomComponent
|
||||
{
|
||||
FigureButton(juce::String image, int widthIn, int heightIn, juce::Colour backgroundIn)
|
||||
: juce::PopupMenu::CustomComponent(false),
|
||||
idealWidth(widthIn),
|
||||
idealHeight(heightIn),
|
||||
background(backgroundIn)
|
||||
{
|
||||
// initialisation de l'interface
|
||||
addAndMakeVisible(button);
|
||||
// récupère l'image de la figure
|
||||
auto doc = juce::XmlDocument::parse(image);
|
||||
auto note = juce::Drawable::createFromSVG(*doc);
|
||||
button.setImages(note.get());
|
||||
button.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||
button.setColour(juce::TextButton::buttonColourId, juce::Colours::whitesmoke);
|
||||
button.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
button.onClick = [&, this]
|
||||
{
|
||||
// notifie la "Combo"
|
||||
this->triggerMenuItem();
|
||||
};
|
||||
}
|
||||
|
||||
void getIdealSize(int& width, int& height) override
|
||||
{
|
||||
width = idealWidth;
|
||||
height = idealHeight;
|
||||
}
|
||||
|
||||
void paint(juce::Graphics& g) override { g.fillAll(background); }
|
||||
|
||||
void resized() override { button.setBounds(getBounds()); }
|
||||
|
||||
// composants graphiques
|
||||
juce::Colour background;
|
||||
juce::DrawableButton button{ "Figures", juce::DrawableButton::ImageOnButtonBackground };
|
||||
|
||||
// taille du bouton
|
||||
int idealWidth = 0;
|
||||
int idealHeight = 0;
|
||||
};
|
||||
|
||||
// L&F pour la combo des sons, permet de setter le background du Popup
|
||||
struct ComboLookAndFeel : public juce::LookAndFeel_V4
|
||||
{
|
||||
void drawPopupMenuBackground(juce::Graphics& g, int width, int height) override;
|
||||
void drawPopupMenuItem(juce::Graphics& g, const juce::Rectangle<int>& area,
|
||||
const bool isSeparator, const bool isActive,
|
||||
const bool isHighlighted, const bool isTicked,
|
||||
const bool hasSubMenu, const juce::String& text,
|
||||
const juce::String& shortcutKeyText,
|
||||
const juce::Drawable* icon, const juce::Colour* const textColourToUse) override;
|
||||
};
|
||||
|
||||
// structure dédiée à la gestion des sons
|
||||
struct ClickSounds
|
||||
{
|
||||
ClickSounds() {};
|
||||
|
||||
// Charge la liste de sons
|
||||
void init();
|
||||
|
||||
// Accesseurs
|
||||
int getSoundCount() const { return (int)sounds.size(); };
|
||||
std::string getSoundName(int i) const;
|
||||
std::string getSoundPathHigh(int i) const;
|
||||
std::string getSoundPathLow(int i) const;
|
||||
|
||||
int getIndex(std::string soundName) const;
|
||||
|
||||
// Liste des sons
|
||||
std::vector<std::string> sounds;
|
||||
};
|
||||
|
||||
// Panneau d'affichage des options
|
||||
struct OptionsPanel : public juce::Component
|
||||
{
|
||||
explicit OptionsPanel(juce::Colour c, Config& configuration);
|
||||
~OptionsPanel();
|
||||
|
||||
// Méthode de surcharge JUCE
|
||||
void paint(juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
// méthodes internes
|
||||
void init(Metronome& metro);
|
||||
|
||||
void selectSound(Metronome& metro);
|
||||
void setFigure(int figure);
|
||||
juce::String getSoundName();
|
||||
|
||||
// composants graphiques
|
||||
juce::DrawableButton figures{ "Figures", juce::DrawableButton::ImageOnButtonBackground };
|
||||
juce::ComboBox sounds;
|
||||
juce::Colour backgroundColour;
|
||||
std::unique_ptr <ComboLookAndFeel> clef;
|
||||
|
||||
// variables internes
|
||||
// liste des sons
|
||||
ClickSounds clicksounds;
|
||||
|
||||
// pointeur sur la méthode qui permet de setter le metronome
|
||||
std::function< void(int)> setMetroFigure {nullptr};
|
||||
|
||||
// permet de stocker l'id du son selectionné dans la configuration entre le constructeur et le init()
|
||||
int curSoundID;
|
||||
};
|
||||
161
Source/PlayPanel.cpp
Normal file
161
Source/PlayPanel.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du bouton play et du volume.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "PlayPanel.h"
|
||||
#include "Metronome.h"
|
||||
#include "Figures.h"
|
||||
|
||||
void RoundButtonLookAndFeel::drawButtonBackground(juce::Graphics& g, juce::Button& button, const juce::Colour& backgroundColour,
|
||||
bool isMouseOverButton, bool isButtonDown)
|
||||
{
|
||||
// version addapté du LookAndFeel_V4
|
||||
auto baseColour = backgroundColour.withMultipliedSaturation(button.hasKeyboardFocus(true) ? 1.3f : 0.9f)
|
||||
.withMultipliedAlpha(button.isEnabled() ? 0.9f : 0.5f);
|
||||
|
||||
if (isButtonDown || isMouseOverButton)
|
||||
baseColour = baseColour.contrasting(isButtonDown ? 0.2f : 0.1f);
|
||||
|
||||
auto width = (float)button.getWidth() - 1.0f;
|
||||
auto height = (float)button.getHeight() - 1.0f;
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
// on viens dessiner un cercle
|
||||
auto rect = button.getLocalBounds();
|
||||
float rwidth = rect.getWidth() < rect.getHeight() ? (float)rect.getWidth() - 25.0f : (float)rect.getHeight() - 25.0f;
|
||||
|
||||
g.setGradientFill(juce::ColourGradient::vertical(juce::Colours::lightgrey, 0.0f,
|
||||
juce::Colours::lightgrey.darker(0.1f), height));
|
||||
g.fillEllipse(rect.getCentreX() - rwidth / 2, rect.getCentreY() - rwidth / 2, rwidth, rwidth);
|
||||
|
||||
g.setGradientFill(juce::ColourGradient::vertical(baseColour, 0.0f,
|
||||
baseColour.darker(0.1f), height));
|
||||
|
||||
g.drawEllipse(rect.getCentreX() - rwidth / 2, rect.getCentreY() - rwidth / 2, rwidth, rwidth, 4);
|
||||
}
|
||||
}
|
||||
|
||||
PlayPanel::PlayPanel(juce::Colour c) : backgroundColour(c)
|
||||
{
|
||||
// initialisation de l'interface
|
||||
lef.reset(new RoundButtonLookAndFeel());
|
||||
|
||||
// Le dessin du bouton play est dans un svg
|
||||
auto doc = juce::XmlDocument::parse(SVGFigures::play);
|
||||
auto image = juce::Drawable::createFromSVG(*doc);
|
||||
addComponent(volume);
|
||||
addComponent(playButton);
|
||||
playButton.setRadioGroupId(1);
|
||||
playButton.setImages(image.get());
|
||||
playButton.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||
playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::lightgreen);
|
||||
playButton.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
playButton.setLookAndFeel(lef.get());
|
||||
volume.setRange(-100, 6); // on prend -100db en min, et on s'autorise à amplifier le sample à +6db
|
||||
volume.setValue(0); // valeur initiale à 0db
|
||||
volume.setSliderStyle(juce::Slider::SliderStyle::LinearVertical);
|
||||
volume.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, true, 0, 0);
|
||||
volume.setColour(juce::Slider::thumbColourId, backgroundColour);
|
||||
volume.setColour(juce::Slider::trackColourId, juce::Colours::green);
|
||||
}
|
||||
|
||||
PlayPanel::~PlayPanel()
|
||||
{
|
||||
// evite une fuite mémoire à la fermeture due au L&F
|
||||
playButton.setLookAndFeel(nullptr);
|
||||
}
|
||||
|
||||
void PlayPanel::addComponent(juce::Component& c)
|
||||
{
|
||||
addAndMakeVisible(c);
|
||||
c.setColour(juce::TextButton::buttonColourId, backgroundColour);
|
||||
c.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
}
|
||||
|
||||
void PlayPanel::paint(juce::Graphics& g)
|
||||
{
|
||||
g.fillAll(backgroundColour);
|
||||
}
|
||||
|
||||
void PlayPanel::resized()
|
||||
{
|
||||
// On gêre le placement via une grille 3 collones
|
||||
// la première colonne est vide et sert de "marge"
|
||||
juce::Grid vpgrid;
|
||||
using Track = juce::Grid::TrackInfo;
|
||||
using Fr = juce::Grid::Fr;
|
||||
vpgrid.templateRows = { Track(Fr(1)) };
|
||||
vpgrid.templateColumns = { Track(Fr(1)), Track(Fr(5)), Track(Fr(1)) };
|
||||
|
||||
vpgrid.items = { juce::GridItem(), juce::GridItem(playButton), juce::GridItem(volume) };
|
||||
vpgrid.performLayout(getLocalBounds());
|
||||
}
|
||||
|
||||
void PlayPanel::init(Metronome& metro)
|
||||
{
|
||||
// On établi les liaisons entre le Metronome et les composants graphique
|
||||
playButton.onClick = [&, this]() { play(metro); };
|
||||
volume.setValue(juce::Decibels::gainToDecibels(metro.getGain())); // On récupère la valeur initiale du gain
|
||||
volume.onValueChange = [&, this]
|
||||
{
|
||||
double db = volume.getValue();
|
||||
metro.setGain((float)juce::Decibels::decibelsToGain(db));
|
||||
};
|
||||
}
|
||||
|
||||
void PlayPanel::play(Metronome& metro)
|
||||
{
|
||||
// lance la lecture ou met en pause
|
||||
playState = playState == PlayState::playing ? PlayState::stopped : PlayState::playing;
|
||||
if (playState == PlayState::stopped)
|
||||
{
|
||||
// en cas de stop, on remet les compteurs à zero sur le metronome
|
||||
metro.reset();
|
||||
}
|
||||
|
||||
// On modifie la couleur du bouton en fonction de l'état
|
||||
playButton.setColour(juce::TextButton::buttonColourId, playState == PlayState::playing ? juce::Colours::green : juce::Colours::lightgreen);
|
||||
}
|
||||
|
||||
void PlayPanel::highlight()
|
||||
{
|
||||
// Met le bouton en surbrillance sur le temps
|
||||
// la variable highlightFrames decompte 6 frames sur un timer de 20ms soit 120ms
|
||||
if (playState == PlayState::playing)
|
||||
{
|
||||
if (highlightFrames > 0)
|
||||
{
|
||||
playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::orangered);
|
||||
highlightFrames--;
|
||||
}
|
||||
else
|
||||
{
|
||||
playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::green);
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Source/PlayPanel.h
Normal file
73
Source/PlayPanel.h
Normal file
@ -0,0 +1,73 @@
|
||||
#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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du bouton play et du volume.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
#include <JuceHeader.h>
|
||||
#include "Metronome.h"
|
||||
|
||||
// Etat de lecture
|
||||
enum class PlayState
|
||||
{
|
||||
playing,
|
||||
stopped
|
||||
};
|
||||
|
||||
// surcharge du look&feel pour dessiner le bouton play en cercle
|
||||
struct RoundButtonLookAndFeel : public juce::LookAndFeel_V4
|
||||
{
|
||||
void drawButtonBackground(juce::Graphics& g, juce::Button& button, const juce::Colour& backgroundColour,
|
||||
bool isMouseOverButton, bool isButtonDown) override;
|
||||
};
|
||||
|
||||
// classe principale
|
||||
struct PlayPanel : public juce::Component
|
||||
{
|
||||
explicit PlayPanel(juce::Colour c);
|
||||
~PlayPanel();
|
||||
|
||||
// Méthode de surcharge JUCE
|
||||
void paint(juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
// utilitaire graphique
|
||||
void addComponent(juce::Component& c);
|
||||
|
||||
// méthodes de gestion du lecteur
|
||||
void init(Metronome& metro);
|
||||
void play(Metronome& metro);
|
||||
void highlight();
|
||||
|
||||
// composants graphiques
|
||||
juce::Colour backgroundColour;
|
||||
juce::Slider volume;
|
||||
juce::DrawableButton playButton { "Play", juce::DrawableButton::ImageOnButtonBackground };
|
||||
std::unique_ptr <RoundButtonLookAndFeel> lef;
|
||||
|
||||
// variables internes
|
||||
int highlightFrames;
|
||||
PlayState playState{ PlayState::stopped };
|
||||
};
|
||||
91
Source/TempoPanel.cpp
Normal file
91
Source/TempoPanel.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
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/>.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du nombre de temps par mesure.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
#include "TempoPanel.h"
|
||||
#include "Metronome.h"
|
||||
|
||||
TempoPanel::TempoPanel(juce::Colour c) : backgroundColour(c)
|
||||
{
|
||||
// initialisation de l'interface
|
||||
addComponent(decrement);
|
||||
addComponent(tempo);
|
||||
addComponent(increment);
|
||||
tempo.setText("4", juce::dontSendNotification); // On met une valeur mais elle va être RaZ dans le init()
|
||||
tempo.getFont().setBold(true);
|
||||
tempo.setColour(juce::Label::textColourId, juce::Colours::black);
|
||||
tempo.setJustificationType(juce::Justification::centred);
|
||||
tempo.setFont(30);
|
||||
}
|
||||
|
||||
void TempoPanel::addComponent(juce::Component& c)
|
||||
{
|
||||
addAndMakeVisible(c);
|
||||
c.setColour(juce::TextButton::buttonColourId, backgroundColour);
|
||||
c.setColour(juce::TextButton::textColourOffId, juce::Colours::black);
|
||||
}
|
||||
|
||||
void TempoPanel::paint(juce::Graphics& g)
|
||||
{
|
||||
g.fillAll(backgroundColour);
|
||||
}
|
||||
|
||||
void TempoPanel::resized()
|
||||
{
|
||||
// On gêre le layout à la main
|
||||
auto area = getLocalBounds();
|
||||
int butHeigth = 20;
|
||||
int butWidth = 48;
|
||||
int labeSize = 3 * butHeigth;
|
||||
int totalWidth = 2 * butWidth + labeSize;
|
||||
int marginH = (area.getWidth() - totalWidth) / 2;
|
||||
int marginV = (area.getHeight() - labeSize) / 2;
|
||||
decrement.setBounds(area.getX() + marginH, area.getY() + marginV + butHeigth, butWidth, butHeigth);
|
||||
tempo.setBounds(area.getX() + marginH + butWidth, area.getY() + marginV, labeSize, labeSize);
|
||||
increment.setBounds(area.getX() + marginH + butWidth + labeSize, area.getY() + marginV + butHeigth, butWidth, butHeigth);
|
||||
}
|
||||
|
||||
void TempoPanel::init(Metronome& metro)
|
||||
{
|
||||
// On établi les liaisons entre le Metronome et les composants graphique
|
||||
tempo.setText(juce::String(metro.getMeasures()), juce::dontSendNotification);
|
||||
increment.onClick = [&, this]() { inc(metro); };
|
||||
decrement.onClick = [&, this]() { dec(metro); };
|
||||
}
|
||||
|
||||
void TempoPanel::inc(Metronome& metro)
|
||||
{
|
||||
// incrémente le tempo
|
||||
metro.setMeasures(metro.getMeasures() + 1);
|
||||
tempo.setText(juce::String(metro.getMeasures()), juce::dontSendNotification); // MàJ du label
|
||||
}
|
||||
|
||||
void TempoPanel::dec(Metronome& metro)
|
||||
{
|
||||
// decremente le tempo
|
||||
metro.setMeasures(metro.getMeasures() - 1);
|
||||
tempo.setText(juce::String(metro.getMeasures()), juce::dontSendNotification); // MàJ du label
|
||||
}
|
||||
34
Source/TempoPanel.h
Normal file
34
Source/TempoPanel.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
Gestion du nombre de temps par mesure.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Metronome.h"
|
||||
|
||||
struct TempoPanel : public juce::Component
|
||||
{
|
||||
explicit TempoPanel(juce::Colour c);
|
||||
|
||||
// Méthode de surcharge JUCE
|
||||
void paint(juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
// utilitaire graphique
|
||||
void addComponent(juce::Component& c);
|
||||
|
||||
// méthodes de gestion du tempo
|
||||
void init(Metronome& metro);
|
||||
void inc(Metronome& metro);
|
||||
void dec(Metronome& metro);
|
||||
|
||||
// composants graphiques
|
||||
juce::Colour backgroundColour;
|
||||
juce::TextButton increment{ "+" };
|
||||
juce::TextButton decrement{ "-" };
|
||||
juce::Label tempo;
|
||||
};
|
||||
114
Tchick.jucer
Normal file
114
Tchick.jucer
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<JUCERPROJECT id="eEbCxS" name="Tchick" projectType="guiapp" useAppConfig="0"
|
||||
addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" displaySplashScreen="1"
|
||||
cppLanguageStandard="latest" splashScreenColour="Light" includeBinaryInJuceHeader="0">
|
||||
<MAINGROUP id="gPzZc8" name="Tchick">
|
||||
<GROUP id="{EDCE3033-ED90-D340-9E42-D702C9B82B08}" name="Assets">
|
||||
<GROUP id="{A07629F7-9E5A-559D-9755-2EB795077D4C}" name="Clicks">
|
||||
<GROUP id="{778AD36A-ADB9-BCE2-49CC-77E288129AEA}" name="01 SeikoSQ50">
|
||||
<FILE id="C9jq8N" name="High Seiko SQ50.wav" compile="0" resource="0"
|
||||
file="Assets/Clicks/01 SeikoSQ50/High Seiko SQ50.wav"/>
|
||||
<FILE id="uQbK7f" name="Low Seiko SQ50.wav" compile="0" resource="0"
|
||||
file="Assets/Clicks/01 SeikoSQ50/Low Seiko SQ50.wav"/>
|
||||
</GROUP>
|
||||
<GROUP id="{AE41D956-97BE-1D29-5301-286FB4B56301}" name="02 Stick">
|
||||
<FILE id="CM52vr" name="High Stick.wav" compile="0" resource="0" file="Assets/Clicks/02 Stick/High Stick.wav"/>
|
||||
<FILE id="zawixh" name="Low Stick.wav" compile="0" resource="0" file="Assets/Clicks/02 Stick/Low Stick.wav"/>
|
||||
</GROUP>
|
||||
<GROUP id="{D75593D1-F482-E1B6-CA27-988E2524442D}" name="03 Cowbell">
|
||||
<FILE id="TjWHWd" name="High Cowbell.wav" compile="0" resource="0"
|
||||
file="Assets/Clicks/03 Cowbell/High Cowbell.wav"/>
|
||||
<FILE id="U48pfg" name="Low Cowbell.wav" compile="0" resource="0" file="Assets/Clicks/03 Cowbell/Low Cowbell.wav"/>
|
||||
</GROUP>
|
||||
<GROUP id="{A40DDBDF-ED54-59C0-CFCD-43194EE8C07A}" name="04 vChip Wood">
|
||||
<FILE id="j6eFYY" name="High Wood.wav" compile="0" resource="0" file="Assets/Clicks/04 vChip Wood/High Wood.wav"/>
|
||||
<FILE id="TNRBe5" name="Low Wood.wav" compile="0" resource="0" file="Assets/Clicks/04 vChip Wood/Low Wood.wav"/>
|
||||
</GROUP>
|
||||
<GROUP id="{157DA364-7F83-712F-1AFC-FB74BC4B3E23}" name="05 vChip Claves">
|
||||
<FILE id="she6pj" name="HIgh Claves.wav" compile="0" resource="0" file="Assets/Clicks/05 vChip Claves/HIgh Claves.wav"/>
|
||||
<FILE id="EC66R0" name="Low Claves.wav" compile="0" resource="0" file="Assets/Clicks/05 vChip Claves/Low Claves.wav"/>
|
||||
</GROUP>
|
||||
</GROUP>
|
||||
</GROUP>
|
||||
<GROUP id="{1F26F6FE-63EA-7E00-50D6-9178F972F8B2}" name="Source">
|
||||
<FILE id="GSXFyS" name="OptionsPanel.cpp" compile="1" resource="0"
|
||||
file="Source/OptionsPanel.cpp"/>
|
||||
<FILE id="rNkF5a" name="TempoPanel.h" compile="0" resource="0" file="Source/TempoPanel.h"/>
|
||||
<FILE id="EoRTt3" name="TempoPanel.cpp" compile="1" resource="0" file="Source/TempoPanel.cpp"/>
|
||||
<FILE id="sl7izB" name="PlayPanel.h" compile="0" resource="0" file="Source/PlayPanel.h"/>
|
||||
<FILE id="aswza3" name="PlayPanel.cpp" compile="1" resource="0" file="Source/PlayPanel.cpp"/>
|
||||
<FILE id="TPOq96" name="OptionsPanel.h" compile="0" resource="0" file="Source/OptionsPanel.h"/>
|
||||
<FILE id="bEvzCW" name="MesurePanel.h" compile="0" resource="0" file="Source/MesurePanel.h"/>
|
||||
<FILE id="s74lBs" name="MesurePanel.cpp" compile="1" resource="0" file="Source/MesurePanel.cpp"/>
|
||||
<FILE id="Ww74sz" name="Figures.h" compile="0" resource="0" file="Source/Figures.h"/>
|
||||
<FILE id="QS0xaD" name="Config.h" compile="0" resource="0" file="Source/Config.h"/>
|
||||
<FILE id="JbnJt4" name="Config.cpp" compile="1" resource="0" file="Source/Config.cpp"/>
|
||||
<FILE id="PAwDsp" name="BPMPanel.h" compile="0" resource="0" file="Source/BPMPanel.h"/>
|
||||
<FILE id="fz3AGQ" name="BPMPanel.cpp" compile="1" resource="0" file="Source/BPMPanel.cpp"/>
|
||||
<FILE id="RqMHaF" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/>
|
||||
<FILE id="lKOoJh" name="Metronome.h" compile="0" resource="0" file="Source/Metronome.h"/>
|
||||
<FILE id="A0wYoj" name="Metronome.cpp" compile="1" resource="0" file="Source/Metronome.cpp"/>
|
||||
<FILE id="WW9a1R" name="MainComponent.h" compile="0" resource="0" file="Source/MainComponent.h"/>
|
||||
<FILE id="qf5GwL" name="MainComponent.cpp" compile="1" resource="0"
|
||||
file="Source/MainComponent.cpp"/>
|
||||
</GROUP>
|
||||
</MAINGROUP>
|
||||
<JUCEOPTIONS JUCE_STRICT_REFCOUNTEDPOINTER="1" JUCE_JACK="1"/>
|
||||
<EXPORTFORMATS>
|
||||
<VS2022 targetFolder="./.">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION isDebug="1" name="Debug" prebuildCommand="xcopy /s /y "$(SolutionDir)Assets\Clicks" "$(OutDir)\Clicks\""/>
|
||||
<CONFIGURATION isDebug="0" name="Release" prebuildCommand="xcopy /s /y "$(SolutionDir)Assets\Clicks" "$(OutDir)\Clicks\""/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_audio_basics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../../juce"/>
|
||||
<MODULEPATH id="juce_core" path="../../juce"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../../juce"/>
|
||||
<MODULEPATH id="juce_events" path="../../juce"/>
|
||||
<MODULEPATH id="juce_graphics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_utils" path="C:/Temp/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="C:/Temp/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="C:/Temp/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</VS2022>
|
||||
<LINUX_MAKE targetFolder="./.">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION isDebug="1" name="Debug"/>
|
||||
<CONFIGURATION isDebug="0" name="Release"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_audio_basics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../../juce"/>
|
||||
<MODULEPATH id="juce_core" path="../../juce"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../../juce"/>
|
||||
<MODULEPATH id="juce_events" path="../../juce"/>
|
||||
<MODULEPATH id="juce_graphics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../../juce"/>
|
||||
<MODULEPATH id="juce_audio_utils" path="C:/Temp/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="C:/Temp/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="C:/Temp/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</LINUX_MAKE>
|
||||
</EXPORTFORMATS>
|
||||
<MODULES>
|
||||
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_core" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_events" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_graphics" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||
</MODULES>
|
||||
<LIVE_SETTINGS>
|
||||
<LINUX/>
|
||||
</LIVE_SETTINGS>
|
||||
</JUCERPROJECT>
|
||||
21
Tchick.sln
Normal file
21
Tchick.sln
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio Version 17
|
||||
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tchick - App", "Tchick_App.vcxproj", "{F9D7600C-859C-26DC-FE32-2EB5A98F1734}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F9D7600C-859C-26DC-FE32-2EB5A98F1734}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F9D7600C-859C-26DC-FE32-2EB5A98F1734}.Debug|x64.Build.0 = Debug|x64
|
||||
{F9D7600C-859C-26DC-FE32-2EB5A98F1734}.Release|x64.ActiveCfg = Release|x64
|
||||
{F9D7600C-859C-26DC-FE32-2EB5A98F1734}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
3235
Tchick_App.vcxproj
Normal file
3235
Tchick_App.vcxproj
Normal file
File diff suppressed because it is too large
Load Diff
5696
Tchick_App.vcxproj.filters
Normal file
5696
Tchick_App.vcxproj.filters
Normal file
File diff suppressed because it is too large
Load Diff
4
Tchick_App.vcxproj.user
Normal file
4
Tchick_App.vcxproj.user
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
31
resources.rc
Normal file
31
resources.rc
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef JUCE_USER_DEFINED_RC_FILE
|
||||
#include JUCE_USER_DEFINED_RC_FILE
|
||||
#else
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "Tchick\0"
|
||||
VALUE "FileVersion", "1.0.0\0"
|
||||
VALUE "ProductName", "Tchick\0"
|
||||
VALUE "ProductVersion", "1.0.0\0"
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user