v0.9.5 beta — full feature build ready for distribution

Core additions since initial commit:
- Platform-split MIDI (midi_linux.c / midi_windows.c)
- Patch system: save/load/scan, subdirectory navigation, favourites
- Config system: last MIDI device and CC mappings persisted to disk
- Custom embedded pixel font and sprite sheet (no loose asset files at runtime)
- Window icon embedded at runtime (SetWindowIcon) and in Windows .exe (windres)
- chdirToExeDir() in platform.c so double-click launch finds patches/ correctly
- About screen accessible from Master panel

UI polish:
- TITLE_BAR_H constant (20 px) — sprite buttons now fit inside title bars
- All title bar text, button overlay text, and close/active labels vertically centred
- Full-screen dim overlay computed from camera transform (no more partial coverage)
- Patch browser: folder navigation, breadcrumb title, 256-slot limit lifted

Build:
- Makefile auto-discovers sources; embeds sprites/font/icon via xxd rules
- Windows cross-compile: make PLATFORM=windows (mingw-w64 + windres)
- windows.h isolated in platform.c to avoid Rectangle/CloseWindow conflicts with raylib.h
- WIN_RES uses lazy = assignment so OBJ_DIR expands correctly for windres output path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Anachronaut
2026-07-07 19:18:34 -04:00
parent 801ea22d3e
commit 75e0894ff8
70 changed files with 5910 additions and 237 deletions

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
bin/
build/
.exe
*.old
config/
untracked/
reference/
resume.sh
patches/favorites.txt

BIN
assets/NPNGear.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/NPNGear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/myFont.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

BIN
assets/sprites.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

1
icon.rc Normal file
View File

@@ -0,0 +1 @@
IDI_ICON1 ICON "assets/NPNGear.ico"

20
include/config.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef CONFIG_H
#define CONFIG_H
#define CONFIG_DIR "config"
#define CONFIG_NAME_LEN 128
typedef struct {
int cc;
int controlId;
float min;
float max;
} ConfigCcEntry;
void configSanitizeName(const char *in, char *out, int maxLen);
int configSaveLastDevice(const char *deviceName);
int configLoadLastDevice(char *out, int maxLen);
int configSaveCcMappings(const char *deviceName, ConfigCcEntry *entries, int count);
int configLoadCcMappings(const char *deviceName, ConfigCcEntry *entries, int maxCount);
#endif

7
include/font_data.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef FONT_DATA_H
#define FONT_DATA_H
extern unsigned char font_png[];
extern unsigned int font_png_len;
#endif

7
include/icon_data.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef ICON_DATA_H
#define ICON_DATA_H
extern unsigned char icon_png[];
extern unsigned int icon_png_len;
#endif

View File

@@ -1,20 +1,52 @@
#ifndef MIDI_H
#define MIDI_H
#define _POSIX_C_SOURCE 200809L
#include <alsa/asoundlib.h>
#ifndef _WIN32
# define _POSIX_C_SOURCE 200809L
# include <alsa/asoundlib.h>
#endif
#include <stdatomic.h>
#include "synth.h"
#define MIDI_MAX_INPUTS 16
typedef struct {
int active;
float *valuePtr; // direct pointer into Synth for CC to write
float min, max; // CC 0 → min, CC 127 → max
int controlId; // stable UI control ID, used for persistence
} CcMapping;
typedef struct {
int client;
int port;
char clientName[64];
char portName[64];
} MidiInputInfo;
typedef struct {
#ifdef _WIN32
void *hMidiIn; // HMIDIIN; kept opaque to avoid including windows.h here
#else
snd_seq_t *seq;
int port;
int client;
Synth *synth; // pointer to the synth we'll drive with MIDI events
#endif
Synth *synth;
int connectedClient; // WinMM device index on Windows, ALSA client on Linux; -1 if not connected
int connectedPort; // always 0 on Windows, ALSA port on Linux
MidiInputInfo inputs[MIDI_MAX_INPUTS];
int inputCount;
atomic_int midiLearnMode; // 1 while waiting for CC wiggle
atomic_int midiLearnCC; // -1 or the CC number received
CcMapping ccMappings[128];
} MidiState;
int midiInit(MidiState *m, Synth *synth);
void midiListInputs(MidiState *m);
void midiConnect(MidiState *m, int srcClient, int srcPort);
void midiScanInputs(MidiState *m);
void midiDevConnect(MidiState *m, int srcClient, int srcPort);
void midiDevDisconnect(MidiState *m);
void midiClose(MidiState *m);
void *midiThread(void *arg);

19
include/patch.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef PATCH_H
#define PATCH_H
#include "synth.h"
#define PATCH_NAME_LEN 64
#define PATCH_MAX_FILES 256
#define PATCH_MAX_DIRS 64
int patchSave(Synth *s, const char *path);
int patchLoad(Synth *s, const char *path);
int patchScanFiles(char (*files)[PATCH_NAME_LEN], int maxFiles);
int patchScanDir(const char *relPath,
char (*files)[PATCH_NAME_LEN], int maxFiles,
char (*dirs)[PATCH_NAME_LEN], int maxDirs, int *outDirCount);
int patchLoadFavs(char (*favs)[PATCH_NAME_LEN], int maxFavs);
int patchSaveFavs(char (*favs)[PATCH_NAME_LEN], int favCount);
#endif

6
include/platform.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef PLATFORM_H
#define PLATFORM_H
void chdirToExeDir(void);
#endif

7
include/sprites_data.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef SPRITES_DATA_H
#define SPRITES_DATA_H
extern unsigned char sprites_png[];
extern unsigned int sprites_png_len;
#endif

View File

@@ -3,7 +3,10 @@
#include <stdint.h>
#define VOICE_COUNT 16
#define VOICE_COUNT 8
#define OSC_COUNT 2
#define LFO_COUNT 2
#define OSC_MAX_GAIN 4.0f
typedef enum {
WAVE_SINE,
@@ -15,32 +18,124 @@ typedef enum {
WAVE_COUNT // handy for the modulo wrap on waveform switching
} Waveform;
// Envelope structures:
typedef enum {
ENV_IDLE,
ENV_ATTACK,
ENV_DECAY,
ENV_SUSTAIN,
ENV_RELEASE
} EnvStage;
typedef enum {
MOD_SOURCE_NONE = 0,
MOD_SOURCE_AMP_ENV = 1,
MOD_SOURCE_MOD_ENV = 2,
MOD_SOURCE_LFO = 3,
MOD_SOURCE_LFO2 = 4
} ModSource;
typedef struct {
float phase;
float freqHz;
float amp;
float targetAmp;
int active;
int midiNote;
EnvStage stage;
float value; // current output value, 0.0 to 1.0
float attackSec;
float decaySec;
float sustainLevel;
float releaseSec;
} Envelope;
typedef struct {
float phase;
float rate; // Hz
Waveform waveform;
int active;
float noiseHeld;
float noisePhase;
} LFO;
typedef enum {
FILTER_LOWPASS,
FILTER_HIGHPASS,
FILTER_BANDPASS,
FILTER_COUNT
} FilterType;
typedef struct {
float cutoff; // Hz
float resonance; // 0.0 (flat) to 0.99 (near self-oscillation)
FilterType type;
int active;
float low, band; // TPT integrator states s1, s2
int modRouting;
float modDepth; // Hz
int resModRouting;
float resModDepth; // resonance units (-0.99..0.99)
} Filter;
typedef struct {
float phase;
float dutyCycle;
Waveform waveform;
float detune; // cents, 0 = no detune
float noiseHeld; // last drawn random value for clocked noise
float noisePhase; // tracks when to draw a new noise value
float gain;
int active; // whether this oscillator contributes to output
int octave; // transposition in octaves, -2 to +2
// Modulation routing: one source per destination by design.
// Each parameter (pwm, detune, gain) has exactly one mod source and one depth.
int modRouting[3]; // 0=off, 1=env0, 2=env1, 3=lfo0, 4=lfo1
float modDepth[3]; // Depth of modulation parameter
} Oscillator;
typedef struct {
Oscillator oscillators[OSC_COUNT];
float freqHz;
int active;
int midiNote;
Envelope ampEnv;
Envelope modEnv;
Filter filter;
} Voice;
typedef struct {
float sampleRate;
float attackSec;
float releaseSec;
float dutyCycle;
Waveform waveform;
Voice voices[VOICE_COUNT];
float pitchBend;
float pitchBendRange;
int lastStolenVoice;
float pitchBend; // -1.0 to +1.0, normalized from raw MIDI value
float pitchBendRange; // semitones, e.g. 2.0f
Voice voices[VOICE_COUNT];
float volume; // 0.0 to 1.0, master output level
LFO lfos[LFO_COUNT];
} Synth;
// Envelope functions:
void envelopeInit(Envelope *e, float attackSec, float decaySec, float sustainLevel, float releaseSec);
void envelopeNoteOn(Envelope *e);
void envelopeNoteOff(Envelope *e);
float envelopeTick(Envelope *e, float sampleRate);
// Oscillator functions:
void oscillatorInit(Oscillator *o, Waveform waveform, float dutyCycle, float detune, float gain);
float oscillatorTick(Oscillator *o, float freqHz, float bendMultiplier, float sampleRate,
float dutyCycle, float detune, float gain);
// Synth functions:
void synthInit(Synth *s, float sampleRate);
void synthResetPatch(Synth *s);
void synthNoteOn(Synth *s, int midiNote);
void synthNoteOff(Synth *s, int midiNote);
void synthFillBuffer(Synth *s, int16_t *out, int frames);
float waveformSample(Waveform w, float phase, float dutyCycle);
void synthSyncVoices(Synth *s);
// LFO functions:
float lfoTick(LFO *l, float sampleRate);
// Filter functions:
float filterTick(Filter *f, float input, float cutoff, float resonance, float sampleRate);
const char *filterTypeName(FilterType t);
// Waveform functions:
float waveformSample(Waveform w, float phase, float dutyCycle, float noiseHeld);
const char *waveformName(Waveform w);
#endif

110
include/ui.h Normal file
View File

@@ -0,0 +1,110 @@
#ifndef UI_H
#define UI_H
#include "raylib.h"
#include "synth.h"
#include "midi.h"
#include "patch.h"
#include "config.h"
typedef struct {
int id;
float *valuePtr;
float min;
float max;
} UIControlEntry;
// Sprite indices
typedef enum {
SPRITE_WAVE_SINE = 0,
SPRITE_WAVE_TRIANGLE,
SPRITE_WAVE_SAW,
SPRITE_WAVE_RAMP,
SPRITE_WAVE_PULSE,
SPRITE_WAVE_NOISE,
SPRITE_BTN_RED,
SPRITE_BTN_GREEN,
SPRITE_SLIDER,
SPRITE_KNOB
} SpriteIndex;
// UI state that needs to persist between frames
typedef struct {
Texture2D sprites;
Font font;
MidiState *midi;
Camera2D *camera;
// About menu state
int aboutMenuOpen;
// MIDI menu state
int midiMenuOpen;
int midiMenuSelected; // -1 if none
// Knob drag state
int draggingKnob; // -1 if none
Vector2 dragStart;
float dragStartValue;
// Slider drag state
int draggingSlider; // -1 if none
// MIDI learn state
int midiLearnActive; // 0=off 1=click a control 2=wiggle CC
int midiLearnTargetId; // id of selected control (-1 if none)
float *midiLearnValuePtr;
float midiLearnMin;
float midiLearnMax;
// Patch browser state
int patchMenuOpen;
int focusedTextInput; // -1 if none
int patchConfirmOverwrite;
int patchConfirmClear;
char patchSaveName[PATCH_NAME_LEN];
char patchCurrentName[PATCH_NAME_LEN];
int patchFileCount;
char patchFiles[PATCH_MAX_FILES][PATCH_NAME_LEN];
int patchScrollOffset;
int patchShowFavsOnly;
char patchFavs[PATCH_MAX_FILES][PATCH_NAME_LEN];
int patchFavCount;
char patchCurrentDir[256];
char patchSubDirs[PATCH_MAX_DIRS][PATCH_NAME_LEN];
int patchSubDirCount;
// Control registry — built lazily by uiKnob/uiSlider for CC mapping persistence
UIControlEntry controlRegistry[128];
int controlRegistryCount;
// CC mappings loaded from file but not yet resolved (registry not yet populated)
ConfigCcEntry pendingMappings[128];
int pendingCount;
} UIState;
// Lifecycle
void uiInit(UIState *ui, MidiState *midi, Camera2D *camera);
void uiClose(UIState *ui);
// Primitives
float uiKnob(UIState *ui, int id, float x, float y, float *ptr, float min, float max, const char *label);
float uiSlider(UIState *ui, int id, float x, float y, float width, float *ptr, float min, float max, const char *label);
int uiWaveformSelector(UIState *ui, float x, float y, int currentWaveform);
void uiADSRShape(float x, float y, float width, float height, float attack, float decay, float sustain, float release, Color color);
void uiVoiceMeter(UIState *ui, float x, float y, Voice *voices, int voiceCount);
// Panels
void uiOscillatorPanel(UIState *ui, int baseId, float x, float y, float width, float height, Oscillator *osc, const char *title);
void uiEnvelopePanel(UIState *ui, int baseId, float x, float y, float width, float height, Envelope *env, const char *title);
void uiLfoPanel(UIState *ui, int baseId, float x, float y, float width, float height, LFO *lfo, const char *title);
void uiFilterPanel(UIState *ui, float x, float y, float width, float height, Filter *filter, const char *title);
void uiMasterPanel(UIState *ui, float x, float y, float width, float height, Synth *s);
void uiMidiMenu(UIState *ui, float x, float y, float width, MidiState *midi);
void uiPatchMenu(UIState *ui, float x, float y, float width, Synth *s);
void uiAboutMenu(UIState *ui, float x, float y, float width);
void uiLoadCcMappingsForDevice(UIState *ui, const char *deviceName);
// Window helpers
void recomputeViewPort(Camera2D* camera, int x_logical_resolution, int y_logical_resolution, int border_width);
#endif

View File

@@ -1,12 +1,38 @@
# Recursive Directory Digesting Makefile V1.0
# === Project Settings ===
PROJECT := soundThing # Change this to your project name
CC := gcc
CFLAGS := -Wall -Wextra -std=c11 -O2
# Preprocessor flags (deps only here)
CPPFLAGS := -MMD -MP
# Add linker flags
LDFLAGS = -lraylib -lm -ldl -lpthread -lGL -lrt -lX11 -lasound #here (e.g. -lm)
# === Platform Selection ===
# Build for Linux (default): make
# Cross-compile for Windows: make PLATFORM=windows
PLATFORM ?= linux
ifeq ($(PLATFORM),windows)
CC := x86_64-w64-mingw32-gcc
BIN_NAME := $(PROJECT).exe
# Point RAYLIB_WIN at the extracted raylib-*_win64_mingw-w64 directory, e.g.:
# make PLATFORM=windows RAYLIB_WIN=/opt/raylib-win64
# RAYLIB_WIN ?=
RAYLIB_WIN = /home/qwhilla/projects/externalLibraries/win64/raylib
ifneq ($(RAYLIB_WIN),)
CPPFLAGS += -I$(RAYLIB_WIN)/include
LDFLAGS := -L$(RAYLIB_WIN)/lib -lraylib -lm -lpthread -lopengl32 -lwinmm -lgdi32 -lws2_32 -static
else
LDFLAGS := -lraylib -lm -lpthread -lopengl32 -lwinmm -lgdi32 -lws2_32 -static
endif
MIDI_SRC := midi_windows.c
WINDRES := x86_64-w64-mingw32-windres
WIN_RES = $(OBJ_DIR)/icon_res.o
else
CC := gcc
BIN_NAME := $(PROJECT)
LDFLAGS := -lraylib -lm -ldl -lpthread -lGL -lrt -lX11 -lasound
MIDI_SRC := midi_linux.c
WIN_RES :=
endif
# === Directory Structure ===
SRC_DIR := source
@@ -18,25 +44,31 @@ INC_DIR := include
INC_SUBDIRS := $(shell find $(INC_DIR) -type d)
CPPFLAGS += $(addprefix -I,$(INC_SUBDIRS))
# === Discover sources recursively ===
SRC := $(shell find $(SRC_DIR) -type f -name '*.c')
# === Discover sources (exclude platform-split MIDI files, add the right one) ===
SRC_AUTO := $(shell find $(SRC_DIR) -type f -name '*.c' ! -name 'midi_*.c' ! -name '*.old')
SRC := $(SRC_AUTO) $(SRC_DIR)/$(MIDI_SRC)
# Map source paths to object paths (mirror folders under build/)
OBJ := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRC))
DEP := $(OBJ:.o=.d)
BIN := $(BIN_DIR)/$(PROJECT)
BIN := $(BIN_DIR)/$(BIN_NAME)
# === Embedded assets ===
SPRITES_DATA := $(SRC_DIR)/sprites_data.c
FONT_DATA := $(SRC_DIR)/font_data.c
ICON_DATA := $(SRC_DIR)/icon_data.c
# === Rules ===
.PHONY: all clean run dirs
all: dirs $(BIN)
all: dirs $(SPRITES_DATA) $(FONT_DATA) $(ICON_DATA) $(BIN)
dirs:
@mkdir -p $(BIN_DIR)
@mkdir -p $(sort $(dir $(OBJ))) # create object subdirs that mirror source/
# Link objects into final executable
$(BIN): $(OBJ)
$(CC) $(OBJ) -o $@ $(LDFLAGS)
$(BIN): $(OBJ) $(WIN_RES)
$(CC) $(OBJ) $(WIN_RES) -o $@ $(LDFLAGS)
@echo "Linked -> $@"
# Compile each .c into a .o, with auto header deps
@@ -56,3 +88,33 @@ clean:
# Include auto-generated dependency files (if present)
-include $(DEP)
# Regenerate embedded sprite data when the PNG changes
$(SPRITES_DATA): assets/sprites.png
xxd -i $< | sed 's/assets_sprites_png/sprites_png/g' > $@
@echo "Generated -> $@"
# Regenerate embedded font data when the PNG changes
$(FONT_DATA): assets/myFont.png
xxd -i $< | sed 's/assets_myFont_png/font_png/g' > $@
@echo "Generated -> $@"
# Regenerate embedded icon data when the PNG changes
$(ICON_DATA): assets/NPNGear.png
xxd -i $< | sed 's/assets_NPNGear_png/icon_png/g' > $@
@echo "Generated -> $@"
# Generate .ico from PNG using pure Python3 stdlib (no Pillow required)
assets/NPNGear.ico: assets/NPNGear.png
python3 -c "import struct; d=open('$<','rb').read(); \
hdr=struct.pack('<HHH',0,1,1); \
ent=struct.pack('<BBBBHHII',128,128,0,0,1,32,len(d),22); \
open('$@','wb').write(hdr+ent+d)"
@echo "Generated -> $@"
# Compile Windows resource (icon.rc -> icon_res.o), only when cross-compiling
ifeq ($(PLATFORM),windows)
$(WIN_RES): icon.rc assets/NPNGear.ico
$(WINDRES) $< -o $@
@echo "Compiled resource -> $@"
endif

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 1,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 7.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 5.000000,
"osc1_gain": 2.200000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 4,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 5.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 1.200000,
"ampEnv_decay": 0.300000,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.110000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.073000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 8000.000000,
"filter_resonance": 0.100000,
"filter_type": 1,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.650000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -0.800000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": -2,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 4,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.900000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.800000,
"osc1_gain": 3.500000,
"osc1_active": 1,
"osc1_octave": -2,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 1.800000,
"ampEnv_decay": 0.300000,
"ampEnv_sustain": 0.880000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.060000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.095000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 500.000000,
"filter_resonance": 0.350000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 3,
"filter_modDepth": 700.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 1,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 2.800000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 5.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.700000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 1.600000,
"ampEnv_decay": 0.300000,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.180000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.085000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 2200.000000,
"filter_resonance": 0.200000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 4,
"filter_modDepth": 800.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.620000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 5,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.400000,
"osc1_active": 1,
"osc1_octave": -1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 2.000000,
"ampEnv_decay": 0.300000,
"ampEnv_sustain": 0.800000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.150000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.220000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 1800.000000,
"filter_resonance": 0.350000,
"filter_type": 2,
"filter_active": 1,
"filter_modRouting": 3,
"filter_modDepth": 1200.000000,
"filter_resModRouting": 4,
"filter_resModDepth": 0.150000,
"master_volume": 0.600000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 5,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 0,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 2.000000,
"ampEnv_decay": 0.500000,
"ampEnv_sustain": 0.800000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.080000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.130000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 900.000000,
"filter_resonance": 0.150000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 3,
"filter_modDepth": 1800.000000,
"filter_resModRouting": 4,
"filter_resModDepth": 0.120000,
"master_volume": 0.650000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -2.000000,
"osc0_gain": 3.200000,
"osc0_active": 1,
"osc0_octave": -2,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 2.000000,
"osc1_gain": 2.800000,
"osc1_active": 1,
"osc1_octave": -2,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 4,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 1.000000,
"ampEnv_attack": 2.000000,
"ampEnv_decay": 0.500000,
"ampEnv_sustain": 0.850000,
"ampEnv_release": 2.000000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.065000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.042000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 380.000000,
"filter_resonance": 0.420000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 3,
"filter_modDepth": 550.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.720000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 1,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.500000,
"osc0_active": 1,
"osc0_octave": -1,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 0,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.700000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.080000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 20000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.800000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 14.000000,
"osc1_gain": 0.500000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 1.400000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.300000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.060000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.030000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 20000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 0,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.050000,
"ampEnv_sustain": 0.850000,
"ampEnv_release": 0.040000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 20000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.250000,
"osc0_detune": -4.000000,
"osc0_gain": 2.800000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 3,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.100000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.250000,
"osc1_detune": 4.000000,
"osc1_gain": 2.800000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.120000,
"ampEnv_decay": 0.100000,
"ampEnv_sustain": 0.800000,
"ampEnv_release": 0.200000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.350000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 20000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.125000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.125000,
"osc1_detune": 0.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.030000,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 0.030000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 20000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -3.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.300000,
"osc1_detune": 3.000000,
"osc1_gain": 2.500000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 4,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.250000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.080000,
"ampEnv_sustain": 0.800000,
"ampEnv_release": 0.060000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.180000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.080000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 6.000000,
"lfo1_waveform": 1,
"lfo1_active": 1,
"filter_cutoff": 1200.000000,
"filter_resonance": 0.550000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 7000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.153236,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 1,
"osc0_modRouting1": 0,
"osc0_modRouting2": 3,
"osc0_modDepth0": 0.290788,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": -0.833591,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 0,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.005000,
"ampEnv_decay": 0.100000,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 0.500000,
"modEnv_attack": 0.005000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.100000,
"lfo0_rate": 2.598532,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 8000.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 0,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.362205,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": -1,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 0,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.500000,
"ampEnv_sustain": 0.300000,
"ampEnv_release": 0.100000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.120000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.050000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 700.000000,
"filter_resonance": 0.700000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 9000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.800000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.200000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 1.500000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.900000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.250000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.050000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.025000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 5000.000000,
"filter_resonance": 0.150000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 5000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -3.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 3.000000,
"osc1_gain": 2.500000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.012000,
"ampEnv_decay": 0.250000,
"ampEnv_sustain": 0.650000,
"ampEnv_release": 0.220000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.150000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.100000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 700.000000,
"filter_resonance": 0.400000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 7500.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -3.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 12.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 3.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.280000,
"ampEnv_decay": 0.150000,
"ampEnv_sustain": 0.850000,
"ampEnv_release": 0.600000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.200000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.100000,
"lfo0_rate": 5.200000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 2500.000000,
"filter_resonance": 0.150000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 1500.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.550000,
"osc0_detune": -4.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 3,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.120000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.450000,
"osc1_detune": 4.000000,
"osc1_gain": 2.500000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.380000,
"ampEnv_decay": 0.250000,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 0.900000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.280000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 1600.000000,
"filter_resonance": 0.280000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 1800.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.650000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 4.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.008000,
"ampEnv_decay": 0.150000,
"ampEnv_sustain": 0.720000,
"ampEnv_release": 0.200000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.300000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.150000,
"lfo0_rate": 5.500000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 2200.000000,
"filter_resonance": 0.500000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 6000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": -2,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 1.800000,
"osc1_active": 1,
"osc1_octave": -1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.006000,
"ampEnv_decay": 0.200000,
"ampEnv_sustain": 0.650000,
"ampEnv_release": 0.180000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.100000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.080000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 500.000000,
"filter_resonance": 0.300000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 3500.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.800000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 6.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.233685,
"osc1_active": 1,
"osc1_octave": 2,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.090000,
"ampEnv_decay": 0.050000,
"ampEnv_sustain": 0.850000,
"ampEnv_release": 0.280000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 5.200000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 7000.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 1.000000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 14.000000,
"osc1_gain": 0.500000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.800000,
"ampEnv_attack": 0.003000,
"ampEnv_decay": 3.000000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 1.000000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.180000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.100000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 14000.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 0.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -8.000000,
"osc0_gain": 2.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 3,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.280000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 8.000000,
"osc1_gain": 2.500000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 4,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.280000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.420000,
"ampEnv_decay": 0.100000,
"ampEnv_sustain": 0.880000,
"ampEnv_release": 1.300000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.400000,
"lfo0_rate": 0.290000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 0.370000,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 4200.000000,
"filter_resonance": 0.080000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 2800.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.720000,
"master_pitchBendRange": 2.000000
}

50
patches/Classic/Oboe.json Normal file
View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.250000,
"osc0_detune": 0.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 5.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.200000,
"osc1_detune": 2.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.055000,
"ampEnv_decay": 0.030000,
"ampEnv_sustain": 0.920000,
"ampEnv_release": 0.150000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 5.000000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 2500.000000,
"filter_resonance": 0.400000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 0.600000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 8.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.060000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.150000,
"ampEnv_attack": 0.040000,
"ampEnv_decay": 0.080000,
"ampEnv_sustain": 0.850000,
"ampEnv_release": 0.220000,
"modEnv_attack": 0.010000,
"modEnv_decay": 0.280000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.060000,
"lfo0_rate": 5.500000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 2.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 2200.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 1800.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.650000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 1,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 7.000000,
"osc1_gain": 1.000000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.000000,
"ampEnv_attack": 0.003000,
"ampEnv_decay": 2.000000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.600000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.120000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.060000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 8000.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 4000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.500000,
"ampEnv_attack": 0.012000,
"ampEnv_decay": 0.050000,
"ampEnv_sustain": 0.920000,
"ampEnv_release": 0.120000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.055000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.025000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 4500.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 7.000000,
"osc1_gain": 0.400000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.200000,
"ampEnv_attack": 0.002000,
"ampEnv_decay": 1.800000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.500000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.100000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.050000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 3500.000000,
"filter_resonance": 0.100000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 4000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -5.000000,
"osc0_gain": 2.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 8.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 5.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.700000,
"ampEnv_decay": 0.300000,
"ampEnv_sustain": 0.750000,
"ampEnv_release": 1.200000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 0.450000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 1000.000000,
"filter_resonance": 0.100000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 2500.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 4.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 4,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": -9.448853,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.079701,
"ampEnv_decay": 0.913929,
"ampEnv_sustain": 0.700000,
"ampEnv_release": 0.567646,
"modEnv_attack": 0.005000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.244094,
"modEnv_release": 0.488945,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 2.528425,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 2851.811279,
"filter_resonance": 0.226063,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 1,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.291339,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -3.345787,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 2,
"osc0_modRouting1": 1,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.114713,
"osc0_modDepth1": 11.471191,
"osc0_modDepth2": -2.256021,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 4.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 2,
"osc1_modRouting1": 3,
"osc1_modRouting2": 0,
"osc1_modDepth0": -0.095594,
"osc1_modDepth1": 17.206787,
"osc1_modDepth2": -1.472151,
"ampEnv_attack": 0.169107,
"ampEnv_decay": 0.679732,
"ampEnv_sustain": 1.000000,
"ampEnv_release": 0.601745,
"modEnv_attack": 0.179308,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.158102,
"lfo0_rate": 1.668824,
"lfo0_waveform": 1,
"lfo0_active": 1,
"lfo1_rate": 0.010000,
"lfo1_waveform": 1,
"lfo1_active": 1,
"filter_cutoff": 20.000000,
"filter_resonance": 0.000000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 7551.934570,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.906796,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.384412,
"osc1_detune": -1.938599,
"osc1_gain": 4.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 3,
"osc1_modRouting1": 4,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.382870,
"osc1_modDepth1": -47.244019,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.095441,
"ampEnv_decay": 0.929669,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.536165,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.221362,
"modEnv_sustain": 0.251969,
"modEnv_release": 0.473205,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 2.843228,
"lfo1_waveform": 0,
"lfo1_active": 1,
"filter_cutoff": 2537.165283,
"filter_resonance": 0.233858,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": -6688.119629,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.307087,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": -3.345787,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 1,
"osc0_modRouting2": 4,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 11.471191,
"osc0_modDepth2": -2.256021,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 4.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 3,
"osc1_modRouting2": 4,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 17.206787,
"osc1_modDepth2": -1.472151,
"ampEnv_attack": 0.050191,
"ampEnv_decay": 0.810141,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.500000,
"modEnv_attack": 0.005000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.100000,
"lfo0_rate": 1.668824,
"lfo0_waveform": 1,
"lfo0_active": 1,
"lfo1_rate": 3.102018,
"lfo1_waveform": 1,
"lfo1_active": 1,
"filter_cutoff": 2789.458252,
"filter_resonance": 0.274451,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": -286.782837,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 1.000000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 2,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 2,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 4.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.008000,
"ampEnv_decay": 0.150000,
"ampEnv_sustain": 0.720000,
"ampEnv_release": 0.200000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.300000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.150000,
"lfo0_rate": 5.500000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 2200.000000,
"filter_resonance": 0.500000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 6000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 1,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 2.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.300000,
"osc1_active": 1,
"osc1_octave": 2,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.000000,
"ampEnv_attack": 0.003000,
"ampEnv_decay": 0.080000,
"ampEnv_sustain": 0.800000,
"ampEnv_release": 0.250000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.090000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.050000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 5000.000000,
"filter_resonance": 0.150000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 4500.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.650000,
"master_pitchBendRange": 1.000000
}

50
patches/Keys/Farfisa.json Normal file
View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.250000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.250000,
"osc1_detune": 0.000000,
"osc1_gain": 1.800000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 0,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 0.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.001000,
"ampEnv_sustain": 1.000000,
"ampEnv_release": 0.015000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 6000.000000,
"filter_resonance": 0.100000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.720000,
"master_pitchBendRange": 2.000000
}

50
patches/Keys/Hammond.json Normal file
View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 4,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 8.000000,
"osc0_modDepth2": 0.700000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 2.000000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 3,
"osc1_modRouting2": 4,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 8.000000,
"osc1_modDepth2": 0.500000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.001000,
"ampEnv_sustain": 1.000000,
"ampEnv_release": 0.020000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.500000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.200000,
"lfo0_rate": 5.500000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 5.500000,
"lfo1_waveform": 1,
"lfo1_active": 1,
"filter_cutoff": 8000.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.700000,
"master_pitchBendRange": 2.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 4,
"osc0_dutyCycle": 0.700000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 4,
"osc1_dutyCycle": 0.700000,
"osc1_detune": 3.000000,
"osc1_gain": 1.500000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 1.000000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 0.700000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.060000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.060000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.030000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 9000.000000,
"filter_resonance": 0.120000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 5000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 0.000000
}

50
patches/Keys/Piano.json Normal file
View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 1,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 3.500000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 1,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 7.000000,
"osc1_gain": 1.000000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.000000,
"ampEnv_attack": 0.003000,
"ampEnv_decay": 2.000000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.600000,
"modEnv_attack": 0.000000,
"modEnv_decay": 0.120000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.060000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 8000.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 2,
"filter_modDepth": 4000.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 0,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 0.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 5,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 0.000000,
"osc1_gain": 0.000000,
"osc1_active": 1,
"osc1_octave": 0,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 2.500000,
"ampEnv_attack": 0.012000,
"ampEnv_decay": 0.050000,
"ampEnv_sustain": 0.920000,
"ampEnv_release": 0.120000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.055000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.025000,
"lfo0_rate": 1.000000,
"lfo0_waveform": 0,
"lfo0_active": 0,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 4500.000000,
"filter_resonance": 0.050000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.750000,
"master_pitchBendRange": 1.000000
}

View File

@@ -0,0 +1,50 @@
{
"osc0_waveform": 0,
"osc0_dutyCycle": 0.500000,
"osc0_detune": 0.000000,
"osc0_gain": 4.000000,
"osc0_active": 1,
"osc0_octave": 0,
"osc0_modRouting0": 0,
"osc0_modRouting1": 3,
"osc0_modRouting2": 0,
"osc0_modDepth0": 0.000000,
"osc0_modDepth1": 10.000000,
"osc0_modDepth2": 0.000000,
"osc1_waveform": 0,
"osc1_dutyCycle": 0.500000,
"osc1_detune": 2.000000,
"osc1_gain": 0.300000,
"osc1_active": 1,
"osc1_octave": 1,
"osc1_modRouting0": 0,
"osc1_modRouting1": 0,
"osc1_modRouting2": 2,
"osc1_modDepth0": 0.000000,
"osc1_modDepth1": 0.000000,
"osc1_modDepth2": 1.500000,
"ampEnv_attack": 0.001000,
"ampEnv_decay": 2.000000,
"ampEnv_sustain": 0.000000,
"ampEnv_release": 0.600000,
"modEnv_attack": 0.001000,
"modEnv_decay": 0.080000,
"modEnv_sustain": 0.000000,
"modEnv_release": 0.040000,
"lfo0_rate": 4.500000,
"lfo0_waveform": 0,
"lfo0_active": 1,
"lfo1_rate": 1.000000,
"lfo1_waveform": 0,
"lfo1_active": 0,
"filter_cutoff": 10000.000000,
"filter_resonance": 0.100000,
"filter_type": 0,
"filter_active": 1,
"filter_modRouting": 0,
"filter_modDepth": 0.000000,
"filter_resModRouting": 0,
"filter_resModDepth": 0.000000,
"master_volume": 0.800000,
"master_pitchBendRange": 2.000000
}

91
source/config.c Normal file
View File

@@ -0,0 +1,91 @@
#define _POSIX_C_SOURCE 200809L
#include "config.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
# include <direct.h>
# define MAKE_DIR(p) _mkdir(p)
#else
# include <sys/stat.h>
# define MAKE_DIR(p) mkdir(p, 0755)
#endif
void configSanitizeName(const char *in, char *out, int maxLen)
{
int i = 0;
for (; in[i] && i < maxLen - 1; i++) {
char c = in[i];
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || c == '_' || c == '-')
out[i] = c;
else
out[i] = '_';
}
out[i] = '\0';
}
int configSaveLastDevice(const char *deviceName)
{
MAKE_DIR(CONFIG_DIR);
FILE *f = fopen(CONFIG_DIR "/last_device.txt", "w");
if (!f) return 0;
fprintf(f, "%s\n", deviceName);
fclose(f);
return 1;
}
int configLoadLastDevice(char *out, int maxLen)
{
FILE *f = fopen(CONFIG_DIR "/last_device.txt", "r");
if (!f) return 0;
int ok = (fgets(out, maxLen, f) != NULL);
fclose(f);
if (!ok) return 0;
int len = (int)strlen(out);
if (len > 0 && out[len - 1] == '\n') out[len - 1] = '\0';
return out[0] != '\0';
}
int configSaveCcMappings(const char *deviceName, ConfigCcEntry *entries, int count)
{
MAKE_DIR(CONFIG_DIR);
char safe[CONFIG_NAME_LEN];
configSanitizeName(deviceName, safe, sizeof(safe));
char path[CONFIG_NAME_LEN + 32];
snprintf(path, sizeof(path), CONFIG_DIR "/cc_%s.cfg", safe);
FILE *f = fopen(path, "w");
if (!f) return 0;
for (int i = 0; i < count; i++)
fprintf(f, "%d %d %f %f\n",
entries[i].cc, entries[i].controlId,
entries[i].min, entries[i].max);
fclose(f);
return 1;
}
int configLoadCcMappings(const char *deviceName, ConfigCcEntry *entries, int maxCount)
{
char safe[CONFIG_NAME_LEN];
configSanitizeName(deviceName, safe, sizeof(safe));
char path[CONFIG_NAME_LEN + 32];
snprintf(path, sizeof(path), CONFIG_DIR "/cc_%s.cfg", safe);
FILE *f = fopen(path, "r");
if (!f) return 0;
int count = 0;
while (count < maxCount) {
int cc, id;
float mn, mx;
if (fscanf(f, "%d %d %f %f\n", &cc, &id, &mn, &mx) != 4) break;
if (cc >= 0 && cc < 128) {
entries[count].cc = cc;
entries[count].controlId = id;
entries[count].min = mn;
entries[count].max = mx;
count++;
}
}
fclose(f);
return count;
}

165
source/font_data.c Normal file
View File

@@ -0,0 +1,165 @@
unsigned char font_png[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x70,
0x08, 0x06, 0x00, 0x00, 0x00, 0xd6, 0xac, 0x78, 0xd2, 0x00, 0x00, 0x00,
0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
0x07, 0x51, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x9c, 0xdd, 0x76,
0xe3, 0x30, 0x08, 0x84, 0x93, 0x9e, 0xbe, 0xff, 0x2b, 0x7b, 0x6f, 0x56,
0x3d, 0x94, 0x0c, 0x30, 0x48, 0x72, 0x12, 0x37, 0xf3, 0x5d, 0x35, 0x96,
0xf8, 0x91, 0x04, 0x08, 0xa7, 0xdd, 0xbd, 0xdd, 0xc4, 0x47, 0x73, 0x67,
0x27, 0x1e, 0xc7, 0x71, 0xdc, 0x6e, 0xb7, 0xdb, 0xfd, 0x7e, 0x87, 0x32,
0x76, 0x1c, 0xcd, 0x3d, 0x8e, 0xe3, 0x18, 0x9f, 0xed, 0xcf, 0x8c, 0x8d,
0x4a, 0x9f, 0x9d, 0xc3, 0xfa, 0x98, 0x8d, 0x7b, 0x3d, 0xd1, 0xf3, 0x2b,
0x33, 0xd6, 0xf4, 0xf5, 0x4c, 0x63, 0xc7, 0x7f, 0xec, 0x33, 0x3f, 0xc7,
0xcf, 0xcb, 0xf4, 0xd9, 0xcf, 0x77, 0x43, 0x26, 0xcb, 0xe8, 0x1c, 0x7a,
0xa2, 0xcf, 0x91, 0xef, 0xd9, 0xfa, 0x98, 0x75, 0x3d, 0x0b, 0xeb, 0xc3,
0xb6, 0x00, 0xf0, 0x1b, 0x86, 0xc6, 0xec, 0x46, 0x66, 0xd9, 0x9c, 0x1d,
0x00, 0x93, 0xc5, 0xd1, 0x18, 0x93, 0xf9, 0x59, 0x76, 0x67, 0x15, 0xc7,
0x07, 0xf0, 0xbb, 0x56, 0x09, 0xef, 0xf7, 0xf7, 0x4e, 0xe5, 0x59, 0x10,
0x54, 0x72, 0xcc, 0x06, 0x46, 0x87, 0x1f, 0x5d, 0x3b, 0x95, 0x8f, 0xbb,
0x88, 0xb2, 0x3d, 0xba, 0x42, 0x58, 0x5f, 0x33, 0xfd, 0x83, 0xce, 0x7a,
0x50, 0xa0, 0xbf, 0xcd, 0x15, 0xe0, 0x83, 0xa7, 0xb3, 0x69, 0xf6, 0x0a,
0xc8, 0x4a, 0xf0, 0x59, 0x20, 0x9f, 0xba, 0x81, 0xb6, 0x7a, 0x3d, 0x74,
0xae, 0xcd, 0x97, 0x54, 0x27, 0x9f, 0xe1, 0x7e, 0xcc, 0x83, 0xc6, 0xb3,
0xcf, 0x91, 0xad, 0x8e, 0x7f, 0xcc, 0x26, 0x46, 0xfe, 0x79, 0xbf, 0xa2,
0xaa, 0x10, 0xe9, 0x3f, 0x33, 0x00, 0xb2, 0xb5, 0x6d, 0x7b, 0x0b, 0xd8,
0x01, 0x6b, 0x03, 0xcd, 0xf3, 0x11, 0x3e, 0xaa, 0xc2, 0x8c, 0x7d, 0xab,
0x27, 0x7b, 0xde, 0xa5, 0x5a, 0xdf, 0x8c, 0xcf, 0x3b, 0xec, 0x8a, 0x0f,
0x26, 0x7c, 0xb5, 0xe9, 0x34, 0x61, 0x8c, 0xfc, 0xca, 0x78, 0x54, 0xda,
0xb2, 0x39, 0x3b, 0xe5, 0x23, 0x1d, 0x67, 0x37, 0x94, 0x33, 0x4d, 0x22,
0xf3, 0xa6, 0x63, 0xe7, 0x7d, 0xd9, 0x41, 0xf4, 0xba, 0x15, 0x29, 0x40,
0x63, 0x91, 0x7c, 0x67, 0x3c, 0x5b, 0xe8, 0xdd, 0xc1, 0xea, 0xf7, 0xf2,
0x3b, 0xfc, 0x47, 0x3a, 0x98, 0xfe, 0x21, 0x5b, 0x5f, 0x76, 0x90, 0x07,
0x00, 0xcd, 0x45, 0x36, 0xb2, 0xf5, 0x7d, 0x7b, 0x25, 0x59, 0xb6, 0x64,
0x0b, 0xc8, 0x0e, 0x6f, 0x57, 0xa6, 0xb0, 0xd9, 0x71, 0xc5, 0xbb, 0x6e,
0x26, 0xf3, 0x2d, 0xf6, 0x7c, 0x7c, 0x2f, 0x91, 0xee, 0x95, 0x15, 0xb0,
0x91, 0x82, 0x1a, 0x12, 0x26, 0x53, 0x99, 0x46, 0xc7, 0x8f, 0x33, 0x25,
0x1a, 0xcd, 0xad, 0xb2, 0x3d, 0xb3, 0x5f, 0xf9, 0xf0, 0xcc, 0x2b, 0x60,
0xf5, 0xf0, 0x59, 0x5d, 0x68, 0xec, 0xcb, 0x0f, 0xae, 0x38, 0xc0, 0xe8,
0xa8, 0x2a, 0x4d, 0xa4, 0x97, 0xd5, 0x9d, 0xe9, 0xaf, 0x0e, 0x3f, 0x93,
0x47, 0x57, 0x4f, 0xe4, 0x63, 0x77, 0x9c, 0x49, 0x86, 0xec, 0x0a, 0xa8,
0xd6, 0x97, 0xd9, 0xfb, 0x42, 0x03, 0x9d, 0xc3, 0xf1, 0xc6, 0xa3, 0xac,
0xad, 0xae, 0x0f, 0xbf, 0xb9, 0x4c, 0x06, 0xcf, 0xf8, 0x97, 0xe9, 0x7e,
0x25, 0x4c, 0x10, 0x64, 0x30, 0xeb, 0x43, 0x01, 0xbc, 0xa5, 0x8b, 0x9e,
0x89, 0xec, 0xce, 0x15, 0xc1, 0xc8, 0xb3, 0xe3, 0x6c, 0x60, 0xad, 0x5c,
0x73, 0x99, 0x5c, 0x25, 0x33, 0x13, 0xa8, 0xac, 0xcc, 0x8e, 0x2a, 0x2f,
0xfe, 0x18, 0x5b, 0x9a, 0x20, 0xa6, 0x41, 0x5a, 0x91, 0x3f, 0xa3, 0x02,
0x21, 0xf9, 0xa8, 0x2f, 0x98, 0xb5, 0xef, 0xe5, 0xd1, 0x7c, 0x34, 0xee,
0x61, 0xfd, 0x8b, 0xc6, 0x91, 0x8f, 0xe3, 0x39, 0xfd, 0x3d, 0x80, 0x17,
0x8c, 0xc6, 0x90, 0xbc, 0x5f, 0x70, 0xe6, 0xd4, 0x4a, 0x1f, 0x12, 0xc1,
0xda, 0x8f, 0x40, 0xfd, 0x09, 0xda, 0x07, 0x66, 0xce, 0x4a, 0x2f, 0x32,
0x64, 0xb3, 0x46, 0x31, 0x7b, 0x8e, 0xd6, 0x4e, 0x7d, 0x0f, 0xe0, 0xa3,
0x69, 0x44, 0x1d, 0x73, 0xa7, 0x59, 0xfc, 0x06, 0x65, 0xf3, 0x90, 0xfe,
0xca, 0x56, 0x67, 0x7c, 0xe7, 0x3d, 0xc8, 0xea, 0xda, 0xd1, 0x88, 0x56,
0x41, 0xdb, 0x3d, 0x93, 0xad, 0x7f, 0x0f, 0x70, 0x76, 0xa7, 0xdd, 0x69,
0xe4, 0x32, 0xfb, 0xd1, 0xbc, 0x9d, 0x55, 0x27, 0xe3, 0x8c, 0xbd, 0x99,
0xe5, 0x21, 0x00, 0xd8, 0x8d, 0x43, 0xd8, 0x2a, 0xd2, 0x8d, 0x44, 0x86,
0x5d, 0xfa, 0xec, 0xbd, 0x19, 0xe9, 0xef, 0x04, 0x43, 0xb7, 0xbb, 0x9e,
0xed, 0xc6, 0x87, 0xdf, 0x99, 0xff, 0x63, 0xef, 0x59, 0x9d, 0x3f, 0x01,
0xc0, 0x1c, 0xd8, 0x6a, 0xb6, 0x58, 0x1b, 0xd9, 0x26, 0x44, 0x63, 0x51,
0x23, 0x13, 0x7d, 0xce, 0xec, 0xbf, 0x82, 0xaa, 0xf7, 0xa8, 0xd6, 0x17,
0x3d, 0xf3, 0xe3, 0xed, 0x00, 0x40, 0x91, 0x33, 0xb3, 0x51, 0x91, 0xbc,
0x75, 0x2a, 0xb3, 0x71, 0xd6, 0x15, 0xc2, 0xda, 0x8f, 0xf0, 0x1b, 0x9a,
0xf5, 0x44, 0x5d, 0xbd, 0xcf, 0x08, 0xc8, 0x5d, 0xe7, 0x2b, 0xfe, 0x20,
0x5b, 0xdf, 0xa3, 0x77, 0xcb, 0x8f, 0x39, 0x28, 0xb3, 0xec, 0xb3, 0xdd,
0xe3, 0xd5, 0xe7, 0x48, 0x3e, 0xdb, 0x03, 0x66, 0xfd, 0x4c, 0x73, 0xeb,
0x65, 0xd1, 0xdc, 0x4e, 0x76, 0x3f, 0xfc, 0x2e, 0x00, 0x2d, 0x92, 0xed,
0x9a, 0x77, 0xc8, 0x47, 0xba, 0xde, 0x01, 0xb4, 0x9e, 0x2e, 0x77, 0x43,
0xa4, 0xbf, 0x23, 0xb3, 0xea, 0x1f, 0xfc, 0xab, 0xe0, 0xc8, 0x90, 0xbd,
0xf3, 0x32, 0xa5, 0xcc, 0xb8, 0x5d, 0xd0, 0xab, 0x0f, 0xdb, 0x66, 0x22,
0xca, 0xc6, 0x28, 0x68, 0xbd, 0xff, 0x7e, 0x0d, 0xec, 0x9a, 0xaa, 0x4a,
0xc9, 0x10, 0xf5, 0x29, 0x15, 0x30, 0x00, 0x56, 0x22, 0xdc, 0xca, 0xa3,
0x80, 0x39, 0x0c, 0x2b, 0x36, 0x32, 0xbb, 0x99, 0x6e, 0xe6, 0xba, 0x42,
0x07, 0xc7, 0x1c, 0xee, 0x4a, 0x93, 0xb5, 0x12, 0x04, 0x6c, 0x85, 0x45,
0xfc, 0x0a, 0x80, 0xaa, 0x53, 0xac, 0x36, 0x38, 0xeb, 0x84, 0x51, 0x96,
0xec, 0x0a, 0x82, 0x2a, 0x43, 0x19, 0xac, 0x1c, 0xf2, 0xab, 0xd2, 0xbb,
0x72, 0xf8, 0x48, 0x6e, 0x66, 0x6f, 0xd8, 0x0a, 0x6d, 0xf9, 0xf5, 0x45,
0x50, 0x56, 0xfa, 0xab, 0xfb, 0x1c, 0xcd, 0xb3, 0xa5, 0xb5, 0xb2, 0xb1,
0x8a, 0xb5, 0x1d, 0xd9, 0x89, 0x02, 0x18, 0x35, 0x7d, 0x1d, 0xff, 0xb3,
0xf2, 0x3b, 0x53, 0x09, 0xd0, 0x1e, 0x56, 0x32, 0xd9, 0xb3, 0x2c, 0x98,
0xe8, 0x7f, 0x19, 0xc4, 0x66, 0x30, 0x1a, 0x5f, 0xcd, 0x50, 0x7f, 0x30,
0x59, 0x95, 0xc9, 0x9e, 0x67, 0x3f, 0x77, 0xfc, 0x58, 0x81, 0xb9, 0x02,
0x51, 0xe5, 0x3d, 0xeb, 0xda, 0x14, 0x1f, 0x4e, 0x9a, 0xad, 0x2c, 0x2b,
0xb2, 0x3b, 0xf5, 0xf9, 0x0c, 0x61, 0xe5, 0x59, 0x7b, 0xb3, 0xf3, 0x18,
0xb9, 0x67, 0x5c, 0x93, 0x88, 0x87, 0x5f, 0x06, 0x45, 0xf7, 0xce, 0xaa,
0x83, 0xb3, 0x87, 0xc3, 0xca, 0x57, 0x9b, 0xbc, 0x6a, 0xbf, 0x23, 0xb3,
0x2b, 0x90, 0xb2, 0xb9, 0xe3, 0x9c, 0xfc, 0xb9, 0x64, 0xf3, 0x91, 0x8f,
0xad, 0x4d, 0x8c, 0xe6, 0x75, 0x7b, 0x81, 0xaa, 0x37, 0xf0, 0x3a, 0x2a,
0x79, 0xf6, 0xf0, 0x2b, 0xf9, 0xc8, 0xff, 0x48, 0x4f, 0x44, 0x66, 0x2f,
0xd3, 0x51, 0x1d, 0x1e, 0xe3, 0x3f, 0xb2, 0x91, 0x7d, 0xa6, 0xde, 0x02,
0xbc, 0x91, 0x08, 0xdf, 0xac, 0x45, 0xfa, 0xd8, 0x05, 0x66, 0x3e, 0x9c,
0x51, 0xa5, 0x58, 0xff, 0x67, 0x59, 0xbd, 0x2a, 0xab, 0x33, 0x98, 0xd1,
0x4b, 0xfd, 0x41, 0x08, 0x7b, 0x40, 0x67, 0x53, 0x2d, 0x30, 0x0b, 0xb8,
0x33, 0xbb, 0xe8, 0xee, 0xc1, 0x9e, 0x11, 0x5c, 0xb3, 0x3c, 0xe5, 0x3f,
0x88, 0xf0, 0xec, 0x38, 0x8c, 0xae, 0xfc, 0xdd, 0xb0, 0x62, 0x77, 0x85,
0x55, 0xfb, 0x67, 0xf8, 0x4f, 0x55, 0x00, 0x9f, 0x41, 0xf6, 0x73, 0x74,
0x8f, 0xdb, 0xe7, 0x28, 0x03, 0xab, 0xf1, 0xcc, 0xbe, 0x97, 0xaf, 0x60,
0xef, 0xf8, 0x59, 0x66, 0xfc, 0x7b, 0x66, 0x15, 0x58, 0xdd, 0x3f, 0xf1,
0x87, 0x79, 0xab, 0x28, 0x58, 0x6d, 0x92, 0xae, 0x40, 0x96, 0x85, 0xd5,
0x5b, 0x00, 0x1a, 0x63, 0x6d, 0x46, 0x72, 0xdf, 0xde, 0x40, 0xe5, 0x1c,
0x1a, 0x67, 0x0e, 0x2e, 0x93, 0xaf, 0x60, 0x5e, 0x6b, 0x90, 0xbf, 0x9d,
0xf1, 0x4a, 0x3f, 0xf3, 0xd9, 0xc3, 0x5c, 0x8f, 0x0c, 0xfe, 0xed, 0x84,
0xd1, 0xc1, 0xec, 0xd1, 0xed, 0x96, 0xfc, 0x41, 0x88, 0x75, 0xd8, 0x2a,
0xcb, 0x16, 0x7d, 0x18, 0x22, 0x67, 0x22, 0xfd, 0xd9, 0x67, 0x06, 0xe4,
0x6f, 0x67, 0x3c, 0x7b, 0xce, 0xc2, 0x34, 0x69, 0xab, 0x4d, 0x60, 0x34,
0x16, 0xed, 0xbd, 0x9f, 0xe3, 0x9f, 0x51, 0x6f, 0x01, 0x6c, 0x04, 0x46,
0x0e, 0xa2, 0xcc, 0xf1, 0x73, 0x7d, 0x53, 0xf8, 0xcc, 0x6b, 0xc0, 0x67,
0x6a, 0x64, 0x3f, 0xcb, 0xf4, 0xa8, 0x3a, 0x78, 0x1b, 0x2b, 0x41, 0x56,
0x5d, 0x11, 0x95, 0x0f, 0xc8, 0x7e, 0xf8, 0xf7, 0x00, 0x68, 0x01, 0x6c,
0x84, 0x47, 0xc1, 0x71, 0xbf, 0xe3, 0x6e, 0x7f, 0xd7, 0x61, 0x57, 0x9b,
0x9b, 0x65, 0x48, 0x54, 0xae, 0xab, 0x31, 0x64, 0x3f, 0xdb, 0xf8, 0x1d,
0x15, 0x20, 0xf3, 0x81, 0x39, 0x27, 0x2b, 0x0f, 0xaf, 0x80, 0x48, 0x78,
0x6c, 0x60, 0x37, 0x9a, 0x51, 0x60, 0xcd, 0x64, 0x42, 0x74, 0x80, 0xe8,
0x80, 0x3a, 0x1b, 0xed, 0xd7, 0x85, 0xfc, 0x63, 0xf6, 0xc6, 0xda, 0x3d,
0xe3, 0x9a, 0x61, 0x2a, 0x50, 0x35, 0xee, 0xe7, 0xd2, 0xff, 0x34, 0x0c,
0xdd, 0xa1, 0xec, 0x26, 0xa3, 0xcc, 0xef, 0x1c, 0xd0, 0x90, 0x47, 0xcf,
0xec, 0xc2, 0xb2, 0xea, 0xe5, 0x03, 0x37, 0xb2, 0x8f, 0x6c, 0xb1, 0x41,
0x17, 0xcd, 0xb5, 0xf3, 0xab, 0x6b, 0x14, 0xb1, 0xab, 0x62, 0xc2, 0xca,
0x3c, 0xa3, 0xe8, 0x2c, 0xd0, 0xc6, 0x54, 0x19, 0xc3, 0x66, 0xe4, 0xea,
0x9c, 0xb3, 0xe8, 0x54, 0xaf, 0x33, 0xc6, 0x5f, 0xf2, 0x55, 0xf0, 0x3b,
0xc0, 0x64, 0xed, 0x27, 0xb0, 0xf5, 0x5f, 0x07, 0xaf, 0xc0, 0x94, 0x4e,
0xf4, 0xbc, 0xa3, 0xcb, 0x8f, 0xfb, 0xb2, 0x5c, 0xdd, 0xa3, 0x99, 0xce,
0xca, 0x46, 0x57, 0xd6, 0xcb, 0xed, 0x0c, 0x52, 0xab, 0x1f, 0xfe, 0x41,
0x48, 0x26, 0x7c, 0xa6, 0x63, 0x95, 0xdd, 0x99, 0x2b, 0xc2, 0x83, 0x74,
0xd8, 0x1e, 0x65, 0xf6, 0x7e, 0xdd, 0xcd, 0xd9, 0xfb, 0x3a, 0xf4, 0x3f,
0xbc, 0x06, 0xb2, 0x82, 0x57, 0x24, 0xcb, 0xca, 0x95, 0xb7, 0x93, 0x5d,
0x30, 0xc1, 0xb7, 0x3b, 0x40, 0xc3, 0x2b, 0x80, 0xcd, 0xf4, 0x5d, 0x9d,
0xec, 0xec, 0xc6, 0x23, 0xfb, 0x48, 0x17, 0x53, 0x92, 0xdf, 0xa1, 0x12,
0x3c, 0xcb, 0xee, 0xb0, 0x43, 0xff, 0xd3, 0xb0, 0x55, 0xc7, 0x7c, 0xc9,
0xdd, 0xad, 0x3f, 0xd3, 0xd5, 0xb9, 0x8f, 0xdf, 0xa1, 0x12, 0x9c, 0xcd,
0x47, 0xbd, 0x05, 0xcc, 0x34, 0x63, 0x9f, 0x10, 0x04, 0x83, 0x32, 0x53,
0x3a, 0x1b, 0xb8, 0x2a, 0x8f, 0x74, 0xfd, 0x38, 0xfa, 0x22, 0xf9, 0x77,
0x69, 0x0a, 0xcf, 0xe2, 0xf4, 0x0a, 0x30, 0x93, 0x4d, 0x57, 0xdc, 0x7c,
0xfb, 0x0d, 0x9f, 0xfd, 0x19, 0xcd, 0xab, 0xf4, 0x54, 0x36, 0x32, 0xdd,
0xd5, 0x98, 0x9f, 0xf3, 0xf0, 0x9f, 0x45, 0x47, 0x4e, 0xac, 0x94, 0xc3,
0x4e, 0x10, 0x5c, 0xf5, 0xf0, 0xab, 0x9f, 0xed, 0xe7, 0x2a, 0x38, 0x66,
0xf6, 0x7a, 0x34, 0xae, 0xf6, 0x75, 0xd9, 0xeb, 0x1d, 0xe3, 0xf6, 0xd9,
0x77, 0x27, 0x52, 0xd1, 0x33, 0xf6, 0xa0, 0x98, 0x0e, 0xfb, 0x8a, 0x87,
0xcf, 0x82, 0x0e, 0x25, 0xfb, 0x3e, 0xc3, 0x8e, 0x67, 0x67, 0xd1, 0xd9,
0x7f, 0xfb, 0xf3, 0x90, 0x7f, 0x6a, 0x13, 0xb8, 0x73, 0x41, 0x57, 0x62,
0x36, 0xe3, 0xd9, 0x4a, 0xe0, 0x83, 0x09, 0x55, 0x81, 0x88, 0xef, 0x6a,
0xc3, 0xad, 0xa2, 0x6c, 0xae, 0x2f, 0x7d, 0xd1, 0x5c, 0x54, 0x09, 0xae,
0x7e, 0xf8, 0xd1, 0x86, 0x8f, 0xf5, 0xac, 0x8e, 0xef, 0x20, 0xaa, 0x28,
0x53, 0x9d, 0x3d, 0x1a, 0x8f, 0x60, 0xe5, 0x66, 0xf5, 0xb3, 0xac, 0xbe,
0x45, 0x30, 0x7a, 0x99, 0x64, 0x61, 0xae, 0xc0, 0xae, 0x7c, 0xe4, 0x6b,
0x76, 0xc5, 0x8c, 0xb1, 0x97, 0xfd, 0x32, 0xc8, 0x46, 0xfd, 0x55, 0x33,
0xdf, 0x33, 0xd6, 0x84, 0xd6, 0x83, 0x9a, 0x43, 0x3f, 0x6f, 0x56, 0x9e,
0xd9, 0xbf, 0xb7, 0xd9, 0xe3, 0x2c, 0xb3, 0xc6, 0xd5, 0x30, 0x23, 0xcb,
0xc8, 0x8b, 0x47, 0x7e, 0xfe, 0xbb, 0x78, 0xc4, 0x98, 0x94, 0x35, 0x6d,
0x11, 0x2b, 0x07, 0x39, 0x23, 0x53, 0xf9, 0x2b, 0x30, 0x3f, 0x6f, 0x01,
0x77, 0x87, 0x9d, 0xe4, 0x9b, 0x94, 0xec, 0x1e, 0x63, 0xc6, 0xc7, 0x1c,
0xd6, 0xc9, 0x99, 0x60, 0x53, 0x10, 0x70, 0xd0, 0x3d, 0x40, 0x76, 0x67,
0xb3, 0x8d, 0x0d, 0x1a, 0xeb, 0x06, 0x4a, 0x37, 0x70, 0xde, 0xe6, 0xee,
0x7b, 0x53, 0xb6, 0x34, 0x81, 0xb6, 0x79, 0xe9, 0x6e, 0xfa, 0x6a, 0xf6,
0xa2, 0x4e, 0x57, 0x87, 0xce, 0xd3, 0xfa, 0xab, 0x60, 0xfb, 0x1e, 0x39,
0xf3, 0x0d, 0xd4, 0x90, 0xf5, 0x63, 0xd5, 0x6b, 0x0c, 0xf3, 0x7a, 0x24,
0xe6, 0xf8, 0xf5, 0xbb, 0x00, 0xd4, 0x00, 0x8e, 0xb1, 0xea, 0x9b, 0xa6,
0x6e, 0xf6, 0x7b, 0x7d, 0xdd, 0x71, 0x71, 0x51, 0xf4, 0x1a, 0x28, 0x84,
0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42,
0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21,
0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10,
0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08,
0x81, 0xf9, 0x07, 0x4e, 0x1f, 0xd4, 0x6d, 0xe4, 0x18, 0xb7, 0xb8, 0x00,
0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
unsigned int font_png_len = 1943;

312
source/icon_data.c Normal file
View File

@@ -0,0 +1,312 @@
unsigned char icon_png[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
0x08, 0x06, 0x00, 0x00, 0x00, 0xc3, 0x3e, 0x61, 0xcb, 0x00, 0x00, 0x00,
0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
0x0e, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x5d, 0x3b, 0x6f,
0x1b, 0xc7, 0x16, 0xfe, 0x78, 0x13, 0x58, 0x8a, 0x40, 0x3d, 0x6c, 0xfd,
0x98, 0x54, 0x41, 0x0a, 0x23, 0x4d, 0xe2, 0x2e, 0x69, 0x0c, 0xd8, 0x95,
0x00, 0x03, 0x6e, 0x2c, 0x20, 0x80, 0x85, 0x14, 0x4a, 0x65, 0x15, 0x81,
0x02, 0x04, 0xb0, 0x1a, 0x03, 0x04, 0x5c, 0x39, 0x40, 0x1a, 0xdd, 0x2e,
0x57, 0xcd, 0x45, 0x8a, 0x8b, 0x5b, 0xdd, 0x1f, 0x43, 0x89, 0x22, 0x09,
0xd9, 0x32, 0x10, 0xf0, 0x16, 0xf4, 0x8c, 0x67, 0x67, 0xce, 0xcc, 0x9c,
0x79, 0xec, 0xce, 0x2c, 0xcd, 0x0f, 0xa0, 0x4d, 0x2d, 0x97, 0xcb, 0xd9,
0x39, 0xdf, 0x9e, 0xe7, 0x3c, 0x06, 0x58, 0x03, 0x00, 0x16, 0xca, 0xfb,
0x41, 0xb1, 0x56, 0x14, 0xc0, 0x2a, 0xde, 0xec, 0x42, 0xfb, 0xdb, 0x77,
0x8f, 0xfa, 0xf9, 0x9c, 0xef, 0xac, 0x0c, 0xfe, 0x51, 0xba, 0x01, 0x99,
0x41, 0x09, 0x93, 0x3a, 0xd6, 0xf8, 0xec, 0x74, 0xf4, 0x06, 0xa3, 0xf3,
0x8b, 0x90, 0xdf, 0x50, 0x5f, 0xbd, 0xc6, 0xe7, 0xa5, 0x1b, 0xd0, 0x06,
0x4e, 0x47, 0x6f, 0xe4, 0xfb, 0xa3, 0x27, 0x8f, 0x81, 0xa5, 0xa0, 0x9c,
0x4f, 0xf5, 0xe4, 0x72, 0x8c, 0xd1, 0xf9, 0x05, 0x9e, 0xfc, 0xf0, 0xad,
0xeb, 0x7c, 0x1b, 0xc1, 0x7a, 0xab, 0x31, 0xfa, 0x42, 0x80, 0x50, 0xb5,
0xce, 0xbe, 0xa6, 0x4a, 0x96, 0xc9, 0xe5, 0x98, 0xd5, 0x86, 0xdf, 0xff,
0xfc, 0x0b, 0x00, 0xf0, 0xe8, 0xc1, 0xfd, 0x0c, 0xcd, 0x28, 0x8b, 0x3e,
0x98, 0x80, 0x50, 0xb5, 0xde, 0x80, 0x22, 0xe0, 0x2c, 0xea, 0x5a, 0x08,
0x7f, 0x55, 0xd0, 0x07, 0x02, 0x00, 0x00, 0x8e, 0x4f, 0xcf, 0x1a, 0x4f,
0x2b, 0xba, 0xb5, 0xbf, 0x0b, 0x00, 0x18, 0x9d, 0x5f, 0xe0, 0xe6, 0xdd,
0x6d, 0xe8, 0xf7, 0xaa, 0xf6, 0x17, 0x7a, 0x43, 0x00, 0x00, 0x98, 0x4e,
0xae, 0x74, 0x12, 0x84, 0x62, 0xa1, 0xfd, 0xcf, 0x39, 0xd7, 0xc0, 0xcd,
0xbb, 0x5b, 0x0e, 0x11, 0x92, 0x34, 0x57, 0x57, 0xe8, 0x15, 0x01, 0x00,
0x83, 0x04, 0xac, 0x0e, 0x4d, 0xd0, 0x1c, 0xb1, 0x4f, 0xee, 0x02, 0x00,
0xfe, 0xf9, 0xef, 0xff, 0xca, 0x57, 0xad, 0x28, 0x4d, 0x80, 0x28, 0xf5,
0x38, 0x9d, 0x5c, 0xd9, 0xae, 0x65, 0x05, 0xa5, 0x39, 0xb8, 0xc7, 0x5c,
0xc7, 0x43, 0xdb, 0x51, 0x1b, 0x4a, 0x46, 0x01, 0x7a, 0x47, 0x05, 0x85,
0x53, 0xc7, 0xa7, 0x67, 0x38, 0x39, 0x7a, 0x46, 0x5d, 0xc7, 0x0a, 0xae,
0x10, 0x6d, 0xe7, 0x4d, 0x2e, 0xc7, 0xd8, 0xbb, 0xb7, 0x4f, 0x7d, 0x24,
0xda, 0xde, 0x88, 0x14, 0xde, 0xde, 0xbe, 0x07, 0x00, 0x7c, 0xb1, 0x71,
0x87, 0xdb, 0xc4, 0xce, 0x51, 0x4a, 0x03, 0xc8, 0x8e, 0x3a, 0x3e, 0x3d,
0x23, 0x8f, 0xeb, 0xf8, 0x20, 0x6c, 0x2f, 0x12, 0x7d, 0x04, 0x2f, 0x26,
0x97, 0x63, 0x5b, 0xb8, 0x28, 0xdb, 0xae, 0x27, 0x95, 0x04, 0x11, 0x6a,
0x44, 0xa9, 0x04, 0xc6, 0x02, 0x68, 0x0a, 0x5f, 0x13, 0xf0, 0x40, 0x3f,
0x57, 0x3f, 0x5f, 0xc5, 0xce, 0xde, 0xdd, 0xac, 0x8d, 0xe3, 0x62, 0xef,
0xde, 0xbe, 0x48, 0x1c, 0x49, 0xa8, 0xc2, 0xdf, 0xda, 0xdc, 0x90, 0xef,
0x95, 0x9c, 0x81, 0xde, 0xe7, 0x45, 0x53, 0xd1, 0xd5, 0x24, 0x82, 0x14,
0x95, 0x0e, 0x04, 0x9a, 0x83, 0xe9, 0xe4, 0xaa, 0x18, 0x09, 0x5c, 0x29,
0x64, 0x11, 0x29, 0x28, 0x24, 0xe1, 0x08, 0x5f, 0x1c, 0xef, 0x84, 0x04,
0xa5, 0x4c, 0xc0, 0x00, 0x30, 0xd5, 0x3a, 0x61, 0x0e, 0xd8, 0xf6, 0xdd,
0xe2, 0x18, 0xb6, 0x0a, 0x87, 0x39, 0xe0, 0x40, 0xde, 0x5b, 0xc9, 0x68,
0xa1, 0x74, 0x14, 0x60, 0xc0, 0xa6, 0xe6, 0x6d, 0xc7, 0x55, 0x94, 0x20,
0x01, 0xe0, 0x4d, 0x21, 0xab, 0x30, 0xf2, 0x10, 0xa5, 0x43, 0xc4, 0xd2,
0x45, 0x0c, 0xc3, 0x17, 0x48, 0x85, 0xcd, 0x59, 0x0c, 0x71, 0x0e, 0x3f,
0x14, 0x90, 0xa2, 0xae, 0x41, 0x45, 0x09, 0xba, 0x9f, 0xa0, 0x42, 0x27,
0xc0, 0xf7, 0xdf, 0x7c, 0x25, 0xde, 0x76, 0x22, 0x9b, 0xb6, 0x7e, 0x84,
0xeb, 0xd8, 0x24, 0x13, 0x80, 0x1b, 0x1d, 0x00, 0x3c, 0x01, 0xda, 0x84,
0x1f, 0x72, 0x3d, 0x2e, 0x09, 0x7e, 0xff, 0xf3, 0x2f, 0x23, 0x44, 0xec,
0x9a, 0x00, 0x6d, 0x38, 0x81, 0x9d, 0x38, 0x36, 0x0e, 0xc1, 0x73, 0xcb,
0xb8, 0x3e, 0x78, 0xaf, 0x23, 0xc8, 0xa2, 0x13, 0x81, 0xca, 0x17, 0x50,
0xce, 0xa2, 0x48, 0x29, 0xef, 0xef, 0x6e, 0x03, 0xe8, 0x5e, 0xf8, 0x40,
0x8b, 0x51, 0xc0, 0xc1, 0xe1, 0x73, 0x00, 0xc0, 0x70, 0x7b, 0x07, 0x2f,
0x4f, 0x7e, 0x16, 0x87, 0x45, 0x07, 0x36, 0x6e, 0x70, 0x36, 0xbd, 0xc6,
0xf6, 0xce, 0xae, 0xf7, 0x9a, 0x81, 0x42, 0x6f, 0x03, 0xa4, 0x17, 0xaf,
0x6a, 0x0d, 0x41, 0x06, 0x47, 0xd2, 0xc8, 0xc0, 0xf8, 0x7a, 0xd6, 0x08,
0x19, 0xbb, 0x44, 0xeb, 0x61, 0xe0, 0x7c, 0x36, 0xc5, 0xe1, 0xf1, 0x0b,
0x00, 0xa0, 0x88, 0x20, 0x31, 0x9b, 0x5e, 0x03, 0x00, 0x49, 0x04, 0x8b,
0xe0, 0x4b, 0xfb, 0x2f, 0xc0, 0xc7, 0x36, 0xc8, 0xfb, 0x51, 0xb5, 0x82,
0x70, 0x0e, 0x39, 0x44, 0xf0, 0x8c, 0x2d, 0x68, 0x2d, 0x57, 0xd0, 0x49,
0x14, 0x30, 0x9f, 0x4d, 0x1b, 0x44, 0x50, 0xa1, 0x1f, 0x13, 0x44, 0x00,
0x96, 0x82, 0x27, 0x84, 0x3f, 0x40, 0x1d, 0xc2, 0x57, 0x31, 0x80, 0xd6,
0xae, 0xa3, 0x27, 0x8f, 0x25, 0x19, 0x02, 0xc3, 0xc5, 0x90, 0x5c, 0x41,
0x32, 0xda, 0xe8, 0x48, 0xd9, 0x30, 0x61, 0x06, 0x54, 0x0c, 0xb7, 0x77,
0x58, 0x17, 0x51, 0xb4, 0x85, 0x40, 0x4a, 0x5b, 0xa5, 0xb3, 0xe9, 0x4b,
0x18, 0x29, 0xea, 0x3c, 0xb5, 0x6f, 0x64, 0x3f, 0xa8, 0x3e, 0x82, 0x4d,
0x1b, 0x10, 0xc9, 0xa2, 0x86, 0x80, 0xd5, 0x68, 0x21, 0xa7, 0xaf, 0xd0,
0x86, 0x09, 0x68, 0x14, 0x45, 0x74, 0xcc, 0x67, 0x53, 0x27, 0x09, 0x32,
0x0b, 0xde, 0x40, 0x87, 0x59, 0x43, 0xd9, 0x0f, 0x81, 0x66, 0xc1, 0x2a,
0xf8, 0x36, 0xd0, 0xaa, 0x09, 0x78, 0xfd, 0xf2, 0x57, 0xf2, 0xb8, 0x30,
0x09, 0x3a, 0x34, 0xe1, 0xb7, 0xa6, 0xea, 0x3b, 0x4c, 0x18, 0x19, 0x66,
0x41, 0x40, 0x37, 0x0b, 0xb6, 0x94, 0xf2, 0xf8, 0x7a, 0xd6, 0x5e, 0xeb,
0xd0, 0xae, 0x2d, 0x75, 0x9a, 0x02, 0x01, 0xa1, 0x0d, 0x08, 0xe1, 0x67,
0x6f, 0x8b, 0x9e, 0x6f, 0xa0, 0x34, 0x41, 0x46, 0x13, 0x40, 0xb6, 0x01,
0x30, 0xc3, 0x46, 0x8e, 0x93, 0x48, 0x84, 0x8a, 0x40, 0x41, 0x13, 0xc0,
0xf1, 0x4a, 0xa5, 0x0a, 0xbc, 0x99, 0xcf, 0xb1, 0x35, 0x1c, 0x92, 0x17,
0x6a, 0x5b, 0xe5, 0xbb, 0x20, 0x34, 0x41, 0x87, 0x26, 0x01, 0x00, 0x16,
0x7a, 0xfe, 0x80, 0x13, 0x32, 0x8e, 0xaf, 0x67, 0x7a, 0x32, 0xa9, 0x58,
0x14, 0xe0, 0xf2, 0x4a, 0x17, 0xb6, 0xf3, 0x6e, 0xe6, 0x73, 0xdc, 0xcc,
0xe7, 0x8d, 0x2f, 0x68, 0x26, 0xa2, 0x98, 0x77, 0x3f, 0x9d, 0x5c, 0x75,
0x6d, 0x16, 0x00, 0x98, 0x26, 0xc1, 0x85, 0x36, 0x84, 0x0f, 0x24, 0x38,
0x81, 0x0f, 0x0f, 0x9e, 0xca, 0xf7, 0x7f, 0xbc, 0x7e, 0xa5, 0x7e, 0xe4,
0x0c, 0x4f, 0x04, 0x09, 0xb4, 0xef, 0x54, 0x11, 0xd6, 0x75, 0x4c, 0x02,
0xe9, 0x20, 0x06, 0x0e, 0x62, 0xc9, 0xda, 0x57, 0x59, 0x9c, 0xc0, 0x87,
0x07, 0x4f, 0xe5, 0x8b, 0xfa, 0x4c, 0x47, 0x8d, 0xc2, 0x2f, 0x00, 0x43,
0x13, 0x24, 0x94, 0x97, 0xa3, 0x87, 0x9f, 0x47, 0x6b, 0x80, 0x3f, 0x5e,
0xbf, 0x62, 0x0b, 0x5c, 0xff, 0x9e, 0x82, 0x4f, 0x55, 0xf8, 0x02, 0xa4,
0x26, 0x60, 0xa6, 0x91, 0x7d, 0x73, 0x1e, 0x59, 0x7d, 0x1b, 0xa3, 0x01,
0xa2, 0x85, 0xb6, 0x16, 0x3e, 0x89, 0x50, 0x9f, 0xc0, 0x78, 0xca, 0x47,
0xe7, 0x17, 0x18, 0x9d, 0x5f, 0xe8, 0x39, 0x03, 0x96, 0x26, 0x88, 0x35,
0x01, 0x03, 0xc0, 0x10, 0xa8, 0x13, 0x6b, 0xe1, 0x3b, 0xe1, 0x25, 0x01,
0x95, 0x27, 0x10, 0x82, 0x17, 0x18, 0x5f, 0xcf, 0x82, 0xa7, 0xae, 0x25,
0x67, 0x02, 0x6d, 0xa6, 0xc0, 0x81, 0xb5, 0xf0, 0x69, 0x90, 0x19, 0x54,
0xd5, 0x1c, 0x70, 0xa6, 0xb0, 0x87, 0x4e, 0x58, 0x4d, 0x71, 0x02, 0x65,
0xd8, 0xe6, 0xd3, 0x04, 0xca, 0xe7, 0x6b, 0xe1, 0xbb, 0x31, 0x00, 0xcc,
0x41, 0x29, 0x5c, 0xc7, 0x30, 0x26, 0x54, 0x6c, 0xbd, 0x1a, 0x18, 0x62,
0x26, 0xd6, 0x00, 0xe0, 0x20, 0x41, 0x42, 0x45, 0xd1, 0x0a, 0x1f, 0x01,
0xf4, 0xf0, 0xc2, 0x99, 0xec, 0xd1, 0xb1, 0xb6, 0xfb, 0x69, 0xa0, 0x86,
0xa7, 0x51, 0x24, 0x78, 0xf2, 0xc3, 0xb7, 0xae, 0xa1, 0xe7, 0x4e, 0xb8,
0x08, 0xe0, 0x0b, 0x33, 0x42, 0xe2, 0xcd, 0x2a, 0x84, 0x3f, 0x9b, 0x5e,
0x37, 0xc6, 0x1b, 0x54, 0x0c, 0xef, 0x6a, 0x26, 0x82, 0x08, 0xa9, 0x19,
0x42, 0xaf, 0x13, 0xa8, 0x17, 0x72, 0x6e, 0xe6, 0x73, 0x43, 0xad, 0x7b,
0x92, 0x3d, 0x55, 0x08, 0x5f, 0x85, 0x6b, 0xf4, 0x51, 0x45, 0x18, 0xe0,
0x43, 0xdd, 0xc0, 0x35, 0x57, 0x51, 0x3b, 0x3f, 0x18, 0xc1, 0x51, 0xc0,
0xd6, 0x70, 0x88, 0x83, 0xc3, 0xe7, 0x46, 0x5e, 0x5f, 0x45, 0x5f, 0xec,
0x3e, 0x77, 0x2c, 0x62, 0x69, 0x44, 0xa4, 0x8b, 0xd9, 0x88, 0x0e, 0x03,
0x45, 0x75, 0xcf, 0x45, 0x04, 0x54, 0xf8, 0xf4, 0xeb, 0xa8, 0x5c, 0x1b,
0x38, 0x07, 0xd7, 0x58, 0xe0, 0x3a, 0xdf, 0x90, 0x87, 0xcb, 0x07, 0x18,
0x00, 0xcb, 0x8a, 0x9d, 0x6d, 0x60, 0x07, 0xb0, 0x24, 0x82, 0x5a, 0xea,
0xed, 0xcb, 0xd3, 0xaf, 0xa3, 0x62, 0xff, 0x80, 0x8c, 0x0a, 0x08, 0x70,
0xfc, 0x32, 0xe3, 0x73, 0x9f, 0x06, 0x90, 0x0c, 0x14, 0x24, 0xb0, 0x0d,
0xee, 0xd8, 0x1a, 0x0e, 0x75, 0x6d, 0x50, 0xfd, 0xd3, 0xbf, 0x0a, 0x38,
0x1d, 0xbd, 0x31, 0xc8, 0x41, 0x25, 0x8c, 0x6c, 0xb3, 0x93, 0x38, 0x26,
0xa0, 0xa1, 0x86, 0x5e, 0xbf, 0xfc, 0xd5, 0x4a, 0x82, 0xbe, 0x3e, 0xfd,
0x3d, 0x80, 0xd3, 0x21, 0xe4, 0x4c, 0x4c, 0xb1, 0x81, 0x9b, 0x08, 0x0a,
0x1d, 0xac, 0xb1, 0x7e, 0xfa, 0x0b, 0x43, 0x8d, 0x10, 0x5c, 0x73, 0x13,
0xab, 0x9b, 0x1d, 0xbc, 0x46, 0x3e, 0x4c, 0x2e, 0xc7, 0xde, 0x3c, 0x41,
0x48, 0x14, 0xe0, 0x74, 0x30, 0x14, 0x47, 0xb1, 0xda, 0xa7, 0x5f, 0x1d,
0x89, 0xcc, 0x9d, 0x9f, 0x50, 0x11, 0xbc, 0x79, 0x01, 0x15, 0x84, 0xd3,
0x48, 0xca, 0x45, 0x27, 0x40, 0xaf, 0x56, 0xb8, 0x4a, 0x81, 0x20, 0x43,
0x0f, 0x89, 0xe0, 0x04, 0x57, 0xf0, 0x02, 0xaa, 0x09, 0x60, 0x09, 0xff,
0xf0, 0xf8, 0x85, 0xd1, 0x69, 0xae, 0x30, 0xb1, 0x26, 0x50, 0x39, 0x0b,
0x6a, 0x7e, 0x42, 0xc5, 0xe0, 0x86, 0x84, 0xe2, 0x5c, 0xaf, 0x36, 0x36,
0x4c, 0x00, 0x35, 0x7f, 0x8f, 0x82, 0x20, 0x81, 0xd6, 0x81, 0xd5, 0xaa,
0x7f, 0x01, 0x41, 0x02, 0x35, 0x77, 0xe1, 0x9b, 0xad, 0xb4, 0xca, 0x48,
0x76, 0x02, 0xfb, 0xda, 0x71, 0xba, 0x36, 0xe8, 0x99, 0x26, 0xe0, 0x20,
0x6e, 0x48, 0xd8, 0xcb, 0x93, 0x9f, 0x6b, 0x4d, 0x8b, 0x66, 0xc7, 0x27,
0x42, 0x02, 0x67, 0x49, 0x5f, 0x25, 0x80, 0x54, 0xdf, 0x27, 0x47, 0xcf,
0xd8, 0x24, 0x50, 0x66, 0xf6, 0x54, 0xaf, 0xfe, 0x29, 0x50, 0x13, 0x56,
0x2a, 0x87, 0xd3, 0x0f, 0x08, 0x5d, 0xd2, 0x56, 0xf7, 0x01, 0x64, 0xd6,
0x4f, 0x9d, 0x97, 0xcf, 0xf5, 0x0b, 0xfa, 0x0c, 0xd7, 0xf4, 0xb5, 0xbe,
0xc1, 0x47, 0x02, 0x95, 0x3c, 0x94, 0x0f, 0x60, 0x78, 0x8f, 0xc4, 0xfc,
0xbd, 0x95, 0x44, 0xcf, 0x34, 0x41, 0x16, 0xf8, 0xaa, 0x81, 0xbd, 0x54,
0xeb, 0x6b, 0xd8, 0xa1, 0x9b, 0x0e, 0x76, 0x14, 0xf0, 0xa9, 0x38, 0x86,
0xab, 0x0c, 0x4d, 0xf8, 0x03, 0xc0, 0x9f, 0x0a, 0x6e, 0x84, 0x12, 0xdb,
0x3b, 0xbb, 0xae, 0x9a, 0xf9, 0xaa, 0x65, 0x11, 0xab, 0xbf, 0x1f, 0xce,
0x6a, 0x27, 0x16, 0x67, 0x51, 0x6a, 0x76, 0x5d, 0x03, 0x78, 0x27, 0x19,
0xea, 0x9a, 0xa0, 0x2f, 0x0e, 0x22, 0x77, 0xf2, 0x4a, 0xe0, 0x24, 0x97,
0x62, 0x10, 0x8b, 0x5d, 0xb8, 0x66, 0x34, 0x5b, 0xd2, 0xc2, 0x03, 0xfd,
0x00, 0xe0, 0x61, 0xbb, 0x6d, 0x25, 0xcf, 0xd8, 0x11, 0x34, 0xa9, 0xf1,
0x76, 0xd7, 0xce, 0x9a, 0x2b, 0x3a, 0xc8, 0x99, 0x08, 0x4b, 0x31, 0xb3,
0xba, 0x26, 0xa0, 0xd4, 0x3d, 0x85, 0xcf, 0xc1, 0x58, 0x8f, 0xdf, 0x06,
0xd1, 0xe0, 0x50, 0x22, 0x0c, 0xb7, 0x77, 0x92, 0x48, 0xc0, 0x1c, 0x8f,
0x98, 0x0d, 0xae, 0x10, 0x31, 0x67, 0x1a, 0x39, 0x65, 0x7c, 0xa2, 0x63,
0xb5, 0x13, 0x5e, 0x31, 0x28, 0x65, 0xbd, 0xde, 0x98, 0x06, 0xe7, 0xe8,
0xb4, 0x2e, 0xe3, 0x76, 0x17, 0xd9, 0x72, 0x67, 0x10, 0x53, 0xc6, 0x26,
0x12, 0x26, 0xc1, 0xa9, 0xdd, 0xb3, 0x0d, 0x08, 0xd9, 0xde, 0xd9, 0x0d,
0x26, 0x42, 0x2e, 0x12, 0x74, 0x45, 0x84, 0x9e, 0x93, 0x80, 0xf4, 0xeb,
0x0c, 0x1f, 0x20, 0xd7, 0xd2, 0xed, 0xa1, 0x37, 0x90, 0xa3, 0x03, 0xbb,
0xf4, 0x0d, 0x7c, 0xa4, 0xcb, 0x65, 0x16, 0x52, 0xfc, 0x02, 0xcf, 0x4a,
0xea, 0x03, 0xf9, 0xcf, 0x07, 0x90, 0xaa, 0x22, 0x85, 0x10, 0x31, 0x2c,
0xee, 0x93, 0x83, 0xd8, 0x07, 0x12, 0x00, 0x4d, 0xbf, 0x40, 0x77, 0x0e,
0xd9, 0x4b, 0xab, 0xaf, 0x89, 0x40, 0xa3, 0x0f, 0x11, 0x02, 0x60, 0x27,
0x81, 0xab, 0x16, 0x90, 0x2d, 0x0d, 0x5c, 0xca, 0x3f, 0xe8, 0x02, 0xae,
0x6a, 0xa2, 0x58, 0x11, 0x35, 0x87, 0x79, 0x4b, 0x9d, 0xb4, 0xa2, 0xfa,
0x05, 0x6a, 0xb1, 0xc8, 0xe7, 0x04, 0x66, 0xad, 0x05, 0xc4, 0x90, 0x40,
0xbc, 0x42, 0xd1, 0x75, 0x65, 0xcf, 0xa7, 0x71, 0x72, 0x10, 0x21, 0x07,
0x09, 0xa6, 0x93, 0xab, 0x86, 0x06, 0x08, 0x4a, 0x05, 0xdb, 0x10, 0xb2,
0x6d, 0x4b, 0x0e, 0xb8, 0x96, 0x9e, 0x55, 0x41, 0xcc, 0x56, 0x02, 0xd0,
0x9c, 0xc0, 0x92, 0x9a, 0xf9, 0x2b, 0x35, 0x19, 0x86, 0x6b, 0x92, 0x7d,
0x8e, 0xa0, 0x4d, 0x03, 0xb0, 0xe7, 0xff, 0x77, 0x2d, 0x7c, 0x20, 0x6c,
0x10, 0xaa, 0x6f, 0xee, 0x62, 0x8a, 0x00, 0x4b, 0xce, 0x84, 0xe2, 0xf4,
0xbb, 0x67, 0x87, 0x95, 0x01, 0x60, 0xaf, 0x05, 0x34, 0xc0, 0x64, 0xdb,
0xa0, 0x83, 0x57, 0x34, 0xb6, 0x86, 0x43, 0xeb, 0x8a, 0x25, 0x99, 0x04,
0xd9, 0xc5, 0xfd, 0x37, 0xfa, 0xc1, 0x65, 0x12, 0x88, 0x9d, 0x58, 0xc9,
0x7e, 0x54, 0x4d, 0x80, 0xb1, 0x9a, 0x75, 0xa9, 0x7d, 0xf8, 0x2c, 0x90,
0xed, 0x3b, 0x3c, 0x7e, 0x11, 0x6c, 0x4f, 0x89, 0x75, 0x89, 0xc5, 0xff,
0x0b, 0x20, 0x6a, 0xb5, 0x33, 0x3c, 0x3c, 0x78, 0xaa, 0x92, 0xa7, 0xb3,
0xdd, 0x3e, 0x55, 0x30, 0xd6, 0x38, 0x60, 0xa5, 0x82, 0x17, 0xc0, 0x52,
0xf0, 0xaa, 0x87, 0x58, 0x6a, 0x3b, 0x56, 0x02, 0x0d, 0xe1, 0x03, 0x08,
0x72, 0x0e, 0x2d, 0xc2, 0x37, 0xfe, 0x8e, 0xd1, 0x04, 0x1a, 0x69, 0x8a,
0x94, 0x90, 0x53, 0x9c, 0x43, 0x6f, 0x2a, 0x78, 0x67, 0xef, 0x6e, 0x69,
0x22, 0x18, 0xc2, 0x57, 0xe1, 0x23, 0x82, 0x47, 0xf8, 0xc6, 0xf1, 0xbe,
0x92, 0xc0, 0x01, 0xa7, 0x3f, 0xc7, 0xae, 0x05, 0x14, 0x22, 0x81, 0x53,
0xf8, 0x2a, 0x28, 0x12, 0x30, 0x85, 0x6f, 0x7c, 0xde, 0x47, 0x12, 0xe8,
0x5a, 0xe0, 0xf8, 0xf4, 0x8c, 0xb5, 0x17, 0x33, 0x6b, 0x3c, 0x80, 0xc0,
0xe9, 0xe8, 0x0d, 0xe9, 0x17, 0x28, 0x0e, 0x47, 0x4e, 0x1b, 0x48, 0xd6,
0x27, 0x5c, 0xea, 0x4e, 0xf5, 0x0b, 0x02, 0x85, 0x4f, 0xfe, 0x6e, 0x4c,
0x88, 0xd8, 0xc1, 0xd2, 0x78, 0xce, 0x87, 0xc2, 0xe6, 0x0f, 0x10, 0x4e,
0x21, 0x80, 0x8f, 0x1a, 0x80, 0xd5, 0xd0, 0xa3, 0x27, 0x8f, 0xbb, 0xd2,
0x04, 0xd6, 0xe2, 0x94, 0x2b, 0xab, 0x28, 0xcc, 0x41, 0x82, 0xf0, 0x1b,
0xe7, 0xd7, 0xac, 0x09, 0x6c, 0x1a, 0xd1, 0xf6, 0x80, 0x10, 0xda, 0x00,
0x80, 0x39, 0x31, 0x84, 0x15, 0x7e, 0xb5, 0xec, 0x17, 0xb0, 0x2a, 0x93,
0x36, 0x12, 0x64, 0xda, 0x7b, 0xa8, 0x17, 0x24, 0xb0, 0x81, 0x49, 0x02,
0x00, 0x61, 0x2b, 0x84, 0x18, 0x68, 0x81, 0x08, 0x41, 0x65, 0x69, 0x5d,
0x1b, 0x64, 0xde, 0x78, 0x6a, 0x25, 0x49, 0xa0, 0x23, 0xd8, 0x36, 0xda,
0x66, 0x9d, 0x64, 0xd8, 0x6d, 0x2b, 0x69, 0x4c, 0x82, 0xcd, 0xc6, 0x65,
0x40, 0xdb, 0x3e, 0x41, 0x48, 0xfe, 0x60, 0x01, 0xb8, 0x1d, 0xe2, 0x80,
0x49, 0x3c, 0x64, 0x26, 0xd0, 0xf6, 0xa3, 0x6d, 0x33, 0xb8, 0x56, 0xe1,
0x37, 0xae, 0xd7, 0x82, 0x26, 0x58, 0x58, 0x8e, 0x47, 0x21, 0x54, 0xf8,
0x80, 0x7f, 0xad, 0xe0, 0x46, 0xc3, 0x5c, 0x73, 0xce, 0x94, 0xcf, 0xa2,
0x17, 0x36, 0xac, 0x50, 0xf8, 0xc6, 0x75, 0x33, 0x92, 0x20, 0xe7, 0x02,
0x90, 0x14, 0x58, 0x3e, 0x9d, 0xab, 0x18, 0x04, 0xe0, 0xe3, 0xae, 0x14,
0x9c, 0xcd, 0x0a, 0x22, 0xd0, 0x07, 0xe1, 0x1b, 0xd7, 0x2f, 0xe9, 0x13,
0x30, 0x2b, 0xa1, 0xec, 0xbe, 0xa0, 0x08, 0xd0, 0x10, 0xbe, 0x8a, 0xbd,
0x7b, 0xfb, 0xec, 0xf5, 0xe7, 0x18, 0xe8, 0x93, 0xf0, 0x8d, 0xdf, 0x89,
0x21, 0xc1, 0xd3, 0x1f, 0x7f, 0x72, 0xfe, 0xcd, 0x45, 0xce, 0x01, 0xa8,
0xd6, 0x21, 0x61, 0xbe, 0x27, 0xde, 0xb6, 0x79, 0x01, 0xd3, 0x19, 0xec,
0xa3, 0xf0, 0x55, 0x44, 0x3b, 0x86, 0x7b, 0xbb, 0xcd, 0xf0, 0xf5, 0xd5,
0x6f, 0xbf, 0x88, 0xb7, 0xde, 0xfe, 0x52, 0x9f, 0x7e, 0x2a, 0xf3, 0x19,
0xb3, 0x0b, 0x6b, 0xd0, 0x62, 0xd1, 0xfa, 0x82, 0x83, 0xa3, 0xf3, 0x8b,
0x98, 0x7d, 0xee, 0xfa, 0x2e, 0x7c, 0xf1, 0xbb, 0x51, 0x55, 0xc4, 0xc9,
0xf5, 0x32, 0x3c, 0xd3, 0x89, 0x80, 0xc0, 0x6a, 0x22, 0x35, 0x21, 0x45,
0x44, 0x07, 0x0a, 0x11, 0xbc, 0xd7, 0x64, 0x0f, 0x0a, 0xb5, 0x81, 0x22,
0x81, 0x43, 0x0b, 0xac, 0x82, 0xf0, 0x55, 0x24, 0x85, 0x88, 0x82, 0x04,
0x1e, 0x2d, 0x60, 0x3c, 0xfd, 0x3a, 0x18, 0xda, 0xc0, 0xda, 0x57, 0xb6,
0x41, 0xa1, 0x2e, 0x18, 0x9f, 0x3b, 0xfc, 0x02, 0x72, 0x7b, 0x99, 0xd3,
0xd1, 0x9b, 0xe0, 0x24, 0x52, 0x85, 0xc2, 0x07, 0xf2, 0x0f, 0x2a, 0xd1,
0x21, 0xfb, 0x2c, 0x74, 0x52, 0x8a, 0x96, 0x2b, 0x08, 0xae, 0x06, 0xfa,
0x42, 0x08, 0x27, 0x09, 0x88, 0x70, 0xd1, 0x18, 0x6c, 0x22, 0xc0, 0x21,
0x42, 0xa5, 0xc2, 0x17, 0x68, 0x9b, 0x04, 0x52, 0xbb, 0x24, 0x92, 0x80,
0x44, 0x4a, 0x67, 0x5a, 0x9d, 0x45, 0x61, 0x12, 0xf4, 0xe9, 0xc9, 0x9c,
0x05, 0x8c, 0xf4, 0x6a, 0x63, 0xe5, 0xc2, 0x57, 0x21, 0x49, 0xfe, 0xf4,
0xc7, 0x9f, 0xa4, 0xad, 0xf7, 0xc1, 0x61, 0x06, 0xac, 0xe6, 0x45, 0x8c,
0x71, 0xa4, 0xc6, 0x46, 0x1e, 0x1c, 0x3e, 0x6f, 0x98, 0x04, 0xdf, 0x22,
0x5e, 0xb1, 0x3b, 0x86, 0x38, 0xfd, 0x04, 0xca, 0x24, 0x70, 0x57, 0xaf,
0x12, 0xda, 0x60, 0x3a, 0xb9, 0xea, 0x93, 0xf0, 0x01, 0xc5, 0x31, 0x7c,
0xf5, 0xdb, 0x2f, 0x41, 0x24, 0x20, 0xe0, 0xf4, 0x2d, 0xa8, 0x7d, 0x9b,
0x04, 0x42, 0x57, 0x6d, 0x8d, 0x21, 0x80, 0x35, 0x4f, 0xa0, 0x23, 0x32,
0x4a, 0x00, 0xd0, 0xab, 0x27, 0x5f, 0x85, 0x24, 0x41, 0x02, 0x62, 0x1c,
0x4b, 0xdf, 0xb8, 0x8e, 0x20, 0x27, 0xd0, 0x05, 0xb6, 0xf0, 0x05, 0x62,
0x92, 0x47, 0xdc, 0xc5, 0x0d, 0x2a, 0x84, 0xec, 0x9f, 0xf7, 0x7f, 0xff,
0x8d, 0xbd, 0xdd, 0x5d, 0x2a, 0xdc, 0x6b, 0x40, 0x68, 0x09, 0x3d, 0x29,
0x14, 0x21, 0x7c, 0xf1, 0xde, 0x5b, 0xce, 0xb7, 0x7d, 0xd9, 0x87, 0x60,
0xe1, 0x53, 0xf0, 0x69, 0x84, 0x55, 0x10, 0xbe, 0x1a, 0xb2, 0xdd, 0xf9,
0xec, 0xb3, 0xc6, 0x49, 0x09, 0x66, 0xa1, 0x81, 0x5c, 0xdb, 0xf2, 0x05,
0x95, 0x21, 0x01, 0xc8, 0xdd, 0xa9, 0x6f, 0xde, 0xdd, 0x46, 0xff, 0x28,
0x23, 0x8b, 0x08, 0xf4, 0x4b, 0xf8, 0x80, 0x43, 0xf5, 0xdb, 0x52, 0xbe,
0xa9, 0x64, 0xc8, 0x31, 0xfc, 0x2c, 0x88, 0x00, 0xea, 0xfe, 0xf4, 0x6f,
0x6f, 0xdf, 0x03, 0x58, 0x12, 0x81, 0xca, 0x10, 0xfa, 0xe0, 0x48, 0x1e,
0x85, 0xb4, 0xab, 0x46, 0x38, 0x7d, 0x00, 0x9d, 0x0c, 0x29, 0x24, 0xe8,
0x9c, 0x00, 0x00, 0xf0, 0xaf, 0xff, 0xfc, 0x0f, 0xef, 0xde, 0x2f, 0x85,
0xff, 0xfd, 0x37, 0x5f, 0x59, 0xbf, 0x10, 0x52, 0x4b, 0x58, 0x21, 0xe1,
0x53, 0x70, 0x6a, 0x86, 0x1c, 0x26, 0x21, 0xc5, 0x1c, 0x44, 0xf9, 0x00,
0x9e, 0x6b, 0xb1, 0x8a, 0x49, 0xc0, 0x92, 0x04, 0x2b, 0x2e, 0x7c, 0x0a,
0x8d, 0x7e, 0xcc, 0xb1, 0x2c, 0x5d, 0x8a, 0x26, 0x08, 0x09, 0x03, 0xa9,
0x10, 0x27, 0x49, 0x60, 0x9f, 0xa0, 0xf0, 0x81, 0xc0, 0xa1, 0xf8, 0x80,
0x7f, 0x36, 0xb3, 0x36, 0x45, 0x2d, 0x08, 0xa1, 0x79, 0x80, 0x4f, 0x45,
0x48, 0x6d, 0x63, 0x01, 0xf0, 0x9e, 0x7e, 0xd7, 0x6c, 0xe6, 0x1c, 0xda,
0x23, 0xb7, 0x40, 0x25, 0xab, 0x85, 0xc3, 0x38, 0xbe, 0x9e, 0x39, 0xbf,
0x90, 0xba, 0xfd, 0x79, 0x0f, 0xc1, 0x4e, 0xf4, 0x10, 0xaa, 0x9d, 0xa3,
0x35, 0x82, 0xfa, 0x30, 0xe7, 0xbe, 0x81, 0x86, 0xf0, 0x01, 0x60, 0x7f,
0x77, 0x1b, 0x5b, 0x9b, 0x1b, 0xd6, 0x2f, 0x69, 0xc3, 0xcd, 0xba, 0x18,
0x80, 0x5a, 0x0a, 0x8d, 0x7b, 0x3b, 0x38, 0x7c, 0x1e, 0xb2, 0x8a, 0x89,
0x5a, 0x84, 0x73, 0x25, 0x77, 0x82, 0x1f, 0xa0, 0xe8, 0xdd, 0xc3, 0x35,
0x90, 0xc2, 0x57, 0xb1, 0xb5, 0xb9, 0xe1, 0xcc, 0x1d, 0x8c, 0xce, 0x2f,
0x54, 0x6d, 0x50, 0x64, 0xaa, 0x75, 0x8b, 0x20, 0x93, 0x44, 0x81, 0xdf,
0xb7, 0xce, 0x6a, 0x4e, 0x41, 0xae, 0x4e, 0x5e, 0x00, 0xcb, 0x10, 0x11,
0x80, 0x0c, 0x13, 0x05, 0xd4, 0x70, 0xd1, 0x17, 0x1d, 0x10, 0xdb, 0x9c,
0xf6, 0x99, 0x08, 0x0d, 0x6d, 0xe6, 0x12, 0xbe, 0xad, 0xd4, 0x9b, 0x2b,
0xe3, 0x67, 0x43, 0x2b, 0x04, 0x00, 0xe0, 0xcc, 0x15, 0x70, 0x42, 0xc4,
0x15, 0xf0, 0x0d, 0xd8, 0xc2, 0x17, 0x28, 0x41, 0x82, 0xd6, 0x08, 0xf0,
0xdd, 0xd7, 0x5f, 0x52, 0xbf, 0x15, 0x54, 0x4f, 0xe8, 0xa9, 0x36, 0x68,
0x08, 0x5e, 0x0c, 0xca, 0x08, 0x19, 0xc9, 0xab, 0x13, 0xa1, 0xcd, 0x19,
0xc7, 0x59, 0x09, 0xc0, 0xfc, 0x8d, 0x05, 0xb0, 0xac, 0x29, 0x70, 0xeb,
0x09, 0x96, 0xdd, 0xaf, 0x6b, 0x22, 0x83, 0x71, 0xff, 0xd4, 0x68, 0x1c,
0x8a, 0x04, 0x7a, 0xfd, 0x5e, 0x68, 0x0a, 0x07, 0x09, 0xaa, 0x24, 0x00,
0x40, 0x93, 0xc0, 0x3a, 0x28, 0x34, 0xa6, 0xa8, 0x54, 0x21, 0x11, 0x9c,
0x0b, 0x6a, 0xd9, 0x26, 0x68, 0x0a, 0x22, 0xd8, 0x06, 0x6f, 0x50, 0x24,
0x68, 0x8b, 0x00, 0xb9, 0xa2, 0x00, 0x20, 0xa0, 0x61, 0x42, 0xf8, 0x80,
0x3f, 0x3a, 0x50, 0x21, 0xcc, 0x86, 0x96, 0x42, 0xce, 0x9a, 0x9d, 0xf4,
0xc0, 0xaa, 0xe9, 0x42, 0x46, 0x39, 0x13, 0xfb, 0x25, 0xa8, 0x6d, 0x5e,
0x08, 0x62, 0x1c, 0x1c, 0x3e, 0x6f, 0x7d, 0xc9, 0xdb, 0xae, 0x9f, 0x1e,
0xa9, 0xfe, 0x75, 0x84, 0x96, 0x97, 0x6d, 0xe3, 0x0e, 0x2d, 0x88, 0xb9,
0x4f, 0x6f, 0x3e, 0x82, 0x2b, 0x74, 0x9b, 0x26, 0x70, 0x8c, 0xd7, 0x0b,
0x31, 0xa9, 0x49, 0xc8, 0xa9, 0x01, 0x7c, 0x90, 0x37, 0xf5, 0xc5, 0xc6,
0x1d, 0x59, 0x4e, 0x06, 0x80, 0x47, 0x0f, 0xee, 0x1b, 0x27, 0xfb, 0x9c,
0xc4, 0xbd, 0x7b, 0xfb, 0x98, 0x5c, 0x8e, 0x8d, 0xb1, 0x86, 0x16, 0x42,
0x64, 0x4b, 0x2e, 0xc5, 0xcc, 0x67, 0xf0, 0x6c, 0xb6, 0x05, 0x98, 0x71,
0xbe, 0x2d, 0xeb, 0x57, 0x6d, 0x14, 0xc0, 0x81, 0x91, 0x2b, 0x78, 0x7b,
0xfb, 0x9e, 0x14, 0xbe, 0x40, 0xcc, 0xb8, 0x02, 0x0a, 0x4c, 0x2d, 0x61,
0x20, 0xd7, 0xde, 0x09, 0x2a, 0x74, 0x22, 0x94, 0xde, 0x7a, 0xb7, 0x4b,
0x0d, 0xd0, 0xc0, 0xe6, 0x9d, 0x3b, 0xfa, 0xa1, 0xe0, 0x2a, 0x19, 0xf0,
0x71, 0x04, 0xb2, 0x8b, 0x08, 0xdc, 0x11, 0xc9, 0xb9, 0x17, 0xc6, 0xd4,
0x97, 0x6a, 0x3d, 0x3e, 0x3d, 0x8b, 0xde, 0x67, 0xa9, 0x2d, 0xe4, 0xac,
0x05, 0x04, 0xe1, 0xbb, 0xaf, 0xbf, 0xb4, 0x0d, 0x28, 0x91, 0x4f, 0x82,
0xab, 0x86, 0xa0, 0x23, 0xc7, 0xac, 0xe5, 0x9c, 0xcb, 0xdd, 0x50, 0xeb,
0xf4, 0xaa, 0xc7, 0xc4, 0xf2, 0x36, 0x4a, 0xb8, 0x58, 0xa4, 0x06, 0xd2,
0xb9, 0x06, 0xb0, 0x24, 0x88, 0xac, 0x10, 0x24, 0xe0, 0x38, 0x89, 0xc2,
0x2f, 0x48, 0xc1, 0xce, 0xde, 0xdd, 0xdc, 0x9a, 0xc0, 0xa9, 0xd9, 0x4a,
0xef, 0xc8, 0xda, 0x25, 0x01, 0xb8, 0x03, 0x4a, 0xc8, 0x8e, 0xda, 0xda,
0xdc, 0x88, 0x72, 0x16, 0x63, 0xa0, 0x4e, 0x4e, 0xc9, 0x88, 0x01, 0x80,
0x85, 0xd0, 0x02, 0x6d, 0xf8, 0x17, 0x31, 0xa8, 0x29, 0x9b, 0x26, 0x40,
0x86, 0x8a, 0x21, 0xce, 0x62, 0xaa, 0x16, 0x50, 0xe1, 0x99, 0xaa, 0x06,
0x80, 0x16, 0xa6, 0x63, 0xf1, 0xcc, 0xc6, 0x0c, 0xe9, 0xd2, 0x13, 0x60,
0x8a, 0xf9, 0x00, 0x09, 0xf0, 0x4e, 0x76, 0xc8, 0xb9, 0x92, 0x89, 0xea,
0x17, 0x64, 0xda, 0x1b, 0x41, 0xb6, 0xbd, 0xb4, 0xf0, 0x81, 0x82, 0x51,
0x40, 0x08, 0x2c, 0x4f, 0xbf, 0x73, 0x84, 0x0c, 0x95, 0x36, 0x66, 0x2c,
0x71, 0x47, 0x9e, 0x6b, 0x71, 0x0e, 0xa5, 0x6d, 0x3f, 0x39, 0x7a, 0x16,
0xaa, 0xd2, 0xf5, 0xb6, 0x17, 0xd3, 0xc4, 0xd5, 0x6b, 0x00, 0x4d, 0xf8,
0x64, 0x47, 0xe9, 0xd1, 0x82, 0xa5, 0x66, 0x40, 0x0a, 0xda, 0x96, 0x23,
0xf0, 0xe4, 0x0e, 0x72, 0x08, 0x8c, 0x35, 0x75, 0xab, 0x6d, 0x54, 0x4b,
0x80, 0x47, 0x0f, 0xee, 0xb3, 0x84, 0x2f, 0x60, 0x09, 0x19, 0x43, 0x3b,
0x38, 0x46, 0x18, 0x03, 0xa0, 0xcc, 0xd6, 0x39, 0x39, 0x50, 0x23, 0x01,
0x28, 0x21, 0xb0, 0x04, 0xb3, 0xb5, 0xb9, 0x91, 0x52, 0x31, 0xb4, 0x2e,
0x7e, 0xc1, 0x45, 0x1f, 0x49, 0x50, 0xab, 0x0f, 0x90, 0x4b, 0xc5, 0x76,
0x05, 0x69, 0xd3, 0xfb, 0x46, 0x82, 0x1a, 0x35, 0x40, 0x34, 0x5c, 0xa1,
0x62, 0x20, 0x06, 0x40, 0x70, 0x0d, 0x21, 0x5a, 0x73, 0x95, 0x44, 0xad,
0x1a, 0x20, 0x08, 0x84, 0xe0, 0x59, 0x1d, 0x9f, 0x61, 0x81, 0xeb, 0xa8,
0xdf, 0xad, 0x09, 0xbd, 0x6b, 0x30, 0x81, 0x90, 0x01, 0x21, 0x8d, 0x15,
0xcf, 0x19, 0x04, 0x08, 0x5e, 0x71, 0xa3, 0x6f, 0x58, 0x99, 0x1b, 0x61,
0x22, 0xa6, 0xc6, 0xde, 0xe5, 0x88, 0xa3, 0xce, 0xb1, 0x52, 0x37, 0xc3,
0x44, 0x15, 0x09, 0x98, 0x5a, 0xf0, 0x7f, 0x84, 0x1d, 0xed, 0xfe, 0xb1,
0x2a, 0x47, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
0x42, 0x60, 0x82
};
unsigned int icon_png_len = 3699;

View File

@@ -1,117 +0,0 @@
#include "midi.h"
#include <stdio.h>
#include <poll.h>
#include <stdatomic.h>
#include <alloca.h>
extern atomic_int gRunning;
int midiInit(MidiState *m, Synth *synth)
{
if (snd_seq_open(&m->seq, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_NONBLOCK, 0) < 0) {
fprintf(stderr, "Failed to open ALSA sequencer\n");
return 0;
}
snd_seq_nonblock(m->seq, 1);
snd_seq_set_client_name(m->seq, "soundThing");
m->client = snd_seq_client_id(m->seq);
m->port = snd_seq_create_simple_port(m->seq, "MIDI In",
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION);
m->synth = synth;
return 1;
}
void midiListInputs(MidiState *m)
{
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_port_info_alloca(&pinfo);
printf("\nAvailable MIDI inputs:\n");
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(m->seq, cinfo) >= 0) {
int client = snd_seq_client_info_get_client(cinfo);
if (client == m->client) continue;
snd_seq_port_info_set_client(pinfo, client);
snd_seq_port_info_set_port(pinfo, -1);
while (snd_seq_query_next_port(m->seq, pinfo) >= 0) {
unsigned int caps = snd_seq_port_info_get_capability(pinfo);
if (caps & SND_SEQ_PORT_CAP_READ && caps & SND_SEQ_PORT_CAP_SUBS_READ) {
printf(" [%d:%d] %s — %s\n",
client,
snd_seq_port_info_get_port(pinfo),
snd_seq_client_info_get_name(cinfo),
snd_seq_port_info_get_name(pinfo));
}
}
}
}
void midiConnect(MidiState *m, int srcClient, int srcPort)
{
snd_seq_port_subscribe_t *sub;
snd_seq_addr_t sender, dest;
sender.client = srcClient;
sender.port = srcPort;
dest.client = m->client;
dest.port = m->port;
snd_seq_port_subscribe_alloca(&sub);
snd_seq_port_subscribe_set_sender(sub, &sender);
snd_seq_port_subscribe_set_dest(sub, &dest);
snd_seq_subscribe_port(m->seq, sub);
printf("Connected [%d:%d] to Cricket\n", srcClient, srcPort);
}
void midiClose(MidiState *m)
{
snd_seq_close(m->seq);
}
void *midiThread(void *arg)
{
MidiState *m = (MidiState *)arg;
struct pollfd pfd;
snd_seq_poll_descriptors(m->seq, &pfd, 1, POLLIN);
while (gRunning) {
int ready = poll(&pfd, 1, 50);
if (ready <= 0) continue;
snd_seq_event_t *ev = NULL;
while (snd_seq_event_input(m->seq, &ev) >= 0 && ev) {
switch (ev->type) {
case SND_SEQ_EVENT_NOTEON:
if (ev->data.note.velocity == 0)
synthNoteOff(m->synth, ev->data.note.note);
else
synthNoteOn(m->synth, ev->data.note.note);
break;
case SND_SEQ_EVENT_NOTEOFF:
synthNoteOff(m->synth, ev->data.note.note);
break;
case SND_SEQ_EVENT_CONTROLLER:
// This are controller parameter changes.
// Map the Mod Wheel to PWM:
if (ev->data.control.param == 1)
m->synth->dutyCycle = 0.05f + (ev->data.control.value / 127.0f) * 0.90f;
// This naively maps parameter 70 to the waveform in a way that does not play so nice with real pots.
if (ev->data.control.param == 70)
m->synth->waveform = ev->data.control.value % WAVE_COUNT;
break;
case SND_SEQ_EVENT_PITCHBEND:
m->synth->pitchBend = ev->data.control.value / 8191.0f;
break;
}
snd_seq_free_event(ev);
ev = NULL;
}
}
return NULL;
}

157
source/midi_linux.c Normal file
View File

@@ -0,0 +1,157 @@
#include "midi.h"
#include <stdio.h>
#include <poll.h>
#include <stdatomic.h>
#include <alloca.h>
extern atomic_int gRunning;
int midiInit(MidiState *m, Synth *synth)
{
if (snd_seq_open(&m->seq, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_NONBLOCK, 0) < 0) {
fprintf(stderr, "Failed to open ALSA sequencer\n");
return 0;
}
snd_seq_nonblock(m->seq, 1);
snd_seq_set_client_name(m->seq, "soundThing");
m->client = snd_seq_client_id(m->seq);
m->port = snd_seq_create_simple_port(m->seq, "MIDI In",
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION);
m->synth = synth;
m->connectedClient = -1;
m->connectedPort = -1;
m->inputCount = 0;
atomic_store(&m->midiLearnMode, 0);
atomic_store(&m->midiLearnCC, -1);
for (int i = 0; i < 128; i++) m->ccMappings[i].active = 0;
return 1;
}
void midiScanInputs(MidiState *m)
{
m->inputCount = 0;
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_port_info_alloca(&pinfo);
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(m->seq, cinfo) >= 0) {
int client = snd_seq_client_info_get_client(cinfo);
if (client == m->client) continue;
snd_seq_port_info_set_client(pinfo, client);
snd_seq_port_info_set_port(pinfo, -1);
while (snd_seq_query_next_port(m->seq, pinfo) >= 0) {
if (m->inputCount >= MIDI_MAX_INPUTS) break;
unsigned int caps = snd_seq_port_info_get_capability(pinfo);
if ((caps & SND_SEQ_PORT_CAP_READ) && (caps & SND_SEQ_PORT_CAP_SUBS_READ)) {
MidiInputInfo *info = &m->inputs[m->inputCount++];
info->client = client;
info->port = snd_seq_port_info_get_port(pinfo);
snprintf(info->clientName, sizeof(info->clientName), "%s",
snd_seq_client_info_get_name(cinfo));
snprintf(info->portName, sizeof(info->portName), "%s",
snd_seq_port_info_get_name(pinfo));
}
}
if (m->inputCount >= MIDI_MAX_INPUTS) break;
}
}
void midiDevDisconnect(MidiState *m)
{
if (m->connectedClient < 0) return;
snd_seq_port_subscribe_t *sub;
snd_seq_addr_t sender, dest;
sender.client = m->connectedClient;
sender.port = m->connectedPort;
dest.client = m->client;
dest.port = m->port;
snd_seq_port_subscribe_alloca(&sub);
snd_seq_port_subscribe_set_sender(sub, &sender);
snd_seq_port_subscribe_set_dest(sub, &dest);
snd_seq_unsubscribe_port(m->seq, sub);
m->connectedClient = -1;
m->connectedPort = -1;
}
void midiDevConnect(MidiState *m, int srcClient, int srcPort)
{
midiDevDisconnect(m);
snd_seq_port_subscribe_t *sub;
snd_seq_addr_t sender, dest;
sender.client = srcClient;
sender.port = srcPort;
dest.client = m->client;
dest.port = m->port;
snd_seq_port_subscribe_alloca(&sub);
snd_seq_port_subscribe_set_sender(sub, &sender);
snd_seq_port_subscribe_set_dest(sub, &dest);
snd_seq_subscribe_port(m->seq, sub);
m->connectedClient = srcClient;
m->connectedPort = srcPort;
}
void midiClose(MidiState *m)
{
midiDevDisconnect(m);
snd_seq_close(m->seq);
}
void *midiThread(void *arg)
{
MidiState *m = (MidiState *)arg;
struct pollfd pfd;
snd_seq_poll_descriptors(m->seq, &pfd, 1, POLLIN);
while (gRunning) {
int ready = poll(&pfd, 1, 50);
if (ready <= 0) continue;
snd_seq_event_t *ev = NULL;
while (snd_seq_event_input(m->seq, &ev) >= 0 && ev) {
switch (ev->type) {
case SND_SEQ_EVENT_NOTEON:
if (ev->data.note.velocity == 0)
synthNoteOff(m->synth, ev->data.note.note);
else
synthNoteOn(m->synth, ev->data.note.note);
break;
case SND_SEQ_EVENT_NOTEOFF:
synthNoteOff(m->synth, ev->data.note.note);
break;
case SND_SEQ_EVENT_CONTROLLER: {
int cc = ev->data.control.param;
int val = ev->data.control.value;
if (cc < 128) {
if (atomic_load(&m->midiLearnMode))
atomic_store(&m->midiLearnCC, cc);
if (m->ccMappings[cc].active) {
float t = (float)val / 127.0f;
*m->ccMappings[cc].valuePtr =
m->ccMappings[cc].min +
t * (m->ccMappings[cc].max - m->ccMappings[cc].min);
}
}
break;
}
case SND_SEQ_EVENT_PITCHBEND:
m->synth->pitchBend = ev->data.control.value / 8191.0f;
break;
}
snd_seq_free_event(ev);
ev = NULL;
}
}
return NULL;
}

108
source/midi_windows.c Normal file
View File

@@ -0,0 +1,108 @@
#include "midi.h"
#include <windows.h>
#include <mmsystem.h>
#include <stdatomic.h>
#include <stdio.h>
extern atomic_int gRunning;
static void CALLBACK midiCallbackWin32(HMIDIIN hIn, UINT msg, DWORD_PTR instance,
DWORD_PTR param1, DWORD_PTR param2)
{
(void)hIn; (void)param2;
if (msg != MIM_DATA) return;
MidiState *m = (MidiState *)instance;
BYTE status = (BYTE)( param1 & 0xFF);
BYTE data1 = (BYTE)((param1 >> 8) & 0xFF);
BYTE data2 = (BYTE)((param1 >> 16) & 0xFF);
BYTE type = status & 0xF0;
if (type == 0x90 && data2 > 0) {
synthNoteOn(m->synth, data1);
} else if (type == 0x80 || (type == 0x90 && data2 == 0)) {
synthNoteOff(m->synth, data1);
} else if (type == 0xB0) {
int cc = data1, val = data2;
if (cc < 128) {
if (atomic_load(&m->midiLearnMode))
atomic_store(&m->midiLearnCC, cc);
if (m->ccMappings[cc].active) {
float t = (float)val / 127.0f;
*m->ccMappings[cc].valuePtr =
m->ccMappings[cc].min + t * (m->ccMappings[cc].max - m->ccMappings[cc].min);
}
}
} else if (type == 0xE0) {
int pb = (data2 << 7) | data1; // 0..16383, centre = 8192
m->synth->pitchBend = (pb - 8192) / 8191.0f;
}
}
int midiInit(MidiState *m, Synth *synth)
{
m->synth = synth;
m->hMidiIn = NULL;
m->connectedClient = -1;
m->connectedPort = -1;
m->inputCount = 0;
atomic_store(&m->midiLearnMode, 0);
atomic_store(&m->midiLearnCC, -1);
for (int i = 0; i < 128; i++) m->ccMappings[i].active = 0;
return 1;
}
void midiScanInputs(MidiState *m)
{
m->inputCount = 0;
UINT n = midiInGetNumDevs();
for (UINT i = 0; i < n && m->inputCount < MIDI_MAX_INPUTS; i++) {
MIDIINCAPSA caps;
if (midiInGetDevCapsA(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
MidiInputInfo *info = &m->inputs[m->inputCount++];
info->client = (int)i;
info->port = 0;
snprintf(info->clientName, sizeof(info->clientName), "%s", caps.szPname);
snprintf(info->portName, sizeof(info->portName), "%s", caps.szPname);
}
}
}
void midiDevDisconnect(MidiState *m)
{
if (m->hMidiIn) {
midiInStop((HMIDIIN)m->hMidiIn);
midiInClose((HMIDIIN)m->hMidiIn);
m->hMidiIn = NULL;
}
m->connectedClient = -1;
m->connectedPort = -1;
}
void midiDevConnect(MidiState *m, int srcClient, int srcPort)
{
(void)srcPort;
midiDevDisconnect(m);
HMIDIIN hIn = NULL;
if (midiInOpen(&hIn, (UINT)srcClient, (DWORD_PTR)midiCallbackWin32,
(DWORD_PTR)m, CALLBACK_FUNCTION) == MMSYSERR_NOERROR) {
midiInStart(hIn);
m->hMidiIn = hIn;
m->connectedClient = srcClient;
m->connectedPort = 0;
}
}
void midiClose(MidiState *m)
{
midiDevDisconnect(m);
}
void *midiThread(void *arg)
{
// WinMM delivers MIDI events via midiCallbackWin32 on its own MM thread.
// This function exists only to satisfy the pthread_create call in soundThing.c.
(void)arg;
while (gRunning) Sleep(50);
return NULL;
}

288
source/patch.c Normal file
View File

@@ -0,0 +1,288 @@
#define _POSIX_C_SOURCE 200809L
#include "patch.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#ifdef _WIN32
# include <direct.h>
# include <sys/stat.h>
# define MAKE_DIR(p) _mkdir(p)
#else
# include <sys/stat.h>
# define MAKE_DIR(p) mkdir(p, 0755)
#endif
// ------------------------------------------------------------------ HELPERS
static const char *findValue(const char *json, const char *key)
{
char pattern[PATCH_NAME_LEN + 4];
snprintf(pattern, sizeof(pattern), "\"%s\"", key);
const char *p = strstr(json, pattern);
if (!p) return NULL;
p += strlen(pattern);
while (*p && (*p == ' ' || *p == ':' || *p == '\t' || *p == '\n' || *p == '\r')) p++;
return p;
}
static int readInt(const char *json, const char *key, int *out)
{
const char *p = findValue(json, key);
if (!p) return 0;
*out = (int)strtol(p, NULL, 10);
return 1;
}
static int readFloat(const char *json, const char *key, float *out)
{
const char *p = findValue(json, key);
if (!p) return 0;
*out = strtof(p, NULL);
return 1;
}
// ------------------------------------------------------------------ SAVE
int patchSave(Synth *s, const char *path)
{
MAKE_DIR("patches");
FILE *f = fopen(path, "w");
if (!f) return 0;
fprintf(f, "{\n");
for (int o = 0; o < OSC_COUNT; o++) {
Oscillator *osc = &s->voices[0].oscillators[o];
fprintf(f, " \"osc%d_waveform\": %d,\n", o, (int)osc->waveform);
fprintf(f, " \"osc%d_dutyCycle\": %f,\n", o, osc->dutyCycle);
fprintf(f, " \"osc%d_detune\": %f,\n", o, osc->detune);
fprintf(f, " \"osc%d_gain\": %f,\n", o, osc->gain);
fprintf(f, " \"osc%d_active\": %d,\n", o, osc->active);
fprintf(f, " \"osc%d_octave\": %d,\n", o, osc->octave);
for (int m = 0; m < 3; m++)
fprintf(f, " \"osc%d_modRouting%d\": %d,\n", o, m, osc->modRouting[m]);
for (int m = 0; m < 3; m++)
fprintf(f, " \"osc%d_modDepth%d\": %f,\n", o, m, osc->modDepth[m]);
}
Envelope *ae = &s->voices[0].ampEnv;
fprintf(f, " \"ampEnv_attack\": %f,\n", ae->attackSec);
fprintf(f, " \"ampEnv_decay\": %f,\n", ae->decaySec);
fprintf(f, " \"ampEnv_sustain\": %f,\n", ae->sustainLevel);
fprintf(f, " \"ampEnv_release\": %f,\n", ae->releaseSec);
Envelope *me = &s->voices[0].modEnv;
fprintf(f, " \"modEnv_attack\": %f,\n", me->attackSec);
fprintf(f, " \"modEnv_decay\": %f,\n", me->decaySec);
fprintf(f, " \"modEnv_sustain\": %f,\n", me->sustainLevel);
fprintf(f, " \"modEnv_release\": %f,\n", me->releaseSec);
for (int l = 0; l < LFO_COUNT; l++) {
LFO *lfo = &s->lfos[l];
fprintf(f, " \"lfo%d_rate\": %f,\n", l, lfo->rate);
fprintf(f, " \"lfo%d_waveform\": %d,\n", l, (int)lfo->waveform);
fprintf(f, " \"lfo%d_active\": %d,\n", l, lfo->active);
}
Filter *flt = &s->voices[0].filter;
fprintf(f, " \"filter_cutoff\": %f,\n", flt->cutoff);
fprintf(f, " \"filter_resonance\": %f,\n", flt->resonance);
fprintf(f, " \"filter_type\": %d,\n", (int)flt->type);
fprintf(f, " \"filter_active\": %d,\n", flt->active);
fprintf(f, " \"filter_modRouting\": %d,\n", flt->modRouting);
fprintf(f, " \"filter_modDepth\": %f,\n", flt->modDepth);
fprintf(f, " \"filter_resModRouting\": %d,\n", flt->resModRouting);
fprintf(f, " \"filter_resModDepth\": %f,\n", flt->resModDepth);
fprintf(f, " \"master_volume\": %f,\n", s->volume);
fprintf(f, " \"master_pitchBendRange\": %f\n", s->pitchBendRange);
fprintf(f, "}\n");
fclose(f);
return 1;
}
// ------------------------------------------------------------------ LOAD
int patchLoad(Synth *s, const char *path)
{
FILE *f = fopen(path, "r");
if (!f) return 0;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char *buf = (char *)malloc((size_t)size + 1);
if (!buf) { fclose(f); return 0; }
size_t got = fread(buf, 1, (size_t)size, f);
buf[got] = '\0';
fclose(f);
int iv;
float fv;
char key[PATCH_NAME_LEN];
for (int o = 0; o < OSC_COUNT; o++) {
Oscillator *osc = &s->voices[0].oscillators[o];
snprintf(key, sizeof(key), "osc%d_waveform", o);
if (readInt(buf, key, &iv) && iv >= 0 && iv < WAVE_COUNT)
osc->waveform = (Waveform)iv;
snprintf(key, sizeof(key), "osc%d_dutyCycle", o);
if (readFloat(buf, key, &fv)) osc->dutyCycle = fv;
snprintf(key, sizeof(key), "osc%d_detune", o);
if (readFloat(buf, key, &fv)) osc->detune = fv;
snprintf(key, sizeof(key), "osc%d_gain", o);
if (readFloat(buf, key, &fv)) osc->gain = fv;
snprintf(key, sizeof(key), "osc%d_active", o);
if (readInt(buf, key, &iv)) osc->active = iv;
snprintf(key, sizeof(key), "osc%d_octave", o);
if (readInt(buf, key, &iv) && iv >= -2 && iv <= 2) osc->octave = iv;
for (int m = 0; m < 3; m++) {
snprintf(key, sizeof(key), "osc%d_modRouting%d", o, m);
if (readInt(buf, key, &iv)) osc->modRouting[m] = iv;
snprintf(key, sizeof(key), "osc%d_modDepth%d", o, m);
if (readFloat(buf, key, &fv)) osc->modDepth[m] = fv;
}
}
Envelope *ae = &s->voices[0].ampEnv;
if (readFloat(buf, "ampEnv_attack", &fv)) ae->attackSec = fv;
if (readFloat(buf, "ampEnv_decay", &fv)) ae->decaySec = fv;
if (readFloat(buf, "ampEnv_sustain", &fv)) ae->sustainLevel = fv;
if (readFloat(buf, "ampEnv_release", &fv)) ae->releaseSec = fv;
Envelope *me = &s->voices[0].modEnv;
if (readFloat(buf, "modEnv_attack", &fv)) me->attackSec = fv;
if (readFloat(buf, "modEnv_decay", &fv)) me->decaySec = fv;
if (readFloat(buf, "modEnv_sustain", &fv)) me->sustainLevel = fv;
if (readFloat(buf, "modEnv_release", &fv)) me->releaseSec = fv;
for (int l = 0; l < LFO_COUNT; l++) {
LFO *lfo = &s->lfos[l];
snprintf(key, sizeof(key), "lfo%d_rate", l);
if (readFloat(buf, key, &fv)) lfo->rate = fv;
snprintf(key, sizeof(key), "lfo%d_waveform", l);
if (readInt(buf, key, &iv) && iv >= 0 && iv < WAVE_COUNT)
lfo->waveform = (Waveform)iv;
snprintf(key, sizeof(key), "lfo%d_active", l);
if (readInt(buf, key, &iv)) lfo->active = iv;
lfo->phase = 0.0f;
lfo->noisePhase = 0.0f;
}
Filter *flt = &s->voices[0].filter;
if (readFloat(buf, "filter_cutoff", &fv)) flt->cutoff = fv;
if (readFloat(buf, "filter_resonance", &fv)) flt->resonance = fv;
if (readInt (buf, "filter_type", &iv) && iv >= 0 && iv < FILTER_COUNT)
flt->type = (FilterType)iv;
if (readInt (buf, "filter_active", &iv)) flt->active = iv;
if (readInt (buf, "filter_modRouting", &iv)) flt->modRouting = iv;
if (readFloat(buf, "filter_modDepth", &fv)) flt->modDepth = fv;
if (readInt (buf, "filter_resModRouting",&iv)) flt->resModRouting = iv;
if (readFloat(buf, "filter_resModDepth", &fv)) flt->resModDepth = fv;
flt->low = 0.0f;
flt->band = 0.0f;
if (readFloat(buf, "master_volume", &fv)) s->volume = fv;
if (readFloat(buf, "master_pitchBendRange", &fv)) s->pitchBendRange = fv;
free(buf);
return 1;
}
// ------------------------------------------------------------------ FAVORITES
int patchLoadFavs(char (*favs)[PATCH_NAME_LEN], int maxFavs)
{
FILE *f = fopen("patches/favorites.txt", "r");
if (!f) return 0;
int count = 0;
while (count < maxFavs && fgets(favs[count], PATCH_NAME_LEN, f)) {
size_t len = strlen(favs[count]);
if (len > 0 && favs[count][len - 1] == '\n') favs[count][len - 1] = '\0';
if (favs[count][0] != '\0') count++;
}
fclose(f);
return count;
}
int patchSaveFavs(char (*favs)[PATCH_NAME_LEN], int favCount)
{
MAKE_DIR("patches");
FILE *f = fopen("patches/favorites.txt", "w");
if (!f) return 0;
for (int i = 0; i < favCount; i++)
fprintf(f, "%s\n", favs[i]);
fclose(f);
return 1;
}
// ------------------------------------------------------------------ SCAN
static int cmpStrings(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
int patchScanFiles(char (*files)[PATCH_NAME_LEN], int maxFiles)
{
int count = 0;
DIR *d = opendir("patches");
if (!d) return 0;
struct dirent *ent;
while ((ent = readdir(d)) != NULL && count < maxFiles) {
const char *name = ent->d_name;
size_t len = strlen(name);
if (len > 5 && strcmp(name + len - 5, ".json") == 0) {
snprintf(files[count], PATCH_NAME_LEN, "%.*s", (int)(len - 5), name);
count++;
}
}
closedir(d);
qsort(files, (size_t)count, PATCH_NAME_LEN, cmpStrings);
return count;
}
int patchScanDir(const char *relPath,
char (*files)[PATCH_NAME_LEN], int maxFiles,
char (*dirs)[PATCH_NAME_LEN], int maxDirs, int *outDirCount)
{
char scanPath[512];
if (relPath && relPath[0])
snprintf(scanPath, sizeof(scanPath), "patches/%s", relPath);
else
snprintf(scanPath, sizeof(scanPath), "patches");
MAKE_DIR(scanPath);
int fc = 0, dc = 0;
DIR *d = opendir(scanPath);
if (!d) { *outDirCount = 0; return 0; }
struct dirent *ent;
while ((ent = readdir(d)) != NULL) {
const char *name = ent->d_name;
if (name[0] == '.') continue;
size_t len = strlen(name);
char full[1024];
snprintf(full, sizeof(full), "%s/%s", scanPath, name);
struct stat st;
if (stat(full, &st) != 0) continue;
if (S_ISDIR(st.st_mode)) {
if (dc < maxDirs)
snprintf(dirs[dc++], PATCH_NAME_LEN, "%s", name);
} else if (len > 5 && strcmp(name + len - 5, ".json") == 0) {
if (fc < maxFiles)
snprintf(files[fc++], PATCH_NAME_LEN, "%.*s", (int)(len - 5), name);
}
}
closedir(d);
qsort(files, (size_t)fc, PATCH_NAME_LEN, cmpStrings);
qsort(dirs, (size_t)dc, PATCH_NAME_LEN, cmpStrings);
*outDirCount = dc;
return fc;
}

29
source/platform.c Normal file
View File

@@ -0,0 +1,29 @@
#define _POSIX_C_SOURCE 200809L
/* Isolated from raylib.h to avoid Rectangle/CloseWindow/ShowCursor conflicts
with windows.h on Windows cross-compile targets. */
#ifdef _WIN32
# include <windows.h>
# include <direct.h>
#else
# include <unistd.h>
# include <libgen.h>
#endif
#include <string.h>
#include "platform.h"
void chdirToExeDir(void)
{
char path[1024];
#ifdef _WIN32
DWORD len = GetModuleFileNameA(NULL, path, (DWORD)sizeof(path));
if (!len) return;
char *last = strrchr(path, '\\');
if (!last) last = strrchr(path, '/');
if (last) { *last = '\0'; _chdir(path); }
#else
ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (len <= 0) return;
path[len] = '\0';
if (chdir(dirname(path)) != 0) { }
#endif
}

View File

@@ -1,60 +1,60 @@
#define _POSIX_C_SOURCE 200809L
#include "raylib.h"
#include <stdio.h>
#include <string.h>
#include <stdatomic.h>
#include <pthread.h>
#include <alloca.h>
#include <alsa/asoundlib.h>
#include "raylib.h"
#include "synth.h"
#include "midi.h"
#include "ui.h"
#include "config.h"
#include "icon_data.h"
#include "platform.h"
#define LOGICAL_WIDTH 1020
#define LOGICAL_HEIGHT 710
#define BORDER_WIDTH 8
atomic_int gRunning = 1;
static Synth gSynth = {0};
static MidiState gMidi = {0};
static UIState gUI = {0};
static void AudioOutputCallback(void *buffer, unsigned int frames)
{
synthFillBuffer(&gSynth, (int16_t *)buffer, (int)frames);
}
static void drawWaveform(Waveform w, float dutyCycle, int x, int y, int width, int height)
{
int steps = width;
for (int i = 0; i < steps - 1; i++) {
float phase0 = (float)i / steps;
float phase1 = (float)(i + 1) / steps;
float s0 = waveformSample(w, phase0, dutyCycle);
float s1 = waveformSample(w, phase1, dutyCycle);
int cx = x + i;
int cy = y + (int)((1.0f - (s0 * 0.5f + 0.5f)) * height);
int nx = x + i + 1;
int ny = y + (int)((1.0f - (s1 * 0.5f + 0.5f)) * height);
DrawLine(cx, cy, nx, ny, GREEN);
}
DrawRectangleLines(x, y, width, height, DARKGRAY);
}
int main(void)
{
chdirToExeDir();
const int sampleRate = 48000;
if (!midiInit(&gMidi, &gSynth)) return 1;
midiListInputs(&gMidi);
int srcClient, srcPort;
printf("\nEnter client and port to connect (e.g. '20 0'), or -1 -1 to skip: ");
if (scanf("%d %d", &srcClient, &srcPort) == 2 && srcClient != -1)
midiConnect(&gMidi, srcClient, srcPort);
midiScanInputs(&gMidi);
pthread_t midiTid;
pthread_create(&midiTid, NULL, midiThread, &gMidi);
synthInit(&gSynth, (float)sampleRate);
InitWindow(800, 450, "SoundThing");
// Window setup
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(LOGICAL_WIDTH + 2 * BORDER_WIDTH, LOGICAL_HEIGHT + 2 * BORDER_WIDTH, "SoundThing");
{
Image appIcon = LoadImageFromMemory(".png", icon_png, (int)icon_png_len);
SetWindowIcon(appIcon);
UnloadImage(appIcon);
}
// Camera2D setup
Camera2D ui_cam = { 0 };
ui_cam.zoom = 1.0f;
recomputeViewPort(&ui_cam, LOGICAL_WIDTH, LOGICAL_HEIGHT, BORDER_WIDTH);
// Audio device setup
InitAudioDevice();
SetAudioStreamBufferSizeDefault(1024);
@@ -63,34 +63,141 @@ int main(void)
PlayAudioStream(stream);
SetTargetFPS(120);
uiInit(&gUI, &gMidi, &ui_cam);
// Auto-connect to last used MIDI device if still available
{
char lastDev[CONFIG_NAME_LEN];
if (configLoadLastDevice(lastDev, sizeof(lastDev))) {
for (int i = 0; i < gMidi.inputCount; i++) {
if (strcmp(gMidi.inputs[i].clientName, lastDev) == 0) {
midiDevConnect(&gMidi, gMidi.inputs[i].client, gMidi.inputs[i].port);
uiLoadCcMappingsForDevice(&gUI, lastDev);
break;
}
}
}
}
// Layout constants
const float pad = 10.0f;
const float oscW = 220.0f;
const float oscH = 340.0f;
const float envW = 180.0f;
const float envH = 280.0f;
const float masterW = 180.0f;
const float masterH = 360.0f;
const float lfoW = 180.0f;
const float lfoH = 155.0f;
const float filterW = 200.0f;
const float filterH = 300.0f;
while (!WindowShouldClose()) {
if (IsKeyPressed(KEY_UP))
gSynth.waveform = (gSynth.waveform + 1) % WAVE_COUNT;
if (IsKeyPressed(KEY_DOWN))
gSynth.waveform = (gSynth.waveform + WAVE_COUNT - 1) % WAVE_COUNT;
// Sync voice settings from voice 0
synthSyncVoices(&gSynth);
BeginDrawing();
ClearBackground(BLACK);
BeginMode2D(ui_cam);
if(IsWindowResized()) {
recomputeViewPort(&ui_cam, LOGICAL_WIDTH, LOGICAL_HEIGHT, BORDER_WIDTH);
}
ClearBackground((Color){ 189, 168, 131, 255 }); // tan background
drawWaveform(gSynth.waveform, gSynth.dutyCycle, 20, 120, 400, 150);
// // Oscillator panels — left side, stacked vertically
// uiOscillatorPanel(&gUI, 0,
// padding, padding,
// oscW, oscH,
// &gSynth.voices[0].oscillators[0], "Oscillator 0");
//
// uiOscillatorPanel(&gUI, 100,
// padding, padding + oscH + padding,
// oscW, oscH,
// &gSynth.voices[0].oscillators[1], "Oscillator 1");
//
// // Envelope panels — to the right of oscillators
// float envX = padding + oscW + padding;
// uiEnvelopePanel(&gUI, 200,
// envX, padding,
// envW, envH,
// &gSynth.voices[0].ampEnv, "Amp Envelope");
//
// uiEnvelopePanel(&gUI, 250,
// envX, padding + envH + padding,
// envW, envH,
// &gSynth.voices[0].modEnv, "Mod Envelope");
//
// // Master panel — to the right of envelopes
// float masterX = envX + envW + padding;
// uiMasterPanel(&gUI,
// masterX, padding,
// masterW, masterH,
// &gSynth);
DrawText("SoundThing", 20, 20, 24, RAYWHITE);
DrawText(TextFormat("Waveform: %s (UP/DOWN to change)", waveformName(gSynth.waveform)),
20, 55, 20, RAYWHITE);
DrawText(TextFormat("MIDI: client %d port %d", gMidi.client, gMidi.port),
20, 90, 20, GRAY);
if (gSynth.waveform == WAVE_PULSE)
DrawText(TextFormat("Duty Cycle: %.2f", gSynth.dutyCycle), 20, 280, 20, GREEN);
// Left column — oscillator panels stacked vertically
float oscX = pad;
uiOscillatorPanel(&gUI, 0,
oscX, pad,
oscW, oscH,
&gSynth.voices[0].oscillators[0], "Oscillator 0");
uiOscillatorPanel(&gUI, 100,
oscX, pad + oscH + pad,
oscW, oscH,
&gSynth.voices[0].oscillators[1], "Oscillator 1");
// Middle column — envelope panels stacked vertically
float envX = pad + oscW + pad;
uiEnvelopePanel(&gUI, 200,
envX, pad,
envW, envH,
&gSynth.voices[0].ampEnv, "Envelope 0 - Amp");
uiEnvelopePanel(&gUI, 250,
envX, pad + envH + pad,
envW, envH,
&gSynth.voices[0].modEnv, "Envelope 1 - Mod");
// LFO column
float lfoX = pad + oscW + pad + envW + pad;
uiLfoPanel(&gUI, 500,
lfoX, pad,
lfoW, lfoH,
&gSynth.lfos[0], "LFO 0");
uiLfoPanel(&gUI, 600,
lfoX, pad + lfoH + pad,
lfoW, lfoH,
&gSynth.lfos[1], "LFO 1");
// Filter panel
float filterX = lfoX + lfoW + pad;
uiFilterPanel(&gUI,
filterX, pad,
filterW, filterH,
&gSynth.voices[0].filter, "Filter");
// Master panel — rightmost
float masterX = filterX + filterW + pad;
uiMasterPanel(&gUI,
masterX, pad,
masterW, masterH,
&gSynth);
// Floating overlays — drawn last, each one on top of the previous
uiMidiMenu(&gUI, (LOGICAL_WIDTH - 420) * 0.5f, 100.0f, 420.0f, &gMidi);
uiPatchMenu(&gUI, (LOGICAL_WIDTH - 420) * 0.5f, 80.0f, 420.0f, &gSynth);
uiAboutMenu(&gUI, (LOGICAL_WIDTH - 420) * 0.5f, 160.0f, 420.0f);
EndDrawing();
}
gRunning = 0;
StopAudioStream(stream);
UnloadAudioStream(stream);
CloseAudioDevice();
CloseWindow();
pthread_join(midiTid, NULL);
uiClose(&gUI);
CloseWindow();
midiClose(&gMidi);
return 0;
}

49
source/sprites_data.c Normal file
View File

@@ -0,0 +1,49 @@
unsigned char sprites_png[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x10,
0x08, 0x06, 0x00, 0x00, 0x00, 0x92, 0x9e, 0xb8, 0x35, 0x00, 0x00, 0x00,
0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
0x01, 0xd8, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xed, 0x58, 0xc1, 0x91,
0xc2, 0x30, 0x0c, 0xdc, 0x30, 0x14, 0xa0, 0x12, 0x5c, 0x82, 0x4b, 0xa0,
0x83, 0xb8, 0x84, 0x94, 0x40, 0x29, 0xbe, 0x0e, 0x28, 0x21, 0xa5, 0xa8,
0x04, 0x4a, 0x50, 0x07, 0xb9, 0x07, 0xe3, 0xa0, 0x18, 0xc5, 0x36, 0x1c,
0x30, 0xc7, 0x5d, 0x76, 0x26, 0x0f, 0xbc, 0x96, 0xac, 0xac, 0x14, 0x45,
0xa4, 0xc3, 0x87, 0x83, 0x88, 0xa6, 0x57, 0xfa, 0x17, 0x91, 0xae, 0xf5,
0x4c, 0x6b, 0xef, 0x1e, 0x00, 0x98, 0x79, 0x35, 0x48, 0xef, 0x7d, 0xa7,
0xf9, 0x10, 0x02, 0xc6, 0x71, 0x5c, 0xf0, 0xce, 0xb9, 0x09, 0xc0, 0x62,
0x7d, 0xcd, 0x5e, 0xfb, 0x01, 0x80, 0xf3, 0xf9, 0x6c, 0xf2, 0x35, 0xfb,
0xe4, 0x43, 0x44, 0xe0, 0xbd, 0x37, 0x6d, 0x99, 0x39, 0xf9, 0x68, 0xe2,
0x87, 0x61, 0x00, 0x00, 0x9c, 0x4e, 0xa7, 0x05, 0xaf, 0x41, 0x44, 0x53,
0xc1, 0xdf, 0x94, 0x8b, 0xbc, 0xd7, 0xc1, 0x02, 0xb6, 0x48, 0x7a, 0xcf,
0x38, 0x8e, 0x37, 0x22, 0x27, 0x3b, 0x6b, 0xbd, 0xe6, 0xc7, 0xe2, 0x6a,
0x76, 0xfa, 0xcc, 0xc3, 0xe1, 0x00, 0xe0, 0x22, 0x0e, 0x11, 0x01, 0x00,
0x44, 0x64, 0x16, 0x29, 0xa1, 0xc6, 0x13, 0xd1, 0xec, 0x9b, 0x88, 0x20,
0x22, 0x37, 0xe7, 0x97, 0xc4, 0x05, 0x2e, 0x89, 0xca, 0x45, 0xde, 0xe9,
0xc0, 0xf3, 0x9b, 0x2e, 0xdd, 0xac, 0x85, 0x35, 0xd1, 0x34, 0x5a, 0x92,
0x90, 0x62, 0xb1, 0x92, 0x58, 0x8a, 0xab, 0x0f, 0x01, 0x7d, 0x29, 0x41,
0x7d, 0x40, 0xe8, 0x6d, 0x5e, 0x44, 0x10, 0x42, 0x98, 0x9f, 0x8a, 0x1c,
0xb9, 0xb8, 0x44, 0xb4, 0xb8, 0x12, 0xbc, 0xf7, 0x8b, 0x16, 0xb2, 0x47,
0x23, 0xb4, 0x30, 0xa5, 0x6a, 0x2d, 0x71, 0xad, 0x15, 0x5e, 0xc3, 0x9a,
0x8f, 0xaf, 0x18, 0x01, 0x00, 0x64, 0xb2, 0x40, 0xfc, 0xba, 0xf0, 0xd6,
0x86, 0x52, 0x05, 0x5b, 0xe2, 0xe6, 0x49, 0xd0, 0x6b, 0xba, 0x92, 0x77,
0x79, 0xc0, 0x49, 0xa0, 0x9f, 0x88, 0x61, 0x55, 0x72, 0xc9, 0x5f, 0x3a,
0x6f, 0xad, 0x32, 0x5b, 0x9f, 0x2a, 0xe7, 0x1c, 0x9c, 0x73, 0x0f, 0xf1,
0x6b, 0x15, 0xdc, 0x22, 0x6e, 0xb2, 0xb7, 0x2a, 0xd9, 0xac, 0xe0, 0x5c,
0x88, 0x52, 0xcf, 0x5d, 0x83, 0xe6, 0x6b, 0xc9, 0x6a, 0x69, 0x19, 0xba,
0x8d, 0x59, 0x3e, 0xf3, 0x9e, 0x9a, 0xa3, 0xc6, 0x37, 0xf6, 0x60, 0x73,
0x3d, 0x21, 0x89, 0xac, 0xf7, 0xdc, 0x8c, 0x15, 0x9f, 0x86, 0x57, 0x8f,
0x69, 0xc0, 0x75, 0xca, 0xa8, 0x09, 0x9c, 0xef, 0x61, 0xe6, 0xf6, 0x1e,
0xfc, 0x5b, 0x61, 0xcd, 0x9e, 0xcf, 0x44, 0x29, 0x81, 0xc3, 0x30, 0x54,
0x9f, 0x8c, 0xdd, 0xb3, 0x03, 0xfa, 0x2f, 0x68, 0x11, 0x17, 0xb8, 0x63,
0x8a, 0xd8, 0x70, 0xed, 0xb1, 0x21, 0x04, 0x53, 0x5c, 0xab, 0x85, 0x6c,
0x15, 0x5c, 0x81, 0x88, 0x74, 0xfa, 0x1f, 0xdd, 0xda, 0x0b, 0x3b, 0x17,
0x97, 0x99, 0x21, 0x22, 0xdd, 0xc7, 0xbf, 0xe4, 0xde, 0x01, 0xe7, 0xdc,
0x24, 0x22, 0x88, 0x31, 0xce, 0x95, 0xab, 0x47, 0x32, 0x00, 0xa6, 0xb8,
0xc0, 0x56, 0xc1, 0xcd, 0x88, 0x31, 0xe2, 0x78, 0x3c, 0xce, 0xbf, 0x45,
0x64, 0x71, 0x25, 0x68, 0x71, 0x81, 0x3f, 0x30, 0xa6, 0xbd, 0x03, 0xcc,
0x3c, 0xa5, 0x99, 0xbe, 0xf6, 0x71, 0x29, 0x9f, 0x6a, 0x36, 0x81, 0x1f,
0xc0, 0x3d, 0x9f, 0x2b, 0xbf, 0x01, 0xc8, 0x27, 0x72, 0x5f, 0xca, 0xe5,
0xdb, 0x35, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
0x60, 0x82
};
unsigned int sprites_png_len = 542;

View File

@@ -2,6 +2,7 @@
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
@@ -9,26 +10,231 @@
void synthInit(Synth *s, float sampleRate)
{
s->sampleRate = sampleRate;
s->attackSec = 0.005f;
s->releaseSec = 0.050f;
s->dutyCycle = 0.5f;
s->waveform = WAVE_SINE;
s->lastStolenVoice = 0;
s->sampleRate = sampleRate;
s->pitchBend = 0.0f;
s->pitchBendRange = 2.0f;
s->lastStolenVoice = 0;
s->volume = 0.8f;
for (int i = 0; i < VOICE_COUNT; i++) {
s->voices[i].phase = 0.0f;
s->voices[i].freqHz = 440.0f;
s->voices[i].amp = 0.0f;
s->voices[i].targetAmp = 0.0f;
s->voices[i].active = 0;
s->voices[i].midiNote = -1;
s->pitchBend = 0.0f;
s->pitchBendRange = 2.0f;
s->voices[i].freqHz = 440.0f;
s->voices[i].active = 0;
s->voices[i].midiNote = -1;
oscillatorInit(&s->voices[i].oscillators[0], WAVE_TRIANGLE, 0.5f, 0.0f, OSC_MAX_GAIN);
oscillatorInit(&s->voices[i].oscillators[1], WAVE_TRIANGLE, 0.5f, 0.0f, 0.0f);
envelopeInit(&s->voices[i].ampEnv,
0.005f, // attack
0.10f, // decay
0.70f, // sustain
0.50f); // release
envelopeInit(&s->voices[i].modEnv,
0.005f, // attack
0.50f, // decay
0.0f, // sustain
0.10f); // release
s->voices[i].filter.cutoff = 8000.0f;
s->voices[i].filter.resonance = 0.0f;
s->voices[i].filter.type = FILTER_LOWPASS;
s->voices[i].filter.active = 0;
s->voices[i].filter.low = 0.0f;
s->voices[i].filter.band = 0.0f;
s->voices[i].filter.modRouting = MOD_SOURCE_NONE;
s->voices[i].filter.modDepth = 0.0f;
s->voices[i].filter.resModRouting = MOD_SOURCE_NONE;
s->voices[i].filter.resModDepth = 0.0f;
}
s->voices[0].oscillators[0].active = 1;
for (int l = 0; l < LFO_COUNT; l++) {
s->lfos[l].phase = 0.0f;
s->lfos[l].rate = 1.0f;
s->lfos[l].waveform = WAVE_SINE;
s->lfos[l].active = 0;
s->lfos[l].noiseHeld = 0.0f;
s->lfos[l].noisePhase = 0.0f;
}
}
float waveformSample(Waveform w, float phase, float dutyCycle)
void synthResetPatch(Synth *s)
{
Voice *v = &s->voices[0];
oscillatorInit(&v->oscillators[0], WAVE_TRIANGLE, 0.5f, 0.0f, OSC_MAX_GAIN);
v->oscillators[0].active = 1;
for (int m = 0; m < 3; m++) {
v->oscillators[0].modRouting[m] = MOD_SOURCE_NONE;
v->oscillators[0].modDepth[m] = 0.0f;
}
oscillatorInit(&v->oscillators[1], WAVE_TRIANGLE, 0.5f, 0.0f, 0.0f);
v->oscillators[1].active = 0;
for (int m = 0; m < 3; m++) {
v->oscillators[1].modRouting[m] = MOD_SOURCE_NONE;
v->oscillators[1].modDepth[m] = 0.0f;
}
envelopeInit(&v->ampEnv, 0.005f, 0.10f, 0.70f, 0.50f);
envelopeInit(&v->modEnv, 0.005f, 0.50f, 0.0f, 0.10f);
v->filter.cutoff = 8000.0f;
v->filter.resonance = 0.0f;
v->filter.type = FILTER_LOWPASS;
v->filter.active = 0;
v->filter.low = 0.0f;
v->filter.band = 0.0f;
v->filter.modRouting = MOD_SOURCE_NONE;
v->filter.modDepth = 0.0f;
v->filter.resModRouting = MOD_SOURCE_NONE;
v->filter.resModDepth = 0.0f;
for (int l = 0; l < LFO_COUNT; l++) {
s->lfos[l].phase = 0.0f;
s->lfos[l].rate = 1.0f;
s->lfos[l].waveform = WAVE_SINE;
s->lfos[l].active = 0;
s->lfos[l].noiseHeld = 0.0f;
s->lfos[l].noisePhase = 0.0f;
}
s->volume = 0.8f;
s->pitchBendRange = 2.0f;
}
void oscillatorInit(Oscillator *o, Waveform waveform, float dutyCycle, float detune, float gain)
{
o->phase = 0.0f;
o->waveform = waveform;
o->dutyCycle = dutyCycle;
o->detune = detune;
o->noiseHeld = 0.0f;
o->noisePhase = 0.0f;
o->gain = gain;
o->octave = 0;
}
static float getModValue(float ampEnv, float modEnv, float lfo0, float lfo1, ModSource source)
{
switch (source) {
case MOD_SOURCE_AMP_ENV: return ampEnv;
case MOD_SOURCE_MOD_ENV: return modEnv;
case MOD_SOURCE_LFO: return lfo0;
case MOD_SOURCE_LFO2: return lfo1;
default: return 0.0f;
}
}
float lfoTick(LFO *l, float sampleRate)
{
if (!l->active) return 0.0f;
l->phase += l->rate / sampleRate;
if (l->phase >= 1.0f) l->phase -= 1.0f;
if (l->waveform == WAVE_NOISE) {
l->noisePhase += l->rate / sampleRate;
if (l->noisePhase >= 1.0f) {
l->noisePhase -= 1.0f;
l->noiseHeld = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
}
}
return waveformSample(l->waveform, l->phase, 0.5f, l->noiseHeld);
}
float filterTick(Filter *f, float input, float cutoff, float resonance, float sampleRate)
{
if (!f->active) return input;
if (cutoff < 20.0f) cutoff = 20.0f;
if (cutoff > sampleRate * 0.499f) cutoff = sampleRate * 0.499f;
if (resonance < 0.0f) resonance = 0.0f;
if (resonance > 0.99f) resonance = 0.99f;
// Andy Simper TPT SVF (bilinear integration — unconditionally stable)
float g = tanf((float)M_PI * cutoff / sampleRate);
float Q = 0.5f + resonance * 9.5f; // resonance 0..0.99 → Q 0.5..10.0
float k = 1.0f / Q;
float a1 = 1.0f / (1.0f + g * (g + k));
float a2 = g * a1;
float a3 = g * a2;
// f->band = s1, f->low = s2 (integrator states)
float v3 = input - f->low;
float v1 = a1 * f->band + a2 * v3;
float v2 = f->low + a2 * f->band + a3 * v3;
f->band = 2.0f * v1 - f->band;
f->low = 2.0f * v2 - f->low;
switch (f->type) {
case FILTER_LOWPASS: return v2;
case FILTER_HIGHPASS: return input - k * v1 - v2;
case FILTER_BANDPASS: return v1;
default: return v2;
}
}
const char *filterTypeName(FilterType t)
{
switch (t) {
case FILTER_LOWPASS: return "LP";
case FILTER_HIGHPASS: return "HP";
case FILTER_BANDPASS: return "BP";
default: return "??";
}
}
// float oscillatorTick(Oscillator *o, float freqHz, float bendMultiplier, float sampleRate,
// float dutyCycle, float detune, float gain)
// {
// float detuneMultiplier = powf(2.0f, o->detune / 1200.0f);
// float freq = freqHz * detuneMultiplier * bendMultiplier;
//
// // Advance phase
// o->phase += freq / sampleRate;
// if (o->phase >= 1.0f) o->phase -= 1.0f;
//
// // Clocked noise — draw a new random value once per cycle
// if (o->waveform == WAVE_NOISE) {
// o->noisePhase += freq / sampleRate;
// if (o->noisePhase >= 1.0f) {
// o->noisePhase -= 1.0f;
// o->noiseHeld = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
// }
// }
//
// return waveformSample(o->waveform, o->phase, o->dutyCycle, o->noiseHeld) * o->gain;
// }
float oscillatorTick(Oscillator *o, float freqHz, float bendMultiplier, float sampleRate,
float dutyCycle, float detune, float gain)
{
float detuneMultiplier = powf(2.0f, detune / 1200.0f);
float freq = freqHz * detuneMultiplier * bendMultiplier;
// Advance phase
o->phase += freq / sampleRate;
if (o->phase >= 1.0f) o->phase -= 1.0f;
// Clocked noise — draw a new random value once per cycle
if (o->waveform == WAVE_NOISE) {
o->noisePhase += freq / sampleRate;
if (o->noisePhase >= 1.0f) {
o->noisePhase -= 1.0f;
o->noiseHeld = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
}
}
return waveformSample(o->waveform, o->phase, dutyCycle, o->noiseHeld) * gain;
}
float waveformSample(Waveform w, float phase, float dutyCycle, float noiseHeld)
{
switch (w) {
case WAVE_SINE:
@@ -44,7 +250,7 @@ float waveformSample(Waveform w, float phase, float dutyCycle)
case WAVE_PULSE:
return (phase < dutyCycle) ? 1.0f : -1.0f;
case WAVE_NOISE:
return ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
return noiseHeld;
default:
return 0.0f;
}
@@ -69,67 +275,95 @@ void synthNoteOn(Synth *s, int midiNote)
for (int i = 0; i < VOICE_COUNT; i++) {
if (!s->voices[i].active) {
s->voices[i].freqHz = hz;
s->voices[i].midiNote = midiNote;
s->voices[i].targetAmp = 1.0f;
s->voices[i].active = 1;
s->voices[i].freqHz = hz;
s->voices[i].midiNote = midiNote;
s->voices[i].active = 1;
s->voices[i].filter.low = 0.0f;
s->voices[i].filter.band = 0.0f;
envelopeNoteOn(&s->voices[i].ampEnv);
envelopeNoteOn(&s->voices[i].modEnv);
return;
}
}
// No free voice — steal round-robin
// Steal round-robin
int i = s->lastStolenVoice % VOICE_COUNT;
s->lastStolenVoice++;
s->voices[i].freqHz = hz;
s->voices[i].midiNote = midiNote;
s->voices[i].targetAmp = 1.0f;
s->voices[i].phase = 0.0f;
s->voices[i].active = 1;
s->voices[i].freqHz = hz;
s->voices[i].midiNote = midiNote;
s->voices[i].active = 1;
s->voices[i].filter.low = 0.0f;
s->voices[i].filter.band = 0.0f;
envelopeNoteOn(&s->voices[i].ampEnv);
envelopeNoteOn(&s->voices[i].modEnv);
}
void synthNoteOff(Synth *s, int midiNote)
{
void synthNoteOff(Synth *s, int midiNote) {
for (int i = 0; i < VOICE_COUNT; i++) {
if (s->voices[i].active && s->voices[i].midiNote == midiNote)
s->voices[i].targetAmp = 0.0f;
if (s->voices[i].active && s->voices[i].midiNote == midiNote) {
envelopeNoteOff(&s->voices[i].ampEnv);
envelopeNoteOff(&s->voices[i].modEnv);
}
}
}
void synthFillBuffer(Synth *s, int16_t *out, int frames)
{
const float sr = s->sampleRate;
const float attackInc = (s->attackSec <= 0.0f) ? 1.0f : (1.0f / (s->attackSec * sr));
const float releaseInc = (s->releaseSec <= 0.0f) ? 1.0f : (1.0f / (s->releaseSec * sr));
void synthFillBuffer(Synth *s, int16_t *out, int frames) {
const float sr = s->sampleRate;
const float bendMultiplier = powf(2.0f, (s->pitchBend * s->pitchBendRange) / 12.0f);
for (int i = 0; i < frames; i++) {
float mix = 0.0f;
float lfo0 = lfoTick(&s->lfos[0], sr);
float lfo1 = lfoTick(&s->lfos[1], sr);
for (int v = 0; v < VOICE_COUNT; v++) {
Voice *vv = &s->voices[v];
if (!vv->active) continue;
if (vv->targetAmp > vv->amp) {
vv->amp += attackInc;
if (vv->amp > vv->targetAmp) vv->amp = vv->targetAmp;
} else if (vv->targetAmp < vv->amp) {
vv->amp -= releaseInc;
if (vv->amp < vv->targetAmp) vv->amp = vv->targetAmp;
}
float amp = envelopeTick(&vv->ampEnv, sr);
float mod = envelopeTick(&vv->modEnv, sr);
if (vv->amp <= 0.0f && vv->targetAmp == 0.0f) {
if (vv->ampEnv.stage == ENV_IDLE) {
vv->active = 0;
continue;
}
//vv->phase += vv->freqHz / sr;
float bendMultiplier = powf(2.0f, (s->pitchBend * s->pitchBendRange) / 12.0f);
vv->phase += (vv->freqHz * bendMultiplier) / sr;
if (vv->phase >= 1.0f) vv->phase -= 1.0f;
float oscMix = 0.0f;
int activeOscs = 0;
for (int o = 0; o < OSC_COUNT; o++) {
Oscillator *osc = &vv->oscillators[o];
if (!osc->active) continue;
mix += waveformSample(s->waveform, vv->phase, s->dutyCycle) * vv->amp;
float dutyCycle = osc->dutyCycle +
getModValue(amp, mod, lfo0, lfo1, osc->modRouting[0]) * osc->modDepth[0];
float detune = osc->detune + (float)osc->octave * 1200.0f +
getModValue(amp, mod, lfo0, lfo1, osc->modRouting[1]) * osc->modDepth[1];
float gain = osc->gain +
getModValue(amp, mod, lfo0, lfo1, osc->modRouting[2]) * osc->modDepth[2];
if (dutyCycle < 0.05f) dutyCycle = 0.05f;
if (dutyCycle > 0.95f) dutyCycle = 0.95f;
if (gain < 0.0f) gain = 0.0f;
if (gain > OSC_MAX_GAIN) gain = OSC_MAX_GAIN;
oscMix += oscillatorTick(osc, vv->freqHz, bendMultiplier, sr, dutyCycle, detune, gain);
activeOscs++;
}
if (activeOscs > 0) oscMix /= activeOscs;
float cutoff = vv->filter.cutoff +
getModValue(amp, mod, lfo0, lfo1, vv->filter.modRouting) * vv->filter.modDepth;
float resonance = vv->filter.resonance +
getModValue(amp, mod, lfo0, lfo1, vv->filter.resModRouting) * vv->filter.resModDepth;
oscMix = filterTick(&vv->filter, oscMix, cutoff, resonance, sr);
mix += oscMix * amp;
}
mix *= (0.2f / VOICE_COUNT) * 4.0f;
mix *= (0.2f / VOICE_COUNT) * 4.0f * s->volume;
int32_t sample = (int32_t)lrintf(mix * 32767.0f);
if (sample > 32767) sample = 32767;
@@ -137,3 +371,109 @@ void synthFillBuffer(Synth *s, int16_t *out, int frames)
out[i] = (int16_t)sample;
}
}
void envelopeInit(Envelope *e, float attackSec, float decaySec, float sustainLevel, float releaseSec)
{
e->stage = ENV_IDLE;
e->value = 0.0f;
e->attackSec = attackSec;
e->decaySec = decaySec;
e->sustainLevel = sustainLevel;
e->releaseSec = releaseSec;
}
void envelopeNoteOn(Envelope *e)
{
e->value = 0.0f;
e->stage = ENV_ATTACK;
}
void envelopeNoteOff(Envelope *e)
{
// Only trigger release if we're actually playing
if (e->stage != ENV_IDLE)
e->stage = ENV_RELEASE;
}
float envelopeTick(Envelope *e, float sampleRate)
{
switch (e->stage) {
case ENV_ATTACK: {
float inc = (e->attackSec <= 0.0f) ? 1.0f : (1.0f / (e->attackSec * sampleRate));
e->value += inc;
if (e->value >= 1.0f) {
e->value = 1.0f;
e->stage = ENV_DECAY;
}
break;
}
case ENV_DECAY: {
float inc = (e->decaySec <= 0.0f) ? 1.0f : (1.0f / (e->decaySec * sampleRate));
e->value -= inc;
if (e->value <= e->sustainLevel) {
e->value = e->sustainLevel;
e->stage = ENV_SUSTAIN;
}
break;
}
case ENV_SUSTAIN:
e->value = e->sustainLevel;
break;
case ENV_RELEASE: {
float inc = (e->releaseSec <= 0.0f) ? 1.0f : (1.0f / (e->releaseSec * sampleRate));
e->value -= inc;
if (e->value <= 0.0f) {
e->value = 0.0f;
e->stage = ENV_IDLE;
}
break;
}
case ENV_IDLE:
e->value = 0.0f;
break;
}
return e->value;
}
void synthSyncVoices(Synth *s)
{
for (int v = 1; v < VOICE_COUNT; v++) {
// Sync oscillator settings
for (int o = 0; o < OSC_COUNT; o++) {
s->voices[v].oscillators[o].waveform = s->voices[0].oscillators[o].waveform;
s->voices[v].oscillators[o].dutyCycle = s->voices[0].oscillators[o].dutyCycle;
s->voices[v].oscillators[o].detune = s->voices[0].oscillators[o].detune;
s->voices[v].oscillators[o].gain = s->voices[0].oscillators[o].gain;
s->voices[v].oscillators[o].active = s->voices[0].oscillators[o].active;
s->voices[v].oscillators[o].octave = s->voices[0].oscillators[o].octave;
s->voices[v].oscillators[o].modRouting[0] = s->voices[0].oscillators[o].modRouting[0];
s->voices[v].oscillators[o].modRouting[1] = s->voices[0].oscillators[o].modRouting[1];
s->voices[v].oscillators[o].modRouting[2] = s->voices[0].oscillators[o].modRouting[2];
s->voices[v].oscillators[o].modDepth[0] = s->voices[0].oscillators[o].modDepth[0];
s->voices[v].oscillators[o].modDepth[1] = s->voices[0].oscillators[o].modDepth[1];
s->voices[v].oscillators[o].modDepth[2] = s->voices[0].oscillators[o].modDepth[2];
}
// Sync filter params but not state (low/band are per-voice)
s->voices[v].filter.cutoff = s->voices[0].filter.cutoff;
s->voices[v].filter.resonance = s->voices[0].filter.resonance;
s->voices[v].filter.type = s->voices[0].filter.type;
s->voices[v].filter.active = s->voices[0].filter.active;
s->voices[v].filter.modRouting = s->voices[0].filter.modRouting;
s->voices[v].filter.modDepth = s->voices[0].filter.modDepth;
s->voices[v].filter.resModRouting = s->voices[0].filter.resModRouting;
s->voices[v].filter.resModDepth = s->voices[0].filter.resModDepth;
// Sync envelope settings but NOT runtime state
// Each voice needs its own stage, value — just copy the parameters
s->voices[v].ampEnv.attackSec = s->voices[0].ampEnv.attackSec;
s->voices[v].ampEnv.decaySec = s->voices[0].ampEnv.decaySec;
s->voices[v].ampEnv.sustainLevel = s->voices[0].ampEnv.sustainLevel;
s->voices[v].ampEnv.releaseSec = s->voices[0].ampEnv.releaseSec;
// Sync the mod envelope, too.
s->voices[v].modEnv.attackSec = s->voices[0].modEnv.attackSec;
s->voices[v].modEnv.decaySec = s->voices[0].modEnv.decaySec;
s->voices[v].modEnv.sustainLevel = s->voices[0].modEnv.sustainLevel;
s->voices[v].modEnv.releaseSec = s->voices[0].modEnv.releaseSec;
}
}

1719
source/ui.c Normal file

File diff suppressed because it is too large Load Diff