2 Commits

Author SHA1 Message Date
19c90b0434 wip: apply gui states 2024-01-19 01:55:51 +07:00
b996685fe6 feat: parse patch files from json 2024-01-18 01:56:00 +07:00
13 changed files with 24928 additions and 7 deletions

15
.vscode/settings.json vendored
View File

@@ -64,7 +64,20 @@
"__string": "cpp",
"compare": "cpp",
"concepts": "cpp",
"numeric": "cpp"
"numeric": "cpp",
"__tree": "cpp",
"any": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"iomanip": "cpp",
"map": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"stack": "cpp",
"valarray": "cpp",
"ranges": "cpp",
"iostream": "cpp"
},
"FSharp.suggestGitignore": false,
}

View File

@@ -17,6 +17,10 @@ FetchContent_Declare(
FetchContent_MakeAvailable(raylib)
# Add nlohmann_json
# FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)
# FetchContent_MakeAvailable(json)
# Adding our source files
file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp") # Define PROJECT_SOURCES as a list of all source files
set(PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/inc/") # Define PROJECT_INCLUDE to be the path to the include directory of the project
@@ -31,6 +35,7 @@ set_target_properties(
target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE})
target_link_libraries(${PROJECT_NAME} PRIVATE raylib)
# target_link_libraries(${PROJECT_NAME} PRIVATE json)
# Setting ASSETS_PATH
target_compile_definitions(${PROJECT_NAME} PUBLIC ASSETS_PATH="${CMAKE_CURRENT_SOURCE_DIR}/assets/") # Set the asset path macro to the absolute path on the dev machine

View File

@@ -23,4 +23,5 @@ class Application {
Application(/* args */);
~Application();
void Run();
void ParsePatch(std::string file_path);
};

View File

@@ -29,6 +29,7 @@ class Oscillator {
~Oscillator();
OscillatorType GetType() { return m_osc; }
void SetType(OscillatorType osc);
void SetType(std::string const& osc_name);
float GetVolume() { return m_volume; }
void SetVolume(float volume) { m_volume = volume; }
float GetKey() { return m_key; }

View File

@@ -17,6 +17,7 @@ class Synth {
std::vector<IEffect*> m_effects;
std::vector<float> m_out_signal;
LFO* m_lfo;
float m_lfo_level;
void ZeroSignal();
void GetNote();
void TriggerNoteOnEffects();
@@ -36,5 +37,8 @@ class Synth {
const bool& GetIsNoteTriggered() { return is_note_triggered; }
ADSR* GetADSR() { return (ADSR*)m_effects[0]; }
Filter* GetFilter() { return (Filter*)m_effects[1]; }
LFO* GetLFO() { return m_lfo; }
const float& GetLFOLevel() { return m_lfo_level; }
void SetLFOLevel(float lvl) { assert(0.f >= lvl <= 1.f); m_lfo_level = lvl; }
void SetFilter(FilterType type);
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "OscillatorType.h"
#include "raygui.h"
#include "raysan/raygui.h"
#include <vector>
#include "Filter.h"

24765
inc/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,12 @@
#include "Application.h"
#include "Logger.h"
#include "Settings.h"
#include <cmath> // log10f
#include <fstream> // read file
#include <iostream> // log error
#include <nlohmann/json.hpp>
#include <string>
using json = nlohmann::json;
Application::Application(/* args */) {
InitSynth();
@@ -94,7 +99,7 @@ void Application::UpdateOnNoteInput() {
if (!m_synth.GetIsNoteTriggered()) {
m_synth.Trigger((*m_current_note));
}
//write_log("Note played: %s\n", m_current_note->name.c_str());
// write_log("Note played: %s\n", m_current_note->name.c_str());
} else if (is_note_up() && m_synth.GetIsNoteTriggered()) {
m_synth.Release();
}
@@ -118,3 +123,67 @@ void Application::Run() {
m_renderer.Draw(m_synth, m_synth_gui_state);
}
}
void Application::ParsePatch(std::string file_path) {
std::ifstream f(file_path);
if (!f.is_open()) {
std::cerr << "[ERR] failed to open " << file_path << '\n';
} else {
json data = json::parse(f);
auto oscillators = m_synth.GetOscillators();
for (int i = 0; i < oscillators.size(); i++) {
auto osc = oscillators[i];
auto gui_osc = m_synth_gui_state.oscillators[i];
std::string type =
data["Oscillators"][i]["Wave"].template get<std::string>();
float fine = data["Oscillators"][i]["Tune"].template get<float>();
float volume =
data["Oscillators"][i]["Volume"].template get<float>();
osc->SetType(type);
osc->SetFine(fine);
osc->SetVolume(volume);
gui_osc->waveshape = osc->GetType();
gui_osc->fine = fine;
gui_osc->volume = volume;
}
auto adsr = m_synth.GetADSR();
auto gui_adsr = m_synth_gui_state.adsr;
auto adsr_params = data["ADSR"];
float attack = adsr_params["Attack"].template get<float>();
float decay = adsr_params["Decay"].template get<float>();
float sustain = adsr_params["Sustain"].template get<float>();
float release = adsr_params["Release"].template get<float>();
adsr->SetParameters(attack, decay, sustain, release);
gui_adsr.attack = attack;
gui_adsr.decay = decay;
gui_adsr.sustain = sustain;
gui_adsr.release = release;
auto lfo = m_synth.GetLFO();
lfo->SetFreq(data["LFO"]["Freq"].template get<float>());
m_synth.SetLFOLevel(data["LFO"]["Level"].template get<float>());
auto filter_type =
(FilterType)data["Filter"]["Type"].template get<int>();
m_synth.SetFilter(filter_type);
auto filter = m_synth.GetFilter();
auto gui_filter = m_synth_gui_state.filter;
float filter_freq =
std::log10f(data["Filter"]["Cutoff"].template get<float>());
float filter_res = data["Filter"]["Res"].template get<float>();
float filter_drive = data["Filter"]["Drive"].template get<float>();
filter->SetParameters(filter_freq, filter_res, filter_drive);
gui_filter.freq = filter_freq;
gui_filter.type = filter_type;
}
}

View File

@@ -43,6 +43,19 @@ void Oscillator::SetType(OscillatorType osc) {
}
}
void Oscillator::SetType(std::string const& osc_name) {
if (osc_name == "Sine")
m_osc = Sine;
else if (osc_name == "Triangle")
m_osc = Triangle;
else if (osc_name == "Saw")
m_osc = Saw;
else if (osc_name == "Square")
m_osc = Square;
SetType(m_osc);
}
void Oscillator::SetKey(float key) {
m_key = key;
float freq = KeyBoard::GetHzBySemitone(m_key + m_fine);

View File

@@ -7,7 +7,7 @@
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include "raygui.h"
#include "raysan/raygui.h"
#pragma clang diagnostic pop
Renderer::Renderer(/* args */) {

View File

@@ -1,7 +1,57 @@
#include "Application.h"
#include <string_view>
#include <vector>
#include <string>
#include <iostream>
inline bool file_exists(const std::string& name) {
if (FILE *file = fopen(name.c_str(), "r")) {
fclose(file);
return true;
} else {
return false;
}
}
[[noreturn]] void print_help(char* const executable) {
std::cout << executable << " [options]\n" <<
"Options:\n" <<
" -h | --help Print this help\n" <<
" -p | --patch Path to a json file with a patch to apply\n" <<
" -v | --version Print a program version" << std::endl;
std::exit(0);
}
int main(int argc, char* argv[]) {
if (argc > 32) {
throw std::runtime_error("Too many input parameters!");
}
std::string patch_file_path;
for (int i = 0; i < argc; i++) {
auto arg = std::string(argv[i]);
if (arg == "-p" || arg == "--patch") {
patch_file_path = std::string(argv[i+1]);
if (patch_file_path.empty()) {
std::cerr << "no file path provided\n";
print_help(argv[0]);
}
else if (!file_exists(patch_file_path)) {
std::cerr << patch_file_path << ": no such file\n";
print_help(argv[0]);
}
}
else if (arg == "-h" || arg == "--help") {
print_help(argv[0]);
}
}
int main() {
Application* app = new Application();
if (!patch_file_path.empty()) {
app->ParsePatch(patch_file_path);
}
app->Run();
delete app;

View File

@@ -7,7 +7,7 @@
Synth::Synth(/* args */) {
m_lfo = new LFO();
m_lfo->SetFreq(5.0);
m_lfo->SetFreq(2.0);
AddOscillator();
AddOscillator();
AddEffect(new ADSR());
@@ -79,7 +79,7 @@ void Synth::ApplyFilterLfo() {
float dt = m_lfo->Process();
Filter* filter = (Filter*)m_effects[1];
float freq = filter->GetFreq();
filter->SetParameters(freq + dt, filter->GetRes(), filter->GetPeakGain());
filter->SetParameters(freq + dt*0.5f, filter->GetRes(), filter->GetPeakGain());
}
void Synth::Process() {