├── .gitignore ├── fourier_transforms ├── bin │ └── main.exe ├── build.bat ├── build_tcc.bat ├── build_vs.bat ├── clean.bat ├── include │ ├── minimal_windows.h │ ├── platform.h │ ├── raygui.h │ ├── raylib.h │ └── ricons.h ├── lib │ ├── tcc │ │ └── raylib.lib │ └── vs2019 │ │ └── raylib.lib ├── project.4coder ├── run.bat └── src │ ├── backup.c │ └── main.c ├── programming_memory_tutorial ├── about.txt ├── asc.txt ├── bin │ └── fantasy_machine.exe ├── bubblesort.txt ├── build_odin.bat ├── build_then_run.bat ├── click_01.wav ├── click_02.wav ├── code.txt ├── conversion.c ├── fantasy_machine.exe ├── fantasy_machine.odin ├── hello.txt ├── include │ └── raylib.h ├── lib │ └── raylib.lib ├── main.c ├── main.exe ├── raylib.dll ├── raylib │ ├── raylib.odin │ └── raylib_helpers.odin ├── stb_ds.h ├── strcmp.txt └── strcmp_data.txt └── synth ├── LICENSE.txt ├── about.txt ├── build_midi.bat ├── build_then_run.bat ├── build_vs.bat ├── include ├── minimal_windows.h ├── raygui.h ├── raylib.h ├── ricons.h └── synth_platform.h ├── lib ├── tcc │ └── raylib.lib └── vs2019 │ └── raylib.lib ├── midi.exe ├── midi.h ├── project.4coder ├── recordings └── sawtooth_and_fastsine.mp3 ├── resources.txt ├── styles ├── README.md ├── ashes │ ├── README.md │ ├── ashes.rgs │ ├── font_readme.txt │ ├── screenshot.png │ ├── style_table.png │ └── v5loxical.ttf ├── bluish │ ├── README.md │ ├── bluish.rgs │ ├── font_readme.txt │ ├── homespun.ttf │ ├── screenshot.png │ └── style_table.png ├── candy │ ├── README.md │ ├── candy.rgs │ ├── font_readme.txt │ ├── screenshot.png │ ├── style_table.png │ └── v5easter.ttf ├── cherry │ ├── README.md │ ├── Westington.ttf │ ├── cherry.rgs │ ├── screenshot.png │ └── style_table.png ├── cyber │ ├── Kyrou 7 Wide.ttf │ ├── README.md │ ├── cyber.rgs │ ├── font_readme.txt │ ├── screenshot.png │ └── style_table.png ├── default │ ├── README.md │ ├── default.rgs │ ├── screenshot.png │ └── style_table.png ├── jungle │ ├── Pixel Intv.otf │ ├── README.md │ ├── font_readme.txt │ ├── jungle.rgs │ ├── screenshot.png │ └── style_table.png ├── lavanda │ ├── Cartridge.ttf │ ├── README.md │ ├── font_readme.txt │ ├── lavanda.rgs │ ├── screenshot.png │ └── style_table.png └── terminal │ ├── Mecha.ttf │ ├── README.md │ ├── screenshot.png │ ├── style_table.png │ └── terminal.rgs ├── synth.c └── synth.exe /.gitignore: -------------------------------------------------------------------------------- 1 | *.pdb 2 | *.obj 3 | *.o 4 | */.vscode 5 | -------------------------------------------------------------------------------- /fourier_transforms/bin/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/fourier_transforms/bin/main.exe -------------------------------------------------------------------------------- /fourier_transforms/build.bat: -------------------------------------------------------------------------------- 1 | build_vs.bat -------------------------------------------------------------------------------- /fourier_transforms/build_tcc.bat: -------------------------------------------------------------------------------- 1 | pushd bin 2 | call tcc -o main.exe ../src/main.c -I../include -L../lib -lraylib -lmsvcrt -lopengl32 -lgdi32 -lkernel32 -lshell32 -luser32 -lwinmm -Wl,-subsystem=gui -std=c99 3 | popd -------------------------------------------------------------------------------- /fourier_transforms/build_vs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET VS=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools 3 | if not defined DevEnvDir ( 4 | CALL "%VS%\VsDevCmd.bat" -arch=x64 5 | ) 6 | 7 | pushd bin 8 | SET CommonFlags=-nologo -Od -Oi /I"..\include" /Zi /Gm- /Gd /TC 9 | SET CommonLinkerFlags=/LIBPATH:"..\lib\vs2019" raylib.lib -opt:ref kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib 10 | call cl.exe %CommonFlags% "..\src\main.c" /link /OUT:"main.exe" %CommonLinkerFlags% 11 | popd -------------------------------------------------------------------------------- /fourier_transforms/clean.bat: -------------------------------------------------------------------------------- 1 | del bin /Q -------------------------------------------------------------------------------- /fourier_transforms/include/minimal_windows.h: -------------------------------------------------------------------------------- 1 | /* date = March 24th 2021 5:46 pm */ 2 | 3 | #ifndef MINIMAL_WINDOWS_H 4 | #define MINIMAL_WINDOWS_H 5 | 6 | /* 7 | @raysan5: To avoid conflicting windows.h symbols with raylib, some flags are defined 8 | WARNING: Those flags avoid inclusion of some Win32 headers that could be required 9 | by user at some point and won't be included... 10 | */ 11 | 12 | /* If defined, the following flags inhibit definition of the indicated items.*/ 13 | #define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ 14 | #define NOVIRTUALKEYCODES // VK_* 15 | #define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* 16 | #define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* 17 | #define NOSYSMETRICS // SM_* 18 | #define NOMENUS // MF_* 19 | #define NOICONS // IDI_* 20 | #define NOKEYSTATES // MK_* 21 | #define NOSYSCOMMANDS // SC_* 22 | #define NORASTEROPS // Binary and Tertiary raster ops 23 | #define NOSHOWWINDOW // SW_* 24 | #define OEMRESOURCE // OEM Resource values 25 | #define NOATOM // Atom Manager routines 26 | #define NOCLIPBOARD // Clipboard routines 27 | #define NOCOLOR // Screen colors 28 | #define NOCTLMGR // Control and Dialog routines 29 | #define NODRAWTEXT // DrawText() and DT_* 30 | #define NOGDI // All GDI defines and routines 31 | #define NOKERNEL // All KERNEL defines and routines 32 | #define NOUSER // All USER defines and routines 33 | /*#define NONLS // All NLS defines and routines*/ 34 | #define NOMB // MB_* and MessageBox() 35 | #define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines 36 | #define NOMETAFILE // typedef METAFILEPICT 37 | #define NOMINMAX // Macros min(a,b) and max(a,b) 38 | #define NOMSG // typedef MSG and associated routines 39 | #define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* 40 | #define NOSCROLL // SB_* and scrolling routines 41 | 42 | #ifndef NOSERVICE 43 | #define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. 44 | #endif 45 | 46 | #define NOSOUND // Sound driver routines 47 | #define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines 48 | #define NOWH // SetWindowsHook and WH_* 49 | #define NOWINOFFSETS // GWL_*, GCL_*, associated routines 50 | #define NOCOMM // COMM driver routines 51 | #define NOKANJI // Kanji support stuff. 52 | #define NOHELP // Help engine interface. 53 | #define NOPROFILER // Profiler interface. 54 | #define NODEFERWINDOWPOS // DeferWindowPos routines 55 | 56 | #ifndef NOMCX 57 | #define NOMCX // Modem Configuration Extensions 58 | #endif 59 | 60 | /* Type required before windows.h inclusion */ 61 | typedef struct tagMSG *LPMSG; 62 | 63 | #include 64 | 65 | /* Type required by some unused function... */ 66 | typedef struct tagBITMAPINFOHEADER { 67 | DWORD biSize; 68 | LONG biWidth; 69 | LONG biHeight; 70 | WORD biPlanes; 71 | WORD biBitCount; 72 | DWORD biCompression; 73 | DWORD biSizeImage; 74 | LONG biXPelsPerMeter; 75 | LONG biYPelsPerMeter; 76 | DWORD biClrUsed; 77 | DWORD biClrImportant; 78 | } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 79 | 80 | #include 81 | #include 82 | #include 83 | 84 | /* @raysan5: Some required types defined for MSVC/TinyC compiler */ 85 | #if defined(_MSC_VER) || defined(__TINYC__) 86 | #include "propidl.h" 87 | #endif 88 | 89 | 90 | #endif //MINIMAL_WINDOWS_H 91 | -------------------------------------------------------------------------------- /fourier_transforms/include/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_H 2 | #define PLATFORM_H 3 | 4 | #include 5 | #include 6 | #include 7 | typedef int8_t i8; 8 | typedef int16_t i16; 9 | typedef int32_t i32; 10 | typedef int64_t i64; 11 | typedef uint8_t u8; 12 | typedef uint16_t u16; 13 | typedef uint32_t u32; 14 | typedef uint64_t u64; 15 | typedef size_t usize; 16 | typedef float f32; 17 | typedef double f64; 18 | 19 | #include 20 | #define F32_MAX FLT_MAX 21 | #include 22 | #define U16_MAX USHRT_MAX; 23 | #define U32_MAX UINT_MAX; 24 | #define U64_MAX ULONG_MAX; 25 | #define I16_MAX SHRT_MAX; 26 | #define I32_MAX INT_MAX; 27 | #define I64_MAX LONG_MAX; 28 | 29 | #define global static 30 | #define local_static static 31 | #define internal static 32 | #define not ! 33 | 34 | // IMPORTANT(luke): function-like macros must start with 'mx_', otherwise it's too easy 35 | // to assume at the callsite that it's a normal function, when it really doesn't behave 36 | // like one! 37 | #define mx_ArrayCount(arr) (sizeof((arr)) / (sizeof((arr)[0]))) 38 | #define mx_Kilobytes(number) ((number)*1024ull) 39 | #define mx_Megabytes(number) (Kilobytes(number) * 1024ull) 40 | #define mx_Gigabytes(number) (Megabytes(number) * 1024ull) 41 | #define mx_Terabytes(number) (Gigabytes(number) * 1024ull) 42 | #define mx_InsideOpen(v, a, b) ((v > a) && (v < b)) 43 | #define mx_InsideClosed(v, a, b) ((v >= a) && (v <= b)) 44 | #define mx_InsideClosedOpen(v, a, b) ((v >= a) && (v < b)) 45 | #define mx_InsideOpenClosed(v, a, b) ((v > a) && (v <= b)) 46 | #define mx_InsideUpto InsideClosedOpen 47 | #define mx_InsideDownto InsideOpenClosed 48 | #define mx_InsideExclusive InsideOpen 49 | #define mx_InsideInclusive InsideClosed 50 | #define mx_OutsideExlusive !InsideInclusive 51 | #define mx_OutsideInclusive !InsideExclusive 52 | 53 | #ifdef ASSERTIONS 54 | #define mx_Assert(expression) \ 55 | if(!(expression)) { \ 56 | *(int *)0 = 0; \ 57 | } 58 | #else 59 | #define mx_Assert(expression) 60 | #endif 61 | 62 | #define Unreachable Assert(!"Unreachable code") 63 | 64 | inline f32 65 | Log2f(f32 n) 66 | { 67 | return logf( n ) / logf( 2 ); 68 | } 69 | 70 | inline u32 71 | RandomU32(u32 seed) 72 | { 73 | local_static u32 z = 362436069; 74 | local_static u32 w = 521288629; 75 | local_static u32 jcong = 380116160; 76 | local_static u32 jsr = 123456789; 77 | u32 z_new = 36969 * ((z+seed) & 65535) + ((z+seed) >> 16); 78 | u32 w_new = 18000 * (w & 65535) + (w >> 16); 79 | u32 mwc = (z_new << 16) + w_new; 80 | u32 jcong_new = 69069 * jcong + 1234567; 81 | u32 jsr_new = jsr ^ (jsr << 17); 82 | jsr_new ^= (jsr >> 13); 83 | jsr_new ^= (jsr << 5); 84 | u32 result = (mwc ^ jcong_new) + jsr_new; 85 | z = z_new; 86 | w = w_new; 87 | jcong = jcong_new; 88 | jsr = jsr_new; 89 | return result; 90 | } 91 | 92 | inline f32 93 | RandomF32(u32 seed) 94 | { 95 | u32 val = RandomU32(seed); 96 | return (f32)val / (f32)U32_MAX; 97 | } 98 | 99 | #endif //PLATFORM_H 100 | -------------------------------------------------------------------------------- /fourier_transforms/lib/tcc/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/fourier_transforms/lib/tcc/raylib.lib -------------------------------------------------------------------------------- /fourier_transforms/lib/vs2019/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/fourier_transforms/lib/vs2019/raylib.lib -------------------------------------------------------------------------------- /fourier_transforms/project.4coder: -------------------------------------------------------------------------------- 1 | version(1); 2 | 3 | project_name = "c_raylib"; 4 | 5 | patterns = 6 | { 7 | "*.c", 8 | "*.cpp", 9 | "*.jai", 10 | "*.odin", 11 | "*.zig", 12 | "*.h", 13 | "*.inc", 14 | "*.bat", 15 | "*.sh", 16 | "*.4coder", 17 | "*.txt", 18 | }; 19 | 20 | blacklist_patterns = 21 | { 22 | ".*", 23 | }; 24 | 25 | load_paths = 26 | { 27 | { 28 | { {"."}, .recursive = true, .relative = true }, .os = "win" 29 | }, 30 | }; 31 | 32 | command_list = 33 | { 34 | { 35 | .name = "build", 36 | .out = "*compilation*", 37 | .footer_panel = true, 38 | .save_dirty_files = true, 39 | .cursor_at_end = false, 40 | .cmd = 41 | { 42 | { "build.bat", .os = "win" }, 43 | { "echo Linux build command not implemented for 4coder project.", .os = "linux" }, 44 | }, 45 | }, 46 | 47 | { 48 | .name = "run", 49 | .out = "*compilation*", 50 | .footer_panel = true, 51 | .save_dirty_files = true, 52 | .cursor_at_end = false, 53 | .cmd = 54 | { 55 | { "run.bat", .os = "win" }, 56 | { "echo Linux run command not implemented for 4coder project.", .os = "linux" }, 57 | }, 58 | } 59 | }; 60 | 61 | fkey_command[1] = "build"; 62 | fkey_command[2] = "run"; 63 | -------------------------------------------------------------------------------- /fourier_transforms/run.bat: -------------------------------------------------------------------------------- 1 | bin\main.exe -------------------------------------------------------------------------------- /fourier_transforms/src/backup.c: -------------------------------------------------------------------------------- 1 | #include "platform.h" 2 | #include "raylib.h" 3 | #define RAYGUI_SUPPORT_ICONS 4 | #define RAYGUI_IMPLEMENTATION 5 | #include "raygui.h" 6 | 7 | #define NUM_SAMPLES 1024 8 | typedef struct 9 | { 10 | f32 Samples[NUM_SAMPLES]; 11 | f32 FourierTransform[NUM_SAMPLES]; 12 | } state; 13 | 14 | internal void 15 | FourierTransform(f32 *TimeDomain, f32 *FreqDomain, usize Size) 16 | { 17 | for (i32 Fn = 0; Fn < Size; Fn++) 18 | { 19 | f32 Theta = ((f32)Fn/Size) * 10.0f; 20 | f32 SumX = 0; 21 | f32 SumY = 0; 22 | for (i32 Sn = 0; Sn < Size; Sn++) 23 | { 24 | f32 Ns = (f32)Sn/Size; 25 | f32 W = (2*PI) * Theta; 26 | f32 Xf = -sinf(Ns*W) * TimeDomain[Sn]; 27 | f32 Yf = -cosf(Ns*W) * TimeDomain[Sn]; 28 | SumX += Xf; 29 | SumY += Yf; 30 | } 31 | f32 Sum = (SumX*SumX + SumY*SumY) * 0.005f; 32 | //f32 Sum = SumX*SumX * 0.001f; 33 | FreqDomain[Fn] = Sum; 34 | } 35 | } 36 | 37 | internal void 38 | Draw(state *State) 39 | { 40 | f32 SignalStartY = 728/3; 41 | Vector2 MousePos = GetMousePosition(); 42 | f32 WrapFreq = (MousePos.x / NUM_SAMPLES) * 10; 43 | DrawLine(0, SignalStartY, 1024, SignalStartY, ColorAlpha(GRAY, 0.6f)); 44 | 45 | Vector2 SignalWrapOrigin = {500, 500}; 46 | Vector2 SumPoint = {0, 0}; 47 | for (i32 N = 0; N < NUM_SAMPLES; N++) 48 | { 49 | f32 Sample = State->Samples[N]; 50 | i32 Y = SignalStartY + (Sample * 50); 51 | DrawPixel(N, Y, ColorAlpha(RED, 0.7f)); 52 | 53 | f32 Ns = (f32)N/NUM_SAMPLES; 54 | f32 W = (2*PI) * WrapFreq; 55 | f32 Xf = -sinf(Ns*W) * Sample; 56 | f32 Yf = -cosf(Ns*W) * Sample; 57 | SumPoint.x += Xf; 58 | SumPoint.y += Yf; 59 | f32 Mag = 100.0f; 60 | DrawPixel((Xf * Mag) + SignalWrapOrigin.x, 61 | (Yf * Mag) + SignalWrapOrigin.y, 62 | ColorAlpha(GREEN, 0.4f)); 63 | } 64 | 65 | Vector2 SumPoint2 = { 66 | SumPoint.x + SignalWrapOrigin.x, 67 | SumPoint.y + SignalWrapOrigin.y 68 | }; 69 | DrawLineV(SignalWrapOrigin, SumPoint2, YELLOW); 70 | DrawCircleV(SumPoint2, 4, YELLOW); 71 | 72 | f32 Stride = NUM_SAMPLES / max(WrapFreq, 1.0f); 73 | { 74 | f32 OverlapArr[NUM_SAMPLES] = {0}; 75 | f32 X = 0; 76 | while(X < NUM_SAMPLES) 77 | { 78 | f32 Y = SignalStartY; 79 | DrawLine(X, Y-100, X, Y+100, GREEN); 80 | for (i32 N = 0; N < Stride; N++) 81 | { 82 | if (N + X >= NUM_SAMPLES) break; 83 | f32 Sample = State->Samples[N + (i32)X]; 84 | DrawPixel(Stride+N, SignalStartY + (Sample*50), ColorAlpha(RED, 0.4f)); 85 | OverlapArr[N] += Sample; 86 | } 87 | X += max(Stride, 1); 88 | } 89 | 90 | if (IsMouseButtonDown(0)) 91 | { 92 | for (i32 N = 0; N < Stride; N++) 93 | { 94 | DrawPixel(Stride+N, SignalStartY + (OverlapArr[N]*50), ColorAlpha(GREEN, 0.6f)); 95 | } 96 | } 97 | } 98 | 99 | { 100 | 101 | #if 0 102 | for(i32 N = 0; N < Stride; N++) 103 | { 104 | f32 X = 0; 105 | if (N + X >= NUM_SAMPLES) break; 106 | f32 Sum = 0; 107 | f32 XCount = 0; 108 | while(X < NUM_SAMPLES) 109 | { 110 | f32 Sample = State->Samples[N + (i32)X]; 111 | Sum += Sample; 112 | X += max(Stride, 1); 113 | XCount += 1; 114 | DrawPixel(N, SignalStartY + (Sample*50), RAYWHITE); 115 | } 116 | //Sum /= XCount+1; 117 | } 118 | #endif 119 | } 120 | 121 | f32 DistSum = sqrt(SumPoint.x*SumPoint.x + SumPoint.y*SumPoint.y); 122 | DrawText(TextFormat("Wrap Freq: %.1fHz", WrapFreq), 15, 25, 20, GREEN); 123 | DrawText(TextFormat("Distance: %.1f", DistSum), 15, 45, 20, YELLOW); 124 | 125 | i32 Xf = (NUM_SAMPLES/10) * WrapFreq; 126 | f32 FourierTransformStartY = 730; 127 | for (i32 N = 0; N < NUM_SAMPLES; N++) 128 | { 129 | f32 Sample = State->FourierTransform[N]; 130 | i32 Y = FourierTransformStartY - (Sample * 1); 131 | DrawPixel(N, Y, YELLOW); 132 | } 133 | DrawLine(Xf, 134 | FourierTransformStartY-(State->FourierTransform[Xf]), 135 | Xf, 136 | FourierTransformStartY+20, 137 | YELLOW); 138 | } 139 | 140 | internal void 141 | Update(state *State) 142 | { 143 | static i32 Freq1 = 6; 144 | static bool Freq1_Edit = false; 145 | static f32 Amp1 = 1; 146 | 147 | static i32 Freq2 = 6; 148 | static bool Freq2_Edit = false; 149 | static f32 Amp2 = 1; 150 | 151 | static i32 Freq3 = 6; 152 | static f32 Amp3 = 1; 153 | static bool Freq3_Edit = false; 154 | 155 | if (GuiSpinner((Rectangle){ 600, 15, 80, 30 }, NULL, &Freq1, 0, 10, Freq1_Edit)) 156 | Freq1_Edit = !Freq1_Edit; 157 | if (GuiSpinner((Rectangle){ 700, 15, 80, 30 }, NULL, &Freq2, 0, 10, Freq2_Edit)) 158 | Freq2_Edit = !Freq2_Edit; 159 | if (GuiSpinner((Rectangle){ 800, 15, 80, 30 }, NULL, &Freq3, 0, 10, Freq3_Edit)) 160 | Freq3_Edit = !Freq3_Edit; 161 | 162 | for (i32 N = 0; N < NUM_SAMPLES; N++) 163 | { 164 | State->Samples[N] = 0; 165 | State->Samples[N] += Amp1 * cosf(2 * PI * Freq1 * ((f32)N / NUM_SAMPLES)); 166 | State->Samples[N] += Amp2 * sinf(2 * PI * Freq2 * ((f32)N / NUM_SAMPLES)); 167 | State->Samples[N] += Amp3 * sinf(2 * PI * Freq3 * ((f32)N / NUM_SAMPLES)); 168 | State->Samples[N] /= 3; 169 | } 170 | 171 | FourierTransform(&State->Samples[0], &State->FourierTransform[0], NUM_SAMPLES); 172 | } 173 | 174 | i32 175 | main(i32 argc, char **argv) 176 | { 177 | const i32 screen_width = 1024; 178 | const i32 screen_height = 768; 179 | InitWindow(screen_width, screen_height, "Raylib"); 180 | SetTargetFPS(60); 181 | InitAudioDevice(); 182 | 183 | f32 Freq1 = 4; 184 | f32 Freq2 = 3; 185 | f32 Freq3 = 9; 186 | f32 Amp1 = 0.5f; 187 | f32 Amp2 = 1.25f; 188 | f32 Amp3 = 2.25f; 189 | state *State = malloc(sizeof(state)); 190 | for (i32 N = 0; N < NUM_SAMPLES; N++) 191 | { 192 | State->Samples[N] = 0; 193 | State->Samples[N] += Amp1 * sinf(2 * PI * Freq1 * ((f32)N / NUM_SAMPLES)); 194 | State->Samples[N] += Amp2 * sinf(2 * PI * Freq2 * ((f32)N / NUM_SAMPLES)); 195 | State->Samples[N] += Amp3 * sinf(2 * PI * Freq3 * ((f32)N / NUM_SAMPLES)); 196 | State->Samples[N] /= 3; 197 | } 198 | for (i32 N = 0; N < NUM_SAMPLES; N++) 199 | { 200 | State->FourierTransform[N] = 0; 201 | } 202 | 203 | // @mainloop 204 | while(!WindowShouldClose()) 205 | { 206 | Update(State); 207 | 208 | BeginDrawing(); 209 | ClearBackground(BLACK); 210 | Draw(State); 211 | EndDrawing(); 212 | } 213 | 214 | CloseAudioDevice(); 215 | CloseWindow(); 216 | return 0; 217 | } -------------------------------------------------------------------------------- /fourier_transforms/src/main.c: -------------------------------------------------------------------------------- 1 | #include "platform.h" 2 | #include "raylib.h" 3 | #define RAYGUI_SUPPORT_ICONS 4 | #define RAYGUI_IMPLEMENTATION 5 | #include "raygui.h" 6 | 7 | #define NUM_SAMPLES 1024 8 | 9 | typedef struct state 10 | { 11 | f32 Signal[NUM_SAMPLES]; 12 | f32 FourierTransform[NUM_SAMPLES]; 13 | } state; 14 | 15 | internal void 16 | SlowFourierTransform(f32 *TimeDomain, f32 *FreqDomain, i32 Size) 17 | { 18 | // TODO: Make a optimized fast fourier transform. 19 | // 0Hz - 10Hz. 20 | for (i32 Ki = 0; Ki < Size; Ki++) 21 | { 22 | f32 K = ((f32)Ki/Size) * 10.0f; 23 | f32 SumX = 0; 24 | f32 SumY = 0; 25 | for (i32 N = 0; N < Size; N++) 26 | { 27 | f32 Sample = TimeDomain[N]; 28 | f32 Ns = (f32)N/Size; 29 | f32 Theta = 2*PI*K*Ns; 30 | f32 Magnitude = Sample; 31 | f32 X = sinf(Theta) * Magnitude; 32 | f32 Y = cosf(Theta) * Magnitude; 33 | SumX += X; 34 | SumY += Y; 35 | } 36 | FreqDomain[Ki] = SumX; 37 | } 38 | } 39 | 40 | internal void 41 | Update(state *State) 42 | { 43 | static i32 Freq1 = 4; 44 | static bool Freq1_Edit = false; 45 | static f32 Amp1 = 1; 46 | 47 | static i32 Freq2 = 0; 48 | static bool Freq2_Edit = false; 49 | static f32 Amp2 = 1; 50 | 51 | static i32 Freq3 = 0; 52 | static f32 Amp3 = 1; 53 | static bool Freq3_Edit = false; 54 | 55 | if (GuiSpinner((Rectangle){ 600, 15, 80, 30 }, NULL, &Freq1, 0, 10, Freq1_Edit)) 56 | Freq1_Edit = !Freq1_Edit; 57 | if (GuiSpinner((Rectangle){ 700, 15, 80, 30 }, NULL, &Freq2, 0, 10, Freq2_Edit)) 58 | Freq2_Edit = !Freq2_Edit; 59 | if (GuiSpinner((Rectangle){ 800, 15, 80, 30 }, NULL, &Freq3, 0, 10, Freq3_Edit)) 60 | Freq3_Edit = !Freq3_Edit; 61 | 62 | for (i32 N = 0; N < NUM_SAMPLES; N++) 63 | { 64 | State->Signal[N] = 0; 65 | State->Signal[N] += Amp1 * sinf(2 * PI * Freq1 * ((f32)N / NUM_SAMPLES)); 66 | State->Signal[N] += Amp2 * sinf(2 * PI * Freq2 * ((f32)N / NUM_SAMPLES)); 67 | State->Signal[N] += Amp3 * sinf(2 * PI * Freq3 * ((f32)N / NUM_SAMPLES)); 68 | State->Signal[N] /= 3; 69 | } 70 | } 71 | 72 | internal void 73 | Draw(state *State) 74 | { 75 | Color SignalCol = ColorAlpha(RED, 0.7f); 76 | Color BaselineCol = ColorAlpha(GRAY, 0.7f); 77 | Color CutCol = ColorAlpha(GREEN, 0.9f); 78 | Color Sum2DCol = ColorAlpha(YELLOW, 0.9f); 79 | f32 MouseX = (f32)GetMouseX(); 80 | 81 | // Draw the signal 82 | i32 SignalBaselineY = 150; 83 | i32 SignalHeight = 50; 84 | DrawLine(0, SignalBaselineY, NUM_SAMPLES, SignalBaselineY, BaselineCol); 85 | for (i32 N = 0; N < NUM_SAMPLES; N++) 86 | { 87 | f32 Sample = State->Signal[N]; 88 | DrawPixel(N, SignalBaselineY + Sample*SignalHeight, SignalCol); 89 | } 90 | 91 | // Cut Frequency 92 | f32 MaxCutFreq = 10.0f; 93 | f32 CutFreq = (MouseX/NUM_SAMPLES) * MaxCutFreq; 94 | 95 | // Draw Cuts 96 | i32 CutX = 0; 97 | i32 CutStride = max((NUM_SAMPLES/CutFreq), 1); 98 | f32 Summation[NUM_SAMPLES] = {0}; 99 | while (CutStride > 0 && CutX < NUM_SAMPLES) 100 | { 101 | DrawLine(CutX, 102 | SignalBaselineY - SignalHeight, 103 | CutX, 104 | SignalBaselineY + SignalHeight, 105 | CutCol); 106 | // Draw overlap. 107 | for (i32 N = 0; (N < CutStride) && (N+CutX < NUM_SAMPLES); N++) 108 | { 109 | f32 Sample = State->Signal[N + CutX]; 110 | DrawPixel(CutStride + N, 111 | SignalBaselineY + Sample*SignalHeight, 112 | SignalCol); 113 | Summation[N] += Sample; 114 | } 115 | CutX += CutStride; 116 | } 117 | 118 | // Draw Summation. 119 | for (i32 N = 0; N < min(CutStride, NUM_SAMPLES); N++) 120 | { 121 | f32 Sample = Summation[N]; 122 | DrawPixel(CutStride + N, 123 | SignalBaselineY + Sample*SignalHeight, 124 | CutCol); 125 | } 126 | 127 | // Draw circular wrap. 128 | i32 CircleOriginX = 512; 129 | i32 CircleOriginY = 400; 130 | f32 SumX = 0; 131 | f32 SumY = 0; 132 | for (i32 N = 0; N < NUM_SAMPLES; N++) 133 | { 134 | f32 Sample = State->Signal[N]; 135 | f32 Ns = (f32)N/NUM_SAMPLES; 136 | f32 Theta = 2*PI*CutFreq*Ns; 137 | f32 Magnitude = 200 * Sample; 138 | f32 X = sinf(Theta) * Magnitude; 139 | f32 Y = cosf(Theta) * Magnitude; 140 | 141 | SumX += X; 142 | SumY += Y; 143 | 144 | DrawPixel(X + CircleOriginX, Y + CircleOriginY, CutCol); 145 | } 146 | 147 | // Draw 2D summation. 148 | f32 Sum2DScale = 0.01f; 149 | i32 SumXFinal = (i32)(SumX*Sum2DScale) + CircleOriginX; 150 | i32 SumYFinal = (i32)(SumY*Sum2DScale) + CircleOriginY; 151 | DrawCircle(SumXFinal, 152 | SumYFinal, 153 | 5, 154 | Sum2DCol); 155 | DrawLine(CircleOriginX, 156 | CircleOriginY, 157 | SumXFinal, 158 | SumYFinal, 159 | Sum2DCol); 160 | 161 | SlowFourierTransform(&State->Signal[0], &State->FourierTransform[0], NUM_SAMPLES); 162 | 163 | // Draw the frequency domain 164 | for (i32 N = 0; N < NUM_SAMPLES; N++) 165 | { 166 | f32 F = State->FourierTransform[N]; 167 | DrawPixel(N, 168 | 650 - (F * 1), 169 | Sum2DCol); 170 | } 171 | 172 | DrawText(TextFormat("Cut Freq: %.2fHz", CutFreq), 173 | 15, 174 | 15, 175 | 20, 176 | RAYWHITE); 177 | } 178 | 179 | i32 180 | main(i32 argc, char **argv) 181 | { 182 | const i32 screen_width = NUM_SAMPLES; 183 | const i32 screen_height = 768; 184 | InitWindow(screen_width, screen_height, "Raylib"); 185 | SetTargetFPS(60); 186 | InitAudioDevice(); 187 | 188 | state *State = malloc(sizeof(state)); 189 | for (i32 N = 0; N < NUM_SAMPLES; N++) 190 | { 191 | State->FourierTransform[N] = 0; 192 | } 193 | 194 | while(!WindowShouldClose()) 195 | { 196 | Update(State); 197 | 198 | BeginDrawing(); 199 | ClearBackground(BLACK); 200 | Draw(State); 201 | EndDrawing(); 202 | } 203 | 204 | CloseAudioDevice(); 205 | CloseWindow(); 206 | return 0; 207 | } -------------------------------------------------------------------------------- /programming_memory_tutorial/about.txt: -------------------------------------------------------------------------------- 1 | ################################## 2 | ### HOW TO PROGRAM A COMPUTER ### 3 | ### SIDEBAR 1 ### 4 | ################################## 5 | 6 | Luke Perkin. 7 | Freelance Technical Designer in the games industry. 8 | 9 | == Understand Proccesors. 10 | == Understand Memory. 11 | == Understand Instructions. 12 | 13 | Find me on twitter: @locogameluke -------------------------------------------------------------------------------- /programming_memory_tutorial/asc.txt: -------------------------------------------------------------------------------- 1 | write(1, 0); 2 | wripe(1, REG_B); 3 | write(16, 70); 4 | checkpoint(REG_C); 5 | copy_indirect(REG_A, REG_B); 6 | add(REG_B, 0, REG_B); 7 | add(REG_A, 0, REG_A); 8 | is_equal(REG_A, 70, REG_D); 9 | jump_if_zero(REG_C, REG_D); 10 | write(0, 0); -------------------------------------------------------------------------------- /programming_memory_tutorial/bin/fantasy_machine.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/bin/fantasy_machine.exe -------------------------------------------------------------------------------- /programming_memory_tutorial/bubblesort.txt: -------------------------------------------------------------------------------- 1 | label(ONE, 70); 2 | label(TAB, 71); 3 | label(START, 3); 4 | label(END, 30); 5 | write_region(0, END, 71); 6 | write(9, TAB); 7 | print_numbers(START, END); 8 | print_characters(TAB, TAB); 9 | write(0, 1); // setup sort 10 | write(0, 2); 11 | write(START, REG_A); 12 | write(END, REG_B); 13 | write(1, ONE); 14 | checkpoint(SORT); // sort 15 | copy_indirect_to_cell(REG_A, 1); 16 | add(REG_A, ONE, REG_A); 17 | copy_indirect_to_cell(REG_A, 2); 18 | is_less_than(1, 2, REG_C); 19 | jump_if_above_zero(AHEAD, REG_C); 20 | copy_cell_to_indirect(1, REG_A); 21 | subtract(REG_A, ONE, REG_A); 22 | copy_cell_to_indirect(2, REG_A); 23 | add(REG_A, ONE, REG_A); 24 | checkpoint(AHEAD); 25 | is_equal(REG_A, REG_B, REG_D); 26 | jump_if_zero(SORT, REG_D); 27 | subtract(REG_B, ONE, REG_B); 28 | write(START, REG_A); 29 | is_equal(REG_B, REG_A, REG_D); 30 | jump_if_zero(SORT, REG_D); 31 | print_numbers(START, END); 32 | print_characters(TAB, TAB); -------------------------------------------------------------------------------- /programming_memory_tutorial/build_odin.bat: -------------------------------------------------------------------------------- 1 | call odin build fantasy_machine.odin 2 | -------------------------------------------------------------------------------- /programming_memory_tutorial/build_then_run.bat: -------------------------------------------------------------------------------- 1 | tcc -o pmt.exe main.c -Iinclude -lraylib -lmsvcrt -lraylib -lopengl32 -lgdi32 -lkernel32 -lshell32 -luser32 -lwinmm -Wl,-subsystem=gui -std=c99 -g -run -------------------------------------------------------------------------------- /programming_memory_tutorial/click_01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/click_01.wav -------------------------------------------------------------------------------- /programming_memory_tutorial/click_02.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/click_02.wav -------------------------------------------------------------------------------- /programming_memory_tutorial/code.txt: -------------------------------------------------------------------------------- 1 | label(ONE, 70); 2 | label(TAB, 71); 3 | label(START, 3); 4 | label(END, 10); 5 | write_region(0, END, 71); 6 | write(9, TAB); 7 | print_numbers(START, END); 8 | print_characters(TAB, TAB); 9 | write(0, 1); // setup sort 10 | write(0, 2); 11 | write(START, REG_A); 12 | write(END, REG_B); 13 | write(1, ONE); 14 | checkpoint(SORT); // sort 15 | copy_indirect_to_cell(REG_A, 1); 16 | add(REG_A, ONE, REG_A); 17 | copy_indirect_to_cell(REG_A, 2); 18 | is_less_than(1, 2, REG_C); 19 | jump_if_above_zero(AHEAD, REG_C); 20 | copy_cell_to_indirect(1, REG_A); 21 | subtract(REG_A, ONE, REG_A); 22 | copy_cell_to_indirect(2, REG_A); 23 | add(REG_A, ONE, REG_A); 24 | checkpoint(AHEAD); 25 | is_equal(REG_A, REG_B, REG_D); 26 | jump_if_zero(SORT, REG_D); 27 | subtract(REG_B, ONE, REG_B); 28 | write(START, REG_A); 29 | is_equal(REG_B, REG_A, REG_D); 30 | jump_if_zero(SORT, REG_D); 31 | print_numbers(START, END); 32 | print_characters(TAB, TAB); -------------------------------------------------------------------------------- /programming_memory_tutorial/conversion.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | unsigned char REG_A = 1; 6 | unsigned char REG_B = 0; 7 | unsigned char REG_C = 0; 8 | unsigned char REG_D = 0; 9 | unsigned char cells[72]; 10 | REG_C = 11; 11 | REG_B = REG_A; 12 | 13 | while( REG_A > 0 ) 14 | { 15 | cells[REG_A] = REG_A; 16 | REG_A += REG_B; 17 | if (REG_A == REG_C) 18 | { 19 | break; 20 | } 21 | } 22 | 23 | printf("%i, %i, %i, %i", cells[1], cells[2], cells[3], cells[4]); 24 | 25 | // the end. 26 | return 0; 27 | } -------------------------------------------------------------------------------- /programming_memory_tutorial/fantasy_machine.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/fantasy_machine.exe -------------------------------------------------------------------------------- /programming_memory_tutorial/fantasy_machine.odin: -------------------------------------------------------------------------------- 1 | package main 2 | import "raylib" 3 | import "core:fmt" 4 | import "core:mem" 5 | import "core:strings" 6 | import "core:math/linalg" 7 | import "core:math/rand" 8 | 9 | NUM_CELL_ROWS :: 6; 10 | NUM_CELL_COLS :: 12; 11 | NUM_CELLS :: NUM_CELL_ROWS*NUM_CELL_COLS; 12 | NUM_INSTRUCTIONS :: 64; 13 | NUM_SNAPSHOTS :: 256*16; 14 | NUM_REGISTERS :: 4; 15 | NUM_LAST_ACCESSED_CELLS :: 4; 16 | 17 | cell_view_type :: enum 18 | { 19 | Number, 20 | Character, 21 | Count 22 | } 23 | 24 | instruction_type :: enum 25 | { 26 | Nop, 27 | Write, 28 | WriteRegion, 29 | Checkpoint, 30 | CopyCellCell, 31 | CopyCellIndirect, 32 | CopyIndirectCell, 33 | CopyIndirectIndirect, 34 | Add, 35 | Sub, 36 | Mul, 37 | Div, 38 | Mod, 39 | Equal, 40 | Less, 41 | Great, 42 | Or, 43 | And, 44 | JumpIf, 45 | JumpNotIf, 46 | Swap, 47 | PrintNumbers, 48 | PrintCharacters, 49 | PrintText, 50 | Load, 51 | Halt 52 | } 53 | 54 | instruction :: struct 55 | { 56 | Type : instruction_type, 57 | Idx0, Idx1, Idx2 : u8, 58 | Val0, Val1 : u8, 59 | Text0 : string 60 | } 61 | 62 | cell_data_snapshot :: struct 63 | { 64 | CellData : ^u8, 65 | Output : ^i8, 66 | InstructionIdx : uint, 67 | FakeCycles : uint 68 | } 69 | 70 | jump_label :: struct 71 | { 72 | Key : string, 73 | Value : i32 74 | } 75 | 76 | app_state :: struct 77 | { 78 | CellData : [NUM_CELLS]u8, 79 | Snapshots : [NUM_SNAPSHOTS]cell_data_snapshot, 80 | Instructions : [NUM_INSTRUCTIONS]instruction, 81 | LastAccessedCells : [NUM_LAST_ACCESSED_CELLS]int, 82 | RegistersStartIdx : int, 83 | JumpLabels : map[string]uint, 84 | InstructionIdx : uint, 85 | InstructionCount : uint, 86 | SnapshotIdx : uint, 87 | IsHalted : bool, 88 | CellViewType : cell_view_type, 89 | } 90 | 91 | main :: proc() 92 | { 93 | using raylib; 94 | SCREEN_WIDTH :: 1400; 95 | SCREEN_HEIGHT :: 768; 96 | TARGET_FPS :: 30; 97 | 98 | InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Fantasy Machine"); 99 | defer CloseWindow(); 100 | 101 | SetTargetFPS(TARGET_FPS); 102 | Click01Sound : Sound = LoadSound("click_01.wav"); 103 | SetSoundVolume(Click01Sound, 0.01); 104 | Click02Sound : Sound = LoadSound("click_02.wav"); 105 | SetSoundVolume(Click02Sound, 0.01); 106 | 107 | AppState : ^app_state = new(app_state); 108 | defer free(AppState); 109 | 110 | // Randomize initial cell data. 111 | for _, Idx in AppState.CellData 112 | { 113 | AppState.CellData[Idx] = cast(u8)rand.uint32(); 114 | } 115 | 116 | for !WindowShouldClose() 117 | { 118 | UpdateLoop(AppState); 119 | DrawLoop(AppState); 120 | } 121 | } 122 | 123 | UpdateLoop :: proc(AppState : ^app_state) 124 | { 125 | using raylib; 126 | KEY_CHANGE_VIEW : i32 : cast(i32)raylib.KeyboardKey.KEY_SPACE; 127 | KEY_NEXT_STEP : i32 : cast(i32)raylib.KeyboardKey.KEY_RIGHT; 128 | KEY_NEXT_FAST : i32 : cast(i32)raylib.KeyboardKey.KEY_DOWN; 129 | KEY_PREV_STEP : i32 : cast(i32)raylib.KeyboardKey.KEY_LEFT; 130 | KEY_PREV_FAST : i32 : cast(i32)raylib.KeyboardKey.KEY_UP; 131 | 132 | if IsKeyPressed(KEY_CHANGE_VIEW) 133 | { 134 | val := cast(i32)AppState.CellViewType; 135 | val += 1; 136 | if cast(cell_view_type)val == cell_view_type.Count 137 | { 138 | val = 0; 139 | } 140 | AppState.CellViewType = cast(cell_view_type)val; 141 | } 142 | 143 | if (IsKeyPressed(KEY_NEXT_STEP) || IsKeyDown(KEY_NEXT_FAST)) && 144 | (AppState.InstructionIdx < AppState.InstructionCount) && 145 | (!AppState.IsHalted) 146 | { 147 | 148 | } 149 | else if (IsKeyPressed(KEY_PREV_STEP) || IsKeyDown(KEY_PREV_FAST)) && 150 | (AppState.InstructionIdx > 0) 151 | { 152 | for I in 0..= AppState.InstructionCount 303 | { 304 | continue; 305 | } 306 | Instruction : instruction = AppState.Instructions[AppState.InstructionIdx]; 307 | { 308 | using Instruction; 309 | IsIdx0Indirect : bool = ( 310 | Type == instruction_type.CopyIndirectCell || 311 | Type == instruction_type.CopyIndirectIndirect); 312 | IsIdx1Indirect : bool = ( 313 | Type == instruction_type.CopyCellIndirect || 314 | Type == instruction_type.CopyIndirectIndirect); 315 | IsIdx0RefThisCell : bool = (cast(u8)J == AppState.CellData[Idx0]); 316 | IsIdx1RefThisCell : bool = (cast(u8)J == AppState.CellData[Idx1]); 317 | IsIdx0ARegister : bool = (Idx0 >= cast(u8)AppState.RegistersStartIdx); 318 | IsIdx1ARegister : bool = (Idx1 >= cast(u8)AppState.RegistersStartIdx); 319 | IsIndirectRegister : bool = ( 320 | (IsIdx0Indirect && IsIdx0RefThisCell && IsIdx0ARegister) || 321 | (IsIdx1Indirect && IsIdx1RefThisCell && IsIdx1ARegister)); 322 | IsIndirect : bool = ( 323 | (IsIdx0Indirect && IsIdx0RefThisCell) || 324 | (IsIdx1Indirect && IsIdx1RefThisCell)); 325 | if IsIndirectRegister 326 | { 327 | RegisterIdx := IsIdx0RefThisCell ? (Idx0 - NUM_CELLS) : (Idx1 - NUM_CELLS); 328 | DrawRectangleRec(FillRect, CELL_INDIRECT_HIGHLIGHT_COLOR); 329 | RegisterOrigin := Vector2{ 330 | x = REGISTER_SPACING_X * cast(f32)RegisterIdx, 331 | y = RegisterHighlightRect.height 332 | }; 333 | DrawLine(cast(i32)(RegisterHighlightRect.x + RegisterOrigin.x), 334 | cast(i32)(RegisterHighlightRect.y + RegisterOrigin.y), 335 | cast(i32)FillRect.x, 336 | cast(i32)FillRect.y, 337 | CELL_INDIRECT_HIGHLIGHT_COLOR); 338 | } 339 | else if IsIndirect 340 | { 341 | SelectedIdx : u8 = (IsIdx0RefThisCell) ? Idx0 : Idx1; 342 | X, Y := XYFromIndex(cast(int)SelectedIdx); 343 | Xp : f32 = ALL_CELLS_X + X * (CELL_WIDTH - CELL_LINE_WIDTH); 344 | Yp : f32 = ALL_CELLS_Y + Y * (CELL_HEIGHT - CELL_LINE_WIDTH); 345 | DrawRectangleRec(FillRect, CELL_INDIRECT_HIGHLIGHT_COLOR); 346 | DrawLine(cast(i32)(Xp + (CELL_WIDTH*0.5)), 347 | cast(i32)(Yp + (CELL_HEIGHT*0.5)), 348 | cast(i32)FillRect.x, 349 | cast(i32)FillRect.y, 350 | CELL_INDIRECT_HIGHLIGHT_COLOR); 351 | } 352 | } 353 | } 354 | LineLeft := Vector2{ 355 | x = CellRect.x, 356 | y = CellRect.y + CELL_ADDRESS_LINE_LOCAL_Y 357 | }; 358 | LineRight := Vector2{ 359 | x = CellRect.x + CellRect.width, 360 | y = CellRect.y + CELL_ADDRESS_LINE_LOCAL_Y 361 | }; 362 | DrawLineEx(LineLeft, LineRight, 1, CELL_COLOR); 363 | AddressText : string = fmt.aprintf("%02d", CellIdx); 364 | defer delete(AddressText); 365 | AddressTextWidth : f32 = cast(f32)MeasureString(AddressText, CELL_ADDRESS_FONT_SIZE); 366 | HalfCellWidth : f32 = CellRect.width * 0.5; 367 | HalfCellHeight : f32 = CellRect.height * 0.5; 368 | DrawString(AddressText, 369 | cast(i32)(CellRect.x + HalfCellWidth - (AddressTextWidth*0.5)), 370 | cast(i32)(CellRect.y + (CELL_ADDRESS_LINE_LOCAL_Y*0.5) - (CELL_ADDRESS_FONT_SIZE*0.5)), 371 | CELL_ADDRESS_FONT_SIZE, 372 | CELL_COLOR); 373 | 374 | DataX : f32 = CellRect.x + HalfCellWidth; 375 | DataY : f32 = CellRect.y + 376 | CELL_ADDRESS_LINE_LOCAL_Y + 377 | ((CellRect.height - CELL_ADDRESS_LINE_LOCAL_Y) * 0.5); 378 | if CellIdx == 0 379 | { 380 | DrawString("!", cast(i32)DataX, cast(i32)DataY - 15, 30, RED); 381 | } 382 | else 383 | { 384 | DataText : string = ---; 385 | #partial switch AppState.CellViewType 386 | { 387 | case .Number: 388 | DataText = fmt.aprintf("%d", AppState.CellData[CellIdx]); 389 | case .Character: 390 | DataText = fmt.aprintf("%c", AppState.CellData[CellIdx]); 391 | } 392 | 393 | DataTextWidth : f32 = cast(f32)MeasureString(DataText, CELL_DATA_FONT_SIZE); 394 | DrawString(DataText, 395 | cast(i32)(DataX - (DataTextWidth*0.5)), 396 | cast(i32)(DataY - (CELL_DATA_FONT_SIZE*0.5)), 397 | CELL_DATA_FONT_SIZE, 398 | CELL_COLOR); 399 | delete(DataText); 400 | } 401 | } 402 | } 403 | 404 | XYFromIndex :: proc(Idx : int) -> (f32, f32) 405 | { 406 | return cast(f32)(Idx % NUM_CELL_COLS), cast(f32)(Idx / NUM_CELL_COLS); 407 | } -------------------------------------------------------------------------------- /programming_memory_tutorial/hello.txt: -------------------------------------------------------------------------------- 1 | label(ONE, 71); 2 | label(START, 13); 3 | label(END, 17); 4 | write(1, ONE); 5 | write(START, REG_A); 6 | write('H', REG_B); 7 | copy_cell_to_indirect(REG_B, REG_A); 8 | print_characters(REG_B, REG_B); 9 | add(REG_A, ONE, REG_A); 10 | write('E', REG_B); 11 | copy_cell_to_indirect(REG_B, REG_A); 12 | print_characters(REG_B, REG_B); 13 | add(REG_A, ONE, REG_A); 14 | write('L', REG_B); 15 | copy_cell_to_indirect(REG_B, REG_A); 16 | print_characters(REG_B, REG_B); 17 | add(REG_A, ONE, REG_A); 18 | write('L', REG_B); 19 | copy_cell_to_indirect(REG_B, REG_A); 20 | print_characters(REG_B, REG_B); 21 | add(REG_A, ONE, REG_A); 22 | write('O', REG_B); 23 | copy_cell_to_indirect(REG_B, REG_A); 24 | print_characters(REG_B, REG_B); -------------------------------------------------------------------------------- /programming_memory_tutorial/lib/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/lib/raylib.lib -------------------------------------------------------------------------------- /programming_memory_tutorial/main.c: -------------------------------------------------------------------------------- 1 | #include // standard input and ouput. 2 | #include 3 | #include 4 | #include "raylib.h" 5 | 6 | #define STB_DS_IMPLEMENTATION 7 | #include "stb_ds.h" 8 | 9 | #define CODE_FONT_SIZE 10 10 | #define SCREEN_WIDTH 1400 11 | #define SCREEN_HEIGHT 768 12 | #define MAX_INSTRUCTIONS 64 13 | #define MAX_SNAPSHOTS 256*16 14 | #define MAX_OUTPUT_SIZE 256*16 15 | #define MAX_LAST_ACCESSED_CELLS 4 16 | 17 | typedef enum { 18 | CELL_DATA_NUMBER, 19 | CELL_DATA_CHARACTER 20 | } CellDataType; 21 | 22 | typedef enum { 23 | INS_NOP, 24 | INS_WRITE, 25 | INS_WRITE_REGION, 26 | INS_CHECKPOINT, 27 | INS_COPY_CELL_CELL, 28 | INS_COPY_CELL_INDIRECT, 29 | INS_COPY_INDIRECT_CELL, 30 | INS_COPY_INDIRECT_INDIRECT, 31 | INS_ADD, 32 | INS_SUB, 33 | INS_MUL, 34 | INS_DIV, 35 | INS_MOD, 36 | INS_EQUAL, 37 | INS_LESS, 38 | INS_GREAT, 39 | INS_OR, 40 | INS_AND, 41 | INS_JUMP_IF, 42 | INS_JUMP_NOT_IF, 43 | INS_SWAP, 44 | INS_PRINT_NUMBERS, 45 | INS_PRINT_CHARACTERS, 46 | INS_PRINT_TEXT, 47 | INS_LOAD, 48 | INS_HALT 49 | } InstructionType; 50 | 51 | typedef struct { 52 | InstructionType type; 53 | int idx0; 54 | int idx1; 55 | int idx2; 56 | unsigned char val0; 57 | unsigned char val1; 58 | const char* text0; 59 | } Instruction; 60 | 61 | typedef struct { 62 | unsigned char* cell_data; 63 | char* output; 64 | size_t instruction_idx; 65 | size_t fake_cycles; 66 | } CellDataSnapshot; 67 | 68 | typedef struct { 69 | char* key; 70 | int value; 71 | } JumpLabel; 72 | 73 | static unsigned char* cell_data; 74 | static CellDataSnapshot* cell_data_snapshots; 75 | static Instruction* instructions; 76 | static size_t instruction_idx = 0; 77 | static size_t instruction_count = 0; 78 | static size_t snapshot_idx = 0; 79 | static size_t last_accessed_cells[MAX_LAST_ACCESSED_CELLS]; 80 | static size_t fake_cycles = 0; 81 | static char my_output[MAX_OUTPUT_SIZE]; 82 | static char* runtime_file; 83 | static bool is_runtime_file_loaded = false; 84 | static bool is_halted = false; 85 | static JumpLabel* jump_labels = NULL; 86 | 87 | void _write(unsigned char val, int idx) 88 | { 89 | cell_data[idx] = val; 90 | } 91 | 92 | void _write_region(unsigned char val, int idx0, int idx1) 93 | { 94 | for (int i = idx0; i < idx1; i++) 95 | { 96 | cell_data[i] = val; 97 | fake_cycles += 1; 98 | } 99 | } 100 | 101 | void _checkpoint(int idx) 102 | { 103 | cell_data[idx] = instruction_idx; 104 | } 105 | 106 | void _copy_cell_cell(int src, int dest) 107 | { 108 | cell_data[dest] = cell_data[src]; 109 | } 110 | 111 | void _copy_cell_indirect(int src, int dest) 112 | { 113 | cell_data[cell_data[dest]] = cell_data[src]; 114 | } 115 | 116 | void _copy_indirect_cell(int src, int dest) 117 | { 118 | cell_data[dest] = cell_data[cell_data[src]]; 119 | } 120 | 121 | void _copy_indirect_indirect(int src, int dest) 122 | { 123 | cell_data[cell_data[dest]] = cell_data[cell_data[src]]; 124 | } 125 | 126 | void _add(int left, int right, int output) 127 | { 128 | cell_data[output] = cell_data[left] + cell_data[right]; 129 | } 130 | 131 | void _subtract(int left, int right, int output) 132 | { 133 | cell_data[output] = cell_data[left] - cell_data[right]; 134 | } 135 | 136 | void _multiply(int left, int right, int output) 137 | { 138 | cell_data[output] = cell_data[left] * cell_data[right]; 139 | } 140 | 141 | void _divide(int left, int right, int output) 142 | { 143 | cell_data[output] = cell_data[left] / cell_data[right]; 144 | } 145 | 146 | void _modulo(int left, int right, int output) 147 | { 148 | cell_data[output] = cell_data[left] % cell_data[right]; 149 | } 150 | 151 | void _is_equal(int left, int right, int output) 152 | { 153 | cell_data[output] = cell_data[left] == cell_data[right]; 154 | } 155 | 156 | void _is_less_than(int left, int right, int output) 157 | { 158 | cell_data[output] = cell_data[left] < cell_data[right]; 159 | } 160 | 161 | void _is_greater_than(int left, int right, int output) 162 | { 163 | cell_data[output] = cell_data[left] > cell_data[right]; 164 | } 165 | 166 | void _is_either_above_zero(int left, int right, int output) 167 | { 168 | cell_data[output] = cell_data[left] || cell_data[right]; 169 | } 170 | 171 | void _is_both_above_zero(int left, int right, int output) 172 | { 173 | cell_data[output] = cell_data[left] && cell_data[right]; 174 | } 175 | 176 | void _jump_if_above_zero(const char* jump_label, int idx) 177 | { 178 | if (cell_data[idx] > 0) 179 | { 180 | instruction_idx = shget(jump_labels, jump_label); 181 | } 182 | } 183 | 184 | void _jump_if_zero(const char* jump_label, int idx) 185 | { 186 | if (cell_data[idx] == 0) 187 | { 188 | instruction_idx = shget(jump_labels, jump_label); 189 | } 190 | } 191 | 192 | void _swap(int idx0, int idx1) 193 | { 194 | int temp = cell_data[idx0]; 195 | cell_data[idx0] = cell_data[idx1]; 196 | cell_data[idx1] = temp; 197 | } 198 | 199 | void _print_numbers(int idx0, int idx1) 200 | { 201 | for (int i = idx0; i <= idx1; i++) 202 | { 203 | const char* text = TextFormat("%i,", cell_data[i]); 204 | unsigned int output_end = TextLength(my_output); 205 | TextCopy(my_output + output_end, text); 206 | fake_cycles += 1; 207 | } 208 | } 209 | 210 | void _print_characters(int idx0, int idx1) 211 | { 212 | unsigned int output_end = TextLength(my_output); 213 | for (int i = idx0; i <= idx1; i++) 214 | { 215 | my_output[output_end++] = cell_data[i]; 216 | fake_cycles += 1; 217 | } 218 | } 219 | 220 | void _print_text(int idx0, int cell_count) 221 | { 222 | unsigned int output_end = TextLength(my_output); 223 | for (int i = idx0; i <= cell_count; i++) 224 | { 225 | if (cell_data[i] == 0) break; 226 | my_output[output_end++] = cell_data[i]; 227 | fake_cycles += 1; 228 | } 229 | } 230 | 231 | void _load(const char* file, int cell_count) 232 | { 233 | if (is_runtime_file_loaded) UnloadFileText(runtime_file); 234 | runtime_file = LoadFileText(file); 235 | is_runtime_file_loaded = true; 236 | size_t len = TextLength(runtime_file)+1; 237 | for (int i = 1; i < cell_count && i < len; i++) 238 | { 239 | cell_data[i] = runtime_file[i-1]; 240 | fake_cycles += 1; 241 | } 242 | int max_len = len; 243 | if (max_len >= cell_count) max_len = cell_count-1; 244 | cell_data[max_len] = 0; 245 | } 246 | 247 | void nop() 248 | { 249 | Instruction instruction = { .type = INS_NOP, .idx0 = -1, .idx1 = -1, .idx2 = -1 }; 250 | instructions[instruction_count++] = instruction; 251 | } 252 | 253 | void write(unsigned char val, int idx) 254 | { 255 | Instruction instruction = { 256 | .type = INS_WRITE, 257 | .val0 = val, 258 | .idx0 = idx, 259 | .idx1 = -1, 260 | .idx2 = -1 261 | }; 262 | instructions[instruction_count++] = instruction; 263 | } 264 | 265 | void copy_cell_to_cell(int src, int dest) 266 | { 267 | Instruction instruction = { 268 | .type = INS_COPY_CELL_CELL, 269 | .idx0 = src, 270 | .idx1 = dest, 271 | .idx2 = -1 272 | }; 273 | instructions[instruction_count++] = instruction; 274 | } 275 | 276 | void copy_cell_to_indirect(int src, int dest) 277 | { 278 | Instruction instruction = { 279 | .type = INS_COPY_CELL_INDIRECT, 280 | .idx0 = src, 281 | .idx1 = dest, 282 | .idx2 = -1 283 | }; 284 | instructions[instruction_count++] = instruction; 285 | } 286 | 287 | void copy_indirect_to_cell(int src, int dest) 288 | { 289 | Instruction instruction = { 290 | .type = INS_COPY_INDIRECT_CELL, 291 | .idx0 = src, 292 | .idx1 = dest, 293 | .idx2 = -1 294 | }; 295 | instructions[instruction_count++] = instruction; 296 | } 297 | 298 | void copy_indirect_to_indirect(int src, int dest) 299 | { 300 | Instruction instruction = { 301 | .type = INS_COPY_INDIRECT_INDIRECT, 302 | .idx0 = src, 303 | .idx1 = dest, 304 | .idx2 = -1 305 | }; 306 | instructions[instruction_count++] = instruction; 307 | } 308 | 309 | void _left_right_instruction(InstructionType type, int left, int right, int output) 310 | { 311 | Instruction instruction = { 312 | .type = type, 313 | .idx0 = left, 314 | .idx1 = right, 315 | .idx2 = output 316 | }; 317 | instructions[instruction_count++] = instruction; 318 | } 319 | 320 | void _two_index_instruction(InstructionType type, int idx0, int idx1) 321 | { 322 | Instruction instruction = { 323 | .type = type, 324 | .idx0 = idx0, 325 | .idx1 = idx1, 326 | .idx2 = -1 327 | }; 328 | instructions[instruction_count++] = instruction; 329 | } 330 | 331 | void add(int left, int right, int output) 332 | { 333 | _left_right_instruction(INS_ADD, left, right, output); 334 | } 335 | 336 | void subtract(int left, int right, int output) 337 | { 338 | _left_right_instruction(INS_SUB, left, right, output); 339 | } 340 | 341 | void multiply(int left, int right, int output) 342 | { 343 | _left_right_instruction(INS_MUL, left, right, output); 344 | } 345 | 346 | void divide(int left, int right, int output) 347 | { 348 | _left_right_instruction(INS_DIV, left, right, output); 349 | } 350 | 351 | void modulo(int left, int right, int output) 352 | { 353 | _left_right_instruction(INS_MOD, left, right, output); 354 | } 355 | 356 | void is_equal(int left, int right, int output) 357 | { 358 | _left_right_instruction(INS_EQUAL, left, right, output); 359 | } 360 | 361 | void is_less_than(int left, int right, int output) 362 | { 363 | _left_right_instruction(INS_LESS, left, right, output); 364 | } 365 | 366 | void is_greater_than(int left, int right, int output) 367 | { 368 | _left_right_instruction(INS_GREAT, left, right, output); 369 | } 370 | 371 | void is_either_above_zero(int left, int right, int output) 372 | { 373 | _left_right_instruction(INS_OR, left, right, output); 374 | } 375 | 376 | void is_both_above_zero(int left, int right, int output) 377 | { 378 | _left_right_instruction(INS_AND, left, right, output); 379 | } 380 | 381 | void jump_if_above_zero(const char* jump_label, int idx) 382 | { 383 | Instruction instruction = { 384 | .type = INS_JUMP_IF, 385 | .text0 = jump_label, 386 | .idx0 = idx, 387 | .idx1 = -1, 388 | .idx2 = -1 389 | }; 390 | instructions[instruction_count++] = instruction; 391 | } 392 | 393 | void jump_if_zero(const char* jump_label, int idx) 394 | { 395 | Instruction instruction = { 396 | .type = INS_JUMP_NOT_IF, 397 | .text0 = jump_label, 398 | .idx0 = idx, 399 | .idx1 = -1, 400 | .idx2 = -1 401 | }; 402 | instructions[instruction_count++] = instruction; 403 | } 404 | 405 | void swap(int idx0, int idx1) 406 | { 407 | _two_index_instruction(INS_SWAP, idx0, idx1); 408 | } 409 | 410 | void print_numbers(int idx0, int idx1) 411 | { 412 | _two_index_instruction(INS_PRINT_NUMBERS, idx0, idx1); 413 | } 414 | 415 | void print_characters(int idx0, int idx1) 416 | { 417 | _two_index_instruction(INS_PRINT_CHARACTERS, idx0, idx1); 418 | } 419 | 420 | void print_text(int idx0) 421 | { 422 | Instruction instruction = { 423 | .type = INS_PRINT_TEXT, 424 | .idx0 = idx0, 425 | .idx1 = -1, 426 | .idx2 = -1 427 | }; 428 | instructions[instruction_count++] = instruction; 429 | } 430 | 431 | void write_region(unsigned char val, int idx0, int idx1) 432 | { 433 | Instruction instruction = { 434 | .type = INS_WRITE_REGION, 435 | .val0 = val, 436 | .idx0 = idx0, 437 | .idx1 = idx1, 438 | .idx2 = -1 439 | }; 440 | instructions[instruction_count++] = instruction; 441 | } 442 | 443 | void load(const char* file) 444 | { 445 | Instruction instruction = { 446 | .type = INS_LOAD, 447 | .text0 = file, 448 | .idx0 = -1, 449 | .idx1 = -1, 450 | .idx2 = -1 451 | }; 452 | instructions[instruction_count++] = instruction; 453 | } 454 | 455 | void halt() 456 | { 457 | Instruction instruction = { 458 | .type = INS_HALT, 459 | .idx0 = -1, 460 | .idx1 = -1, 461 | .idx2 = -1 462 | }; 463 | instructions[instruction_count++] = instruction; 464 | } 465 | 466 | #define and is_both_above_zero 467 | #define or is_either_above_zero 468 | #define label(id, idx) int id = idx; nop(); 469 | #define relabel(id, idx) id = idx; nop(); 470 | #define dereference(idx0, idx1) copy_indirect_to_cell(idx0, idx1); 471 | #define checkpoint(name) shput(jump_labels, #name, instruction_count); nop(); 472 | #define jump_if_above_zero(name, idx) jump_if_above_zero(#name, idx); 473 | #define jump_if_zero(name, idx) jump_if_zero(#name, idx); 474 | #define cell 475 | 476 | void execute_instruction(Instruction ins, int cell_count) 477 | { 478 | const bool is_idx0_mem = (ins.idx0 < cell_count && ins.idx0 != -1); 479 | const bool is_idx1_mem = (ins.idx1 < cell_count && ins.idx1 != -1); 480 | const bool is_idx2_mem = (ins.idx2 < cell_count && ins.idx2 != -1); 481 | if (is_idx0_mem || is_idx1_mem || is_idx2_mem) 482 | { 483 | fake_cycles += 1; 484 | } 485 | 486 | switch(ins.type) 487 | { 488 | case INS_WRITE: _write(ins.val0, ins.idx0); break; 489 | case INS_WRITE_REGION: _write_region(ins.val0, ins.idx0, ins.idx1); break; 490 | case INS_CHECKPOINT: _checkpoint(ins.idx0); break; 491 | case INS_COPY_CELL_CELL: _copy_cell_cell(ins.idx0, ins.idx1); break; 492 | case INS_COPY_CELL_INDIRECT: _copy_cell_indirect(ins.idx0, ins.idx1); break; 493 | case INS_COPY_INDIRECT_CELL: _copy_indirect_cell(ins.idx0, ins.idx1); break; 494 | case INS_COPY_INDIRECT_INDIRECT: _copy_indirect_indirect(ins.idx0, ins.idx1); break; 495 | case INS_ADD: _add(ins.idx0, ins.idx1, ins.idx2); break; 496 | case INS_SUB: _subtract(ins.idx0, ins.idx1, ins.idx2); break; 497 | case INS_MUL: _multiply(ins.idx0, ins.idx1, ins.idx2); break; 498 | case INS_DIV: _divide(ins.idx0, ins.idx1, ins.idx2); break; 499 | case INS_MOD: _modulo(ins.idx0, ins.idx1, ins.idx2); break; 500 | case INS_EQUAL: _is_equal(ins.idx0, ins.idx1, ins.idx2); break; 501 | case INS_LESS: _is_less_than(ins.idx0, ins.idx1, ins.idx2); break; 502 | case INS_GREAT: _is_greater_than(ins.idx0, ins.idx1, ins.idx2); break; 503 | case INS_OR: _is_either_above_zero(ins.idx0, ins.idx1, ins.idx2); break; 504 | case INS_AND: _is_both_above_zero(ins.idx0, ins.idx1, ins.idx2); break; 505 | case INS_JUMP_IF: _jump_if_above_zero(ins.text0, ins.idx0); break; 506 | case INS_JUMP_NOT_IF: _jump_if_zero(ins.text0, ins.idx0); break; 507 | case INS_SWAP: _swap(ins.idx0, ins.idx1); break; 508 | case INS_PRINT_NUMBERS: _print_numbers(ins.idx0, ins.idx1); break; 509 | case INS_PRINT_CHARACTERS: _print_characters(ins.idx0, ins.idx1); break; 510 | case INS_PRINT_TEXT: _print_text(ins.idx0, cell_count); break; 511 | case INS_LOAD: _load(ins.text0, cell_count); break; 512 | case INS_HALT: is_halted = true; break; 513 | } 514 | } 515 | 516 | void update_accessed_cells() 517 | { 518 | last_accessed_cells[0] = instructions[instruction_idx].idx0; 519 | last_accessed_cells[1] = instructions[instruction_idx].idx1; 520 | last_accessed_cells[2] = instructions[instruction_idx].idx2; 521 | } 522 | 523 | void main() 524 | { 525 | InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Programming Memory"); 526 | SetTargetFPS(30); 527 | InitAudioDevice(); 528 | Sound click01_sound = LoadSound("click_01.wav"); 529 | SetAudioStreamVolume(click01_sound.stream, 0.01f); 530 | Sound click02_sound = LoadSound("click_02.wav"); 531 | SetAudioStreamVolume(click02_sound.stream, 0.01f); 532 | 533 | CellDataType cell_data_type = CELL_DATA_NUMBER; 534 | const int num_registers = 4; 535 | const int cells_per_row = 12; 536 | const int cell_rows = 6; 537 | const int cell_count = cells_per_row * cell_rows; 538 | const int cell_data_length = cell_count + num_registers; 539 | cell_data = (unsigned char*)malloc(cell_data_length * sizeof(unsigned char)); 540 | for (int i = 0; i < cell_count; i++) 541 | { 542 | cell_data[i] = GetRandomValue(0, 255); 543 | } 544 | cell_data[0] = 0; 545 | cell_data_snapshots = (CellDataSnapshot*)malloc(MAX_SNAPSHOTS * sizeof(CellDataSnapshot)); 546 | for (int i = 0; i < MAX_SNAPSHOTS; i++) 547 | { 548 | cell_data_snapshots[i].cell_data = (unsigned char*)malloc(cell_data_length * sizeof(unsigned char)); 549 | cell_data_snapshots[i].output = (char*)malloc(MAX_OUTPUT_SIZE * sizeof(char)); 550 | cell_data_snapshots[i].instruction_idx = 0; 551 | cell_data_snapshots[i].fake_cycles = 0; 552 | } 553 | instructions = (Instruction*)malloc(MAX_INSTRUCTIONS * sizeof(Instruction)); 554 | for (int i = 0; i < MAX_OUTPUT_SIZE; i++) 555 | { 556 | my_output[i] = 0; 557 | } 558 | 559 | const int REG_A = cell_count + 0; 560 | const int REG_B = cell_count + 1; 561 | const int REG_C = cell_count + 2; 562 | const int REG_D = cell_count + 3; 563 | const int all_registers[4] = {REG_A, REG_B, REG_C, REG_D}; 564 | const char all_register_chars[4] = {'A', 'B', 'C', 'D'}; 565 | cell_data[REG_A] = 1; 566 | 567 | const char* code_text = LoadFileText("code.txt"); 568 | #include "code.txt" 569 | 570 | update_accessed_cells(); 571 | 572 | while(!WindowShouldClose()) 573 | { 574 | if (IsKeyPressed(KEY_SPACE)) 575 | { 576 | if (cell_data_type == CELL_DATA_NUMBER) 577 | cell_data_type = CELL_DATA_CHARACTER; 578 | else 579 | cell_data_type = CELL_DATA_NUMBER; 580 | } 581 | 582 | if ((IsKeyPressed(KEY_RIGHT) || IsKeyDown(KEY_DOWN)) && instruction_idx < instruction_count && !is_halted) 583 | { 584 | for (int i = 0; i < MAX_LAST_ACCESSED_CELLS; i++) 585 | last_accessed_cells[i] = -1; 586 | 587 | memcpy(cell_data_snapshots[snapshot_idx].cell_data, cell_data, cell_data_length); 588 | memcpy(cell_data_snapshots[snapshot_idx].output, my_output, MAX_OUTPUT_SIZE); 589 | cell_data_snapshots[snapshot_idx].instruction_idx = instruction_idx; 590 | cell_data_snapshots[snapshot_idx].fake_cycles = fake_cycles; 591 | snapshot_idx++; 592 | 593 | execute_instruction(instructions[instruction_idx], cell_count); 594 | instruction_idx++; 595 | 596 | update_accessed_cells(); 597 | PlaySound(click01_sound); 598 | } 599 | if ((IsKeyPressed(KEY_LEFT) || IsKeyDown(KEY_UP)) && instruction_idx > 0) 600 | { 601 | for (int i = 0; i < MAX_LAST_ACCESSED_CELLS; i++) 602 | last_accessed_cells[i] = -1; 603 | 604 | snapshot_idx--; 605 | is_halted = false; 606 | memcpy(cell_data, cell_data_snapshots[snapshot_idx].cell_data, cell_data_length); 607 | memcpy(my_output, cell_data_snapshots[snapshot_idx].output, MAX_OUTPUT_SIZE); 608 | instruction_idx = cell_data_snapshots[snapshot_idx].instruction_idx; 609 | fake_cycles = cell_data_snapshots[snapshot_idx].fake_cycles; 610 | update_accessed_cells(); 611 | 612 | PlaySound(click02_sound); 613 | } 614 | 615 | BeginDrawing(); 616 | ClearBackground(BLACK); 617 | 618 | DrawText(FormatText("CLOCK: %08d", snapshot_idx + (fake_cycles*99)), 50, 50, 20, BLUE); 619 | 620 | const int cell_width = 70; 621 | const int cell_height = 90; 622 | const int all_cells_x = 500; 623 | const int all_cells_y = 100; 624 | const int cell_line_width = 1; 625 | const int cell_address_line_local_y = 20; 626 | const int cell_address_font_size = 10; 627 | const Color cell_color = RAYWHITE; 628 | const int cell_data_font_size = 30; 629 | const int all_cells_end_x = all_cells_x + ((cell_width-cell_line_width) * cells_per_row); 630 | const int all_cells_end_y = all_cells_y + ((cell_height-cell_line_width) * cell_rows); 631 | 632 | const int pixel_width = 6; 633 | const int pixel_height = 6; 634 | const int pixels_x = all_cells_end_x - (pixel_width*cells_per_row); 635 | const int pixels_y = 50; 636 | DrawRectangleLines(pixels_x-1, pixels_y-1, (cells_per_row*pixel_width)+2, (cell_rows*pixel_height)+2, BLUE); 637 | for (int i = 0; i < cell_count; i++) 638 | { 639 | const int x = i % cells_per_row; 640 | const int y = i / cells_per_row; 641 | const Color col = { 642 | .r = cell_data[i], 643 | .g = cell_data[i], 644 | .b = cell_data[i], 645 | .a = 255 646 | }; 647 | DrawRectangle( 648 | pixels_x + (x * pixel_width), 649 | pixels_y + (y * pixel_height), 650 | pixel_width, 651 | pixel_height, 652 | col 653 | ); 654 | } 655 | 656 | const char* output_text = FormatText("OUTPUT:\n%s", my_output); 657 | Rectangle output_text_rec = { 658 | .x = all_cells_x, 659 | .y = all_cells_end_y + 10, 660 | .width = 800, 661 | .height = 400 662 | }; 663 | DrawTextRec(GetFontDefault(), output_text, output_text_rec, 10, 2, true, BLUE); 664 | 665 | const int code_x = 50; 666 | const int code_y = 100; 667 | const int code_font_size = CODE_FONT_SIZE; 668 | const int code_line_height = code_font_size/2; 669 | Rectangle code_line_rect = { 670 | .x = code_x, 671 | .y = code_y + (instruction_idx * (code_font_size+code_line_height)), 672 | .width = 360, 673 | .height = code_font_size 674 | }; 675 | DrawRectangleRec(code_line_rect, RED); 676 | DrawText(code_text, code_x, code_y, code_font_size, RAYWHITE); 677 | 678 | const int register_x_start = 500; 679 | const int register_x_spacing = 150; 680 | const int register_y_start = 50; 681 | const int register_font_size = 40; 682 | const Color register_font_color = RAYWHITE; 683 | const int register_text_width = MeasureText("A: 255", register_font_size); 684 | const int register_highlight_padding = 5; 685 | Rectangle register_highlight_rec = { 686 | .x = register_x_start + register_highlight_padding, 687 | .y = register_y_start + register_highlight_padding, 688 | .width = register_text_width - (register_highlight_padding*2), 689 | .height = register_font_size - (register_highlight_padding*2) 690 | }; 691 | for (int r = 0; r < 4; r++) 692 | { 693 | for (int k = 0; k < MAX_LAST_ACCESSED_CELLS; k++) 694 | { 695 | if (last_accessed_cells[k] == all_registers[r]) 696 | { 697 | Vector2 origin = {.x = -register_x_spacing * r, .y = 0}; 698 | DrawRectanglePro(register_highlight_rec, origin, 0, (k == 2) ? GREEN : RED); 699 | } 700 | } 701 | DrawText(FormatText("%c: %03d", all_register_chars[r], cell_data[all_registers[r]]), 702 | register_x_start + (register_x_spacing*r), 703 | register_y_start, 704 | register_font_size, 705 | register_font_color); 706 | } 707 | 708 | // Draw Cells. 709 | for (int i = 0; i < cell_count; i++) 710 | { 711 | Rectangle box_rect = { 712 | .x = all_cells_x + ((i % cells_per_row) * (cell_width-cell_line_width)), 713 | .y = all_cells_y + ((i / cells_per_row) * (cell_height-cell_line_width)), 714 | .width = cell_width, 715 | .height = cell_height}; 716 | const int half_width = box_rect.width/2; 717 | const int half_height = box_rect.height/2; 718 | DrawRectangleLinesEx(box_rect, cell_line_width, cell_color); 719 | 720 | const int fill_padding = 10; 721 | Rectangle fill_box_rec = { 722 | .x = box_rect.x + fill_padding, 723 | .y = box_rect.y + cell_address_line_local_y + fill_padding, 724 | .width = box_rect.width - fill_padding*2, 725 | .height = box_rect.height - cell_address_line_local_y - fill_padding*2 726 | }; 727 | 728 | for (int k = 0; k < MAX_LAST_ACCESSED_CELLS; k++) 729 | { 730 | if (i == last_accessed_cells[k] && i != 0) 731 | { 732 | DrawRectangleRec(fill_box_rec, (k == 2) ? GREEN : RED); 733 | } 734 | 735 | if (instruction_idx >= instruction_count) continue; 736 | 737 | const InstructionType itype = instructions[instruction_idx].type; 738 | const bool is_idx0_indirect = (itype == INS_COPY_INDIRECT_CELL || itype == INS_COPY_INDIRECT_INDIRECT); 739 | const bool is_idx1_indirect = (itype == INS_COPY_CELL_INDIRECT || itype == INS_COPY_INDIRECT_INDIRECT); 740 | const int idx0_ref = instructions[instruction_idx].idx0; 741 | const bool is_idx0_ref_this_cell = (i == cell_data[idx0_ref]); 742 | const bool is_idx0_a_register = (idx0_ref >= cell_count); 743 | const int idx1_ref = instructions[instruction_idx].idx1; 744 | const bool is_idx1_ref_this_cell = (i == cell_data[idx1_ref]); 745 | const bool is_idx1_a_register = (idx1_ref >= cell_count); 746 | if ( (is_idx0_indirect && is_idx0_ref_this_cell && is_idx0_a_register) 747 | || (is_idx1_indirect && is_idx1_ref_this_cell && is_idx1_a_register) 748 | ) 749 | { 750 | const int register_idx = (is_idx0_ref_this_cell) ? (idx0_ref - cell_count) : (idx1_ref - cell_count); 751 | DrawRectangleRec(fill_box_rec, BLUE); 752 | Vector2 register_origin = {.x = register_x_spacing * register_idx, .y = register_highlight_rec.height }; 753 | DrawLine( 754 | register_highlight_rec.x + register_origin.x, 755 | register_highlight_rec.y + register_origin.y, 756 | fill_box_rec.x, fill_box_rec.y, BLUE); 757 | } 758 | else if ( (is_idx0_indirect && is_idx0_ref_this_cell) 759 | ||(is_idx1_indirect && is_idx1_ref_this_cell) 760 | ) 761 | { 762 | const int ref_idx = (is_idx0_ref_this_cell) ? idx0_ref : idx1_ref; 763 | const int x = all_cells_x + ((ref_idx % cells_per_row) * (cell_width-cell_line_width)); 764 | const int y = all_cells_y + ((ref_idx / cells_per_row) * (cell_height-cell_line_width)); 765 | DrawRectangleRec(fill_box_rec, BLUE); 766 | DrawLine(x + (cell_width/2), y + (cell_height/2), fill_box_rec.x, fill_box_rec.y, BLUE); 767 | } 768 | } 769 | 770 | Vector2 line_vec_left = { 771 | .x = box_rect.x, 772 | .y = box_rect.y + cell_address_line_local_y 773 | }; 774 | Vector2 line_vec_right = { 775 | .x = box_rect.x + box_rect.width, 776 | .y = box_rect.y + cell_address_line_local_y 777 | }; 778 | DrawLineEx(line_vec_left, line_vec_right, 1, cell_color); 779 | const char* address_text = TextFormat("%02d", i); 780 | const int address_text_width = MeasureText(address_text, cell_address_font_size); 781 | DrawText(address_text, 782 | box_rect.x + half_width - (address_text_width/2), 783 | box_rect.y + (cell_address_line_local_y/2) - (cell_address_font_size/2), 784 | cell_address_font_size, 785 | cell_color 786 | ); 787 | 788 | const int data_x = box_rect.x + half_width; 789 | const int data_y = box_rect.y + cell_address_line_local_y + ((box_rect.height-cell_address_line_local_y)/2); 790 | if (i == 0) 791 | { 792 | DrawText("!", data_x, data_y-15, 30, RED); 793 | continue; 794 | } 795 | switch(cell_data_type) { 796 | case CELL_DATA_NUMBER: { 797 | const char* data_text = TextFormat("%d", cell_data[i]); 798 | int data_text_width = MeasureText(data_text, cell_data_font_size); 799 | DrawText(data_text, 800 | data_x - (data_text_width/2), 801 | data_y - (cell_data_font_size/2), 802 | cell_data_font_size, 803 | cell_color); 804 | break; 805 | } 806 | case CELL_DATA_CHARACTER: { 807 | const char* data_text = TextFormat("%c", cell_data[i]); 808 | int data_text_width = MeasureText(data_text, cell_data_font_size); 809 | DrawText(data_text, 810 | data_x - (data_text_width/2), 811 | data_y - (cell_data_font_size/2), 812 | cell_data_font_size, 813 | cell_color); 814 | break; 815 | } 816 | } 817 | } 818 | 819 | // const float total_frame_duration = GetFrameTime(); 820 | // DrawText( 821 | // FormatText("Frame time: %.03f%%", 100.0f * (1.0f / (total_frame_duration * 30.f))), 822 | // 10, 10, 823 | // 20, 824 | // RED); 825 | 826 | EndDrawing(); 827 | } 828 | 829 | CloseAudioDevice(); 830 | CloseWindow(); 831 | } -------------------------------------------------------------------------------- /programming_memory_tutorial/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/main.exe -------------------------------------------------------------------------------- /programming_memory_tutorial/raylib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/programming_memory_tutorial/raylib.dll -------------------------------------------------------------------------------- /programming_memory_tutorial/raylib/raylib_helpers.odin: -------------------------------------------------------------------------------- 1 | package raylib 2 | import "core:strings" 3 | import _c "core:c" 4 | 5 | DrawStringRec :: proc( 6 | font : Font, 7 | text : string, 8 | rec : Rectangle, 9 | fontSize : _c.float, 10 | spacing : _c.float, 11 | wordWrap : bool, 12 | color : Color) 13 | { 14 | ctext : cstring = strings.clone_to_cstring(text); 15 | DrawTextRec(font, ctext, rec, fontSize, spacing, wordWrap, color); 16 | } 17 | 18 | DrawString :: proc( 19 | text : string, 20 | posX : _c.int, 21 | posY : _c.int, 22 | fontSize : _c.int, 23 | color : Color 24 | ) 25 | { 26 | ctext : cstring = strings.clone_to_cstring(text); 27 | DrawText(ctext, posX, posY, fontSize, color); 28 | } 29 | 30 | MeasureString :: proc(text : string, fontSize : _c.int) -> i32 31 | { 32 | ctext : cstring = strings.clone_to_cstring(text); 33 | return MeasureText(ctext, fontSize); 34 | } -------------------------------------------------------------------------------- /programming_memory_tutorial/strcmp.txt: -------------------------------------------------------------------------------- 1 | clear(0,71); 2 | load("strcmp_data.txt"); 3 | write(44, REG_D); 4 | write(1, REG_B); 5 | checkpoint(FIND_COMMA); 6 | copy_indirect_to_cell(REG_B, 50); 7 | add(REG_A, REG_B, REG_B); 8 | is_equal(50, REG_D, 52); 9 | jump_if_zero(FIND_COMMA, 52); 10 | copy_cell_to_cell(REG_B, REG_C); 11 | subtract(REG_B, REG_A, REG_B); 12 | copy_cell_to_cell(REG_B, 49); 13 | write(1, REG_B); 14 | checkpoint(COMPARE_CHAR); 15 | copy_indirect_to_cell(REG_B, 50); 16 | copy_indirect_to_cell(REG_C, 51); 17 | is_equal(REG_B, 49, 52); // reached end of string 0 18 | jump_if_above_zero(STRINGS_ARE_SAME, 52); 19 | add(REG_A, REG_B, REG_B); 20 | add(REG_A, REG_C, REG_C); 21 | is_equal(50, 51, 52); 22 | jump_if_above_zero(COMPARE_CHAR, 52); 23 | write('N', 50); 24 | print_characters(50,50); 25 | halt(); 26 | checkpoint(STRINGS_ARE_SAME); 27 | write('Y', 50); 28 | print_characters(50,50); 29 | halt(); -------------------------------------------------------------------------------- /programming_memory_tutorial/strcmp_data.txt: -------------------------------------------------------------------------------- 1 | something,somethings -------------------------------------------------------------------------------- /synth/LICENSE.txt: -------------------------------------------------------------------------------- 1 | End User License Agreement (EULA) 2 | 3 | The Software ("RemedyBG", "remedybg.exe") is Copyright 2019 by George Menhorn, 4 | ("Licensor"), all rights are reserved. Anyone who has purchased a copy of 5 | the Software, ("Licensee"), is granted a personal, non-assignable, 6 | non-transferable, license to use the Software for personal or commercial 7 | uses. 8 | 9 | By installing, copying, or otherwise using the Software, Licensee agrees to be 10 | bound by the terms and conditions set forth in this EULA. If Licensee does not 11 | agree to the terms and conditions set forth in this EULA, then Licensee may not 12 | use the Software. 13 | 14 | The User may not redistribute, sub-license, or resell the Software. The User is 15 | permitted to make an unlimited number of copies of the Software which are 16 | subject to the aforementioned restrictions. 17 | 18 | Warranty Disclaimer. Licensor hereby expressly disclaim any warranty for the 19 | Software. The Software is provided "as is" without warranty of any kind, either 20 | express or implied, including: without limitation, the implied warranties of 21 | merchantability, fitness for a particular purpose, or non-infringement. Licensee 22 | accepts any and all risk arising out of use or performance of the Software. 23 | 24 | Limitation of Liability. Licensor shall not be liable to Licensee, or any other 25 | person or entity claiming through Licensee any loss of profits, income, savings, 26 | or any other consequential, incidental, special, punitive, direct or 27 | indirect damage, whether arising in contract, tort, warranty, or 28 | otherwise. These limitations shall apply regardless of the essential 29 | purpose of any limited remedy. Under no circumstances shall Licensor's 30 | aggregate liability to Licensee, or any other person or entity claiming 31 | through Licensee, exceed the financial amount actually paid by Licensee 32 | to Licensor for the Software. 33 | -------------------------------------------------------------------------------- /synth/about.txt: -------------------------------------------------------------------------------- 1 | ############################### 2 | ### MAKE A SYNTHESIZER IN C ### 3 | ### EPISODE 9 ### 4 | ############################### 5 | 6 | 7 | === TODO === 8 | == fix bugs with UI and modulation seems inconsistent? 9 | == better UI for setting up modulators. 10 | == Amplitude modulation. 11 | == Pulse Width modulation. 12 | 13 | 14 | === TOOLS === 15 | == 4coder (with customizations). 16 | == Raylib [https://www.raylib.com/]. 17 | == Visual Studio 2019 compiler. 18 | == Windows 10. 19 | 20 | 21 | Find me on twitter: @locogameluke -------------------------------------------------------------------------------- /synth/build_midi.bat: -------------------------------------------------------------------------------- 1 | tcc -o midi.exe midi.c -Iinclude -lmsvcrt -lgdi32 -lkernel32 -lshell32 -luser32 -lwinmm -Wl -std=c99 -g -------------------------------------------------------------------------------- /synth/build_then_run.bat: -------------------------------------------------------------------------------- 1 | tcc -o synth.exe synth.c -Iinclude -lraylib -lmsvcrt -lopengl32 -lgdi32 -lkernel32 -lshell32 -luser32 -lwinmm -Wl,-subsystem=gui -std=c99 -run -------------------------------------------------------------------------------- /synth/build_vs.bat: -------------------------------------------------------------------------------- 1 | SET VS=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools 2 | CALL "%VS%\VsDevCmd.bat" -arch=x64 3 | 4 | SET CommonFlags=-nologo -Od -Oi /I"include" /Zi /Gm- /Gd /TC 5 | SET CommonLinkerFlags=raylib.lib -opt:ref kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib 6 | cl.exe %CommonFlags% synth.c /link /OUT:"synth.exe" /LIBPATH:"lib/vs2019" %CommonLinkerFlags% -------------------------------------------------------------------------------- /synth/include/minimal_windows.h: -------------------------------------------------------------------------------- 1 | /* date = March 24th 2021 5:46 pm */ 2 | 3 | #ifndef MINIMAL_WINDOWS_H 4 | #define MINIMAL_WINDOWS_H 5 | 6 | /* 7 | @raysan5: To avoid conflicting windows.h symbols with raylib, some flags are defined 8 | WARNING: Those flags avoid inclusion of some Win32 headers that could be required 9 | by user at some point and won't be included... 10 | */ 11 | 12 | /* If defined, the following flags inhibit definition of the indicated items.*/ 13 | #define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ 14 | #define NOVIRTUALKEYCODES // VK_* 15 | #define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* 16 | #define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* 17 | #define NOSYSMETRICS // SM_* 18 | #define NOMENUS // MF_* 19 | #define NOICONS // IDI_* 20 | #define NOKEYSTATES // MK_* 21 | #define NOSYSCOMMANDS // SC_* 22 | #define NORASTEROPS // Binary and Tertiary raster ops 23 | #define NOSHOWWINDOW // SW_* 24 | #define OEMRESOURCE // OEM Resource values 25 | #define NOATOM // Atom Manager routines 26 | #define NOCLIPBOARD // Clipboard routines 27 | #define NOCOLOR // Screen colors 28 | #define NOCTLMGR // Control and Dialog routines 29 | #define NODRAWTEXT // DrawText() and DT_* 30 | #define NOGDI // All GDI defines and routines 31 | #define NOKERNEL // All KERNEL defines and routines 32 | #define NOUSER // All USER defines and routines 33 | /*#define NONLS // All NLS defines and routines*/ 34 | #define NOMB // MB_* and MessageBox() 35 | #define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines 36 | #define NOMETAFILE // typedef METAFILEPICT 37 | #define NOMINMAX // Macros min(a,b) and max(a,b) 38 | #define NOMSG // typedef MSG and associated routines 39 | #define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* 40 | #define NOSCROLL // SB_* and scrolling routines 41 | 42 | #ifndef NOSERVICE 43 | #define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. 44 | #endif 45 | 46 | #define NOSOUND // Sound driver routines 47 | #define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines 48 | #define NOWH // SetWindowsHook and WH_* 49 | #define NOWINOFFSETS // GWL_*, GCL_*, associated routines 50 | #define NOCOMM // COMM driver routines 51 | #define NOKANJI // Kanji support stuff. 52 | #define NOHELP // Help engine interface. 53 | #define NOPROFILER // Profiler interface. 54 | #define NODEFERWINDOWPOS // DeferWindowPos routines 55 | 56 | #ifndef NOMCX 57 | #define NOMCX // Modem Configuration Extensions 58 | #endif 59 | 60 | /* Type required before windows.h inclusion */ 61 | typedef struct tagMSG *LPMSG; 62 | 63 | #include 64 | 65 | /* Type required by some unused function... */ 66 | typedef struct tagBITMAPINFOHEADER { 67 | DWORD biSize; 68 | LONG biWidth; 69 | LONG biHeight; 70 | WORD biPlanes; 71 | WORD biBitCount; 72 | DWORD biCompression; 73 | DWORD biSizeImage; 74 | LONG biXPelsPerMeter; 75 | LONG biYPelsPerMeter; 76 | DWORD biClrUsed; 77 | DWORD biClrImportant; 78 | } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 79 | 80 | #include 81 | #include 82 | #include 83 | 84 | /* @raysan5: Some required types defined for MSVC/TinyC compiler */ 85 | #if defined(_MSC_VER) || defined(__TINYC__) 86 | #include "propidl.h" 87 | #endif 88 | 89 | 90 | #endif //MINIMAL_WINDOWS_H 91 | -------------------------------------------------------------------------------- /synth/include/ricons.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * rIcons - Icons pack intended for tools development with raygui 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2019-2020 Ramon Santamaria (@raysan5) 8 | * 9 | **********************************************************************************************/ 10 | 11 | #ifndef RICONS_H 12 | #define RICONS_H 13 | 14 | //---------------------------------------------------------------------------------- 15 | // Defines and Macros 16 | //---------------------------------------------------------------------------------- 17 | #define RICON_MAX_ICONS 256 // Maximum number of icons 18 | #define RICON_SIZE 16 // Size of icons (squared) 19 | 20 | #define RICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id 21 | 22 | // Icons data is defined by bit array (every bit represents one pixel) 23 | // Those arrays are stored as unsigned int data arrays, so every array 24 | // element defines 32 pixels (bits) of information 25 | // Number of elemens depend on RICON_SIZE (by default 16x16 pixels) 26 | #define RICON_DATA_ELEMENTS (RICON_SIZE*RICON_SIZE/32) 27 | 28 | //---------------------------------------------------------------------------------- 29 | // Icons enumeration 30 | //---------------------------------------------------------------------------------- 31 | typedef enum { 32 | RICON_NONE = 0, 33 | RICON_FOLDER_FILE_OPEN = 1, 34 | RICON_FILE_SAVE_CLASSIC = 2, 35 | RICON_FOLDER_OPEN = 3, 36 | RICON_FOLDER_SAVE = 4, 37 | RICON_FILE_OPEN = 5, 38 | RICON_FILE_SAVE = 6, 39 | RICON_FILE_EXPORT = 7, 40 | RICON_FILE_NEW = 8, 41 | RICON_FILE_DELETE = 9, 42 | RICON_FILETYPE_TEXT = 10, 43 | RICON_FILETYPE_AUDIO = 11, 44 | RICON_FILETYPE_IMAGE = 12, 45 | RICON_FILETYPE_PLAY = 13, 46 | RICON_FILETYPE_VIDEO = 14, 47 | RICON_FILETYPE_INFO = 15, 48 | RICON_FILE_COPY = 16, 49 | RICON_FILE_CUT = 17, 50 | RICON_FILE_PASTE = 18, 51 | RICON_CURSOR_HAND = 19, 52 | RICON_CURSOR_POINTER = 20, 53 | RICON_CURSOR_CLASSIC = 21, 54 | RICON_PENCIL = 22, 55 | RICON_PENCIL_BIG = 23, 56 | RICON_BRUSH_CLASSIC = 24, 57 | RICON_BRUSH_PAINTER = 25, 58 | RICON_WATER_DROP = 26, 59 | RICON_COLOR_PICKER = 27, 60 | RICON_RUBBER = 28, 61 | RICON_COLOR_BUCKET = 29, 62 | RICON_TEXT_T = 30, 63 | RICON_TEXT_A = 31, 64 | RICON_SCALE = 32, 65 | RICON_RESIZE = 33, 66 | RICON_FILTER_POINT = 34, 67 | RICON_FILTER_BILINEAR = 35, 68 | RICON_CROP = 36, 69 | RICON_CROP_ALPHA = 37, 70 | RICON_SQUARE_TOGGLE = 38, 71 | RICON_SYMMETRY = 39, 72 | RICON_SYMMETRY_HORIZONTAL = 40, 73 | RICON_SYMMETRY_VERTICAL = 41, 74 | RICON_LENS = 42, 75 | RICON_LENS_BIG = 43, 76 | RICON_EYE_ON = 44, 77 | RICON_EYE_OFF = 45, 78 | RICON_FILTER_TOP = 46, 79 | RICON_FILTER = 47, 80 | RICON_TARGET_POINT = 48, 81 | RICON_TARGET_SMALL = 49, 82 | RICON_TARGET_BIG = 50, 83 | RICON_TARGET_MOVE = 51, 84 | RICON_CURSOR_MOVE = 52, 85 | RICON_CURSOR_SCALE = 53, 86 | RICON_CURSOR_SCALE_RIGHT = 54, 87 | RICON_CURSOR_SCALE_LEFT = 55, 88 | RICON_UNDO = 56, 89 | RICON_REDO = 57, 90 | RICON_REREDO = 58, 91 | RICON_MUTATE = 59, 92 | RICON_ROTATE = 60, 93 | RICON_REPEAT = 61, 94 | RICON_SHUFFLE = 62, 95 | RICON_EMPTYBOX = 63, 96 | RICON_TARGET = 64, 97 | RICON_TARGET_SMALL_FILL = 65, 98 | RICON_TARGET_BIG_FILL = 66, 99 | RICON_TARGET_MOVE_FILL = 67, 100 | RICON_CURSOR_MOVE_FILL = 68, 101 | RICON_CURSOR_SCALE_FILL = 69, 102 | RICON_CURSOR_SCALE_RIGHT_FILL = 70, 103 | RICON_CURSOR_SCALE_LEFT_FILL = 71, 104 | RICON_UNDO_FILL = 72, 105 | RICON_REDO_FILL = 73, 106 | RICON_REREDO_FILL = 74, 107 | RICON_MUTATE_FILL = 75, 108 | RICON_ROTATE_FILL = 76, 109 | RICON_REPEAT_FILL = 77, 110 | RICON_SHUFFLE_FILL = 78, 111 | RICON_EMPTYBOX_SMALL = 79, 112 | RICON_BOX = 80, 113 | RICON_BOX_TOP = 81, 114 | RICON_BOX_TOP_RIGHT = 82, 115 | RICON_BOX_RIGHT = 83, 116 | RICON_BOX_BOTTOM_RIGHT = 84, 117 | RICON_BOX_BOTTOM = 85, 118 | RICON_BOX_BOTTOM_LEFT = 86, 119 | RICON_BOX_LEFT = 87, 120 | RICON_BOX_TOP_LEFT = 88, 121 | RICON_BOX_CENTER = 89, 122 | RICON_BOX_CIRCLE_MASK = 90, 123 | RICON_POT = 91, 124 | RICON_ALPHA_MULTIPLY = 92, 125 | RICON_ALPHA_CLEAR = 93, 126 | RICON_DITHERING = 94, 127 | RICON_MIPMAPS = 95, 128 | RICON_BOX_GRID = 96, 129 | RICON_GRID = 97, 130 | RICON_BOX_CORNERS_SMALL = 98, 131 | RICON_BOX_CORNERS_BIG = 99, 132 | RICON_FOUR_BOXES = 100, 133 | RICON_GRID_FILL = 101, 134 | RICON_BOX_MULTISIZE = 102, 135 | RICON_ZOOM_SMALL = 103, 136 | RICON_ZOOM_MEDIUM = 104, 137 | RICON_ZOOM_BIG = 105, 138 | RICON_ZOOM_ALL = 106, 139 | RICON_ZOOM_CENTER = 107, 140 | RICON_BOX_DOTS_SMALL = 108, 141 | RICON_BOX_DOTS_BIG = 109, 142 | RICON_BOX_CONCENTRIC = 110, 143 | RICON_BOX_GRID_BIG = 111, 144 | RICON_OK_TICK = 112, 145 | RICON_CROSS = 113, 146 | RICON_ARROW_LEFT = 114, 147 | RICON_ARROW_RIGHT = 115, 148 | RICON_ARROW_BOTTOM = 116, 149 | RICON_ARROW_TOP = 117, 150 | RICON_ARROW_LEFT_FILL = 118, 151 | RICON_ARROW_RIGHT_FILL = 119, 152 | RICON_ARROW_BOTTOM_FILL = 120, 153 | RICON_ARROW_TOP_FILL = 121, 154 | RICON_AUDIO = 122, 155 | RICON_FX = 123, 156 | RICON_WAVE = 124, 157 | RICON_WAVE_SINUS = 125, 158 | RICON_WAVE_SQUARE = 126, 159 | RICON_WAVE_TRIANGULAR = 127, 160 | RICON_CROSS_SMALL = 128, 161 | RICON_PLAYER_PREVIOUS = 129, 162 | RICON_PLAYER_PLAY_BACK = 130, 163 | RICON_PLAYER_PLAY = 131, 164 | RICON_PLAYER_PAUSE = 132, 165 | RICON_PLAYER_STOP = 133, 166 | RICON_PLAYER_NEXT = 134, 167 | RICON_PLAYER_RECORD = 135, 168 | RICON_MAGNET = 136, 169 | RICON_LOCK_CLOSE = 137, 170 | RICON_LOCK_OPEN = 138, 171 | RICON_CLOCK = 139, 172 | RICON_TOOLS = 140, 173 | RICON_GEAR = 141, 174 | RICON_GEAR_BIG = 142, 175 | RICON_BIN = 143, 176 | RICON_HAND_POINTER = 144, 177 | RICON_LASER = 145, 178 | RICON_COIN = 146, 179 | RICON_EXPLOSION = 147, 180 | RICON_1UP = 148, 181 | RICON_PLAYER = 149, 182 | RICON_PLAYER_JUMP = 150, 183 | RICON_KEY = 151, 184 | RICON_DEMON = 152, 185 | RICON_TEXT_POPUP = 153, 186 | RICON_GEAR_EX = 154, 187 | RICON_CRACK = 155, 188 | RICON_CRACK_POINTS = 156, 189 | RICON_STAR = 157, 190 | RICON_DOOR = 158, 191 | RICON_EXIT = 159, 192 | RICON_MODE_2D = 160, 193 | RICON_MODE_3D = 161, 194 | RICON_CUBE = 162, 195 | RICON_CUBE_FACE_TOP = 163, 196 | RICON_CUBE_FACE_LEFT = 164, 197 | RICON_CUBE_FACE_FRONT = 165, 198 | RICON_CUBE_FACE_BOTTOM = 166, 199 | RICON_CUBE_FACE_RIGHT = 167, 200 | RICON_CUBE_FACE_BACK = 168, 201 | RICON_CAMERA = 169, 202 | RICON_SPECIAL = 170, 203 | RICON_LINK_NET = 171, 204 | RICON_LINK_BOXES = 172, 205 | RICON_LINK_MULTI = 173, 206 | RICON_LINK = 174, 207 | RICON_LINK_BROKE = 175, 208 | RICON_TEXT_NOTES = 176, 209 | RICON_NOTEBOOK = 177, 210 | RICON_SUITCASE = 178, 211 | RICON_SUITCASE_ZIP = 179, 212 | RICON_MAILBOX = 180, 213 | RICON_MONITOR = 181, 214 | RICON_PRINTER = 182, 215 | RICON_PHOTO_CAMERA = 183, 216 | RICON_PHOTO_CAMERA_FLASH = 184, 217 | RICON_HOUSE = 185, 218 | RICON_HEART = 186, 219 | RICON_CORNER = 187, 220 | RICON_VERTICAL_BARS = 188, 221 | RICON_VERTICAL_BARS_FILL = 189, 222 | RICON_LIFE_BARS = 190, 223 | RICON_INFO = 191, 224 | RICON_CROSSLINE = 192, 225 | RICON_HELP = 193, 226 | RICON_FILETYPE_ALPHA = 194, 227 | RICON_FILETYPE_HOME = 195, 228 | RICON_LAYERS_VISIBLE = 196, 229 | RICON_LAYERS = 197, 230 | RICON_WINDOW = 198, 231 | RICON_HIDPI = 199, 232 | RICON_200 = 200, 233 | RICON_201 = 201, 234 | RICON_202 = 202, 235 | RICON_203 = 203, 236 | RICON_204 = 204, 237 | RICON_205 = 205, 238 | RICON_206 = 206, 239 | RICON_207 = 207, 240 | RICON_208 = 208, 241 | RICON_209 = 209, 242 | RICON_210 = 210, 243 | RICON_211 = 211, 244 | RICON_212 = 212, 245 | RICON_213 = 213, 246 | RICON_214 = 214, 247 | RICON_215 = 215, 248 | RICON_216 = 216, 249 | RICON_217 = 217, 250 | RICON_218 = 218, 251 | RICON_219 = 219, 252 | RICON_220 = 220, 253 | RICON_221 = 221, 254 | RICON_222 = 222, 255 | RICON_223 = 223, 256 | RICON_224 = 224, 257 | RICON_225 = 225, 258 | RICON_226 = 226, 259 | RICON_227 = 227, 260 | RICON_228 = 228, 261 | RICON_229 = 229, 262 | RICON_230 = 230, 263 | RICON_231 = 231, 264 | RICON_232 = 232, 265 | RICON_233 = 233, 266 | RICON_234 = 234, 267 | RICON_235 = 235, 268 | RICON_236 = 236, 269 | RICON_237 = 237, 270 | RICON_238 = 238, 271 | RICON_239 = 239, 272 | RICON_240 = 240, 273 | RICON_241 = 241, 274 | RICON_242 = 242, 275 | RICON_243 = 243, 276 | RICON_244 = 244, 277 | RICON_245 = 245, 278 | RICON_246 = 246, 279 | RICON_247 = 247, 280 | RICON_248 = 248, 281 | RICON_249 = 249, 282 | RICON_250 = 250, 283 | RICON_251 = 251, 284 | RICON_252 = 252, 285 | RICON_253 = 253, 286 | RICON_254 = 254, 287 | RICON_255 = 255, 288 | } guiIconName; 289 | 290 | #endif // RICONS_H 291 | 292 | #if defined(RICONS_IMPLEMENTATION) 293 | //---------------------------------------------------------------------------------- 294 | // Icons data (allocated on memory data section by default) 295 | // NOTE: A new icon set could be loaded over this array using GuiLoadIcons(), 296 | // just note that loaded icons set must be same RICON_SIZE 297 | //---------------------------------------------------------------------------------- 298 | static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = { 299 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_NONE 300 | 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // RICON_FOLDER_FILE_OPEN 301 | 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // RICON_FILE_SAVE_CLASSIC 302 | 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // RICON_FOLDER_OPEN 303 | 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // RICON_FOLDER_SAVE 304 | 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // RICON_FILE_OPEN 305 | 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // RICON_FILE_SAVE 306 | 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // RICON_FILE_EXPORT 307 | 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // RICON_FILE_NEW 308 | 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // RICON_FILE_DELETE 309 | 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_FILETYPE_TEXT 310 | 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // RICON_FILETYPE_AUDIO 311 | 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // RICON_FILETYPE_IMAGE 312 | 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // RICON_FILETYPE_PLAY 313 | 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // RICON_FILETYPE_VIDEO 314 | 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // RICON_FILETYPE_INFO 315 | 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // RICON_FILE_COPY 316 | 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // RICON_FILE_CUT 317 | 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // RICON_FILE_PASTE 318 | 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_CURSOR_HAND 319 | 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // RICON_CURSOR_POINTER 320 | 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // RICON_CURSOR_CLASSIC 321 | 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // RICON_PENCIL 322 | 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // RICON_PENCIL_BIG 323 | 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // RICON_BRUSH_CLASSIC 324 | 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // RICON_BRUSH_PAINTER 325 | 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // RICON_WATER_DROP 326 | 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // RICON_COLOR_PICKER 327 | 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // RICON_RUBBER 328 | 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // RICON_COLOR_BUCKET 329 | 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // RICON_TEXT_T 330 | 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // RICON_TEXT_A 331 | 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // RICON_SCALE 332 | 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // RICON_RESIZE 333 | 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_POINT 334 | 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_BILINEAR 335 | 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // RICON_CROP 336 | 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // RICON_CROP_ALPHA 337 | 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // RICON_SQUARE_TOGGLE 338 | 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // RICON_SIMMETRY 339 | 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // RICON_SIMMETRY_HORIZONTAL 340 | 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // RICON_SIMMETRY_VERTICAL 341 | 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // RICON_LENS 342 | 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // RICON_LENS_BIG 343 | 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // RICON_EYE_ON 344 | 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // RICON_EYE_OFF 345 | 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // RICON_FILTER_TOP 346 | 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // RICON_FILTER 347 | 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_POINT 348 | 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL 349 | 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG 350 | 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // RICON_TARGET_MOVE 351 | 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // RICON_CURSOR_MOVE 352 | 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // RICON_CURSOR_SCALE 353 | 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // RICON_CURSOR_SCALE_RIGHT 354 | 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // RICON_CURSOR_SCALE_LEFT 355 | 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO 356 | 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO 357 | 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // RICON_REREDO 358 | 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // RICON_MUTATE 359 | 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // RICON_ROTATE 360 | 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // RICON_REPEAT 361 | 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // RICON_SHUFFLE 362 | 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // RICON_EMPTYBOX 363 | 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // RICON_TARGET 364 | 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL_FILL 365 | 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG_FILL 366 | 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // RICON_TARGET_MOVE_FILL 367 | 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // RICON_CURSOR_MOVE_FILL 368 | 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // RICON_CURSOR_SCALE_FILL 369 | 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // RICON_CURSOR_SCALE_RIGHT 370 | 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // RICON_CURSOR_SCALE_LEFT 371 | 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO_FILL 372 | 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO_FILL 373 | 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // RICON_REREDO_FILL 374 | 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // RICON_MUTATE_FILL 375 | 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // RICON_ROTATE_FILL 376 | 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // RICON_REPEAT_FILL 377 | 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // RICON_SHUFFLE_FILL 378 | 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // RICON_EMPTYBOX_SMALL 379 | 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX 380 | 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP 381 | 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_RIGHT 382 | 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_RIGHT 383 | 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // RICON_BOX_BOTTOM_RIGHT 384 | 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // RICON_BOX_BOTTOM 385 | 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // RICON_BOX_BOTTOM_LEFT 386 | 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_LEFT 387 | 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_LEFT 388 | 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_CIRCLE_MASK 389 | 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // RICON_BOX_CENTER 390 | 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // RICON_POT 391 | 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // RICON_ALPHA_MULTIPLY 392 | 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // RICON_ALPHA_CLEAR 393 | 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // RICON_DITHERING 394 | 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // RICON_MIPMAPS 395 | 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // RICON_BOX_GRID 396 | 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // RICON_GRID 397 | 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // RICON_BOX_CORNERS_SMALL 398 | 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // RICON_BOX_CORNERS_BIG 399 | 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // RICON_FOUR_BOXES 400 | 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // RICON_GRID_FILL 401 | 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // RICON_BOX_MULTISIZE 402 | 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_SMALL 403 | 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_MEDIUM 404 | 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // RICON_ZOOM_BIG 405 | 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // RICON_ZOOM_ALL 406 | 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // RICON_ZOOM_CENTER 407 | 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // RICON_BOX_DOTS_SMALL 408 | 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // RICON_BOX_DOTS_BIG 409 | 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // RICON_BOX_CONCENTRIC 410 | 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // RICON_BOX_GRID_BIG 411 | 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // RICON_OK_TICK 412 | 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // RICON_CROSS 413 | 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // RICON_ARROW_LEFT 414 | 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // RICON_ARROW_RIGHT 415 | 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // RICON_ARROW_BOTTOM 416 | 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_TOP 417 | 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // RICON_ARROW_LEFT_FILL 418 | 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // RICON_ARROW_RIGHT_FILL 419 | 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // RICON_ARROW_BOTTOM_FILL 420 | 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_TOP_FILL 421 | 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // RICON_AUDIO 422 | 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // RICON_FX 423 | 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // RICON_WAVE 424 | 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // RICON_WAVE_SINUS 425 | 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // RICON_WAVE_SQUARE 426 | 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // RICON_WAVE_TRIANGULAR 427 | 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // RICON_CROSS_SMALL 428 | 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // RICON_PLAYER_PREVIOUS 429 | 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // RICON_PLAYER_PLAY_BACK 430 | 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // RICON_PLAYER_PLAY 431 | 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // RICON_PLAYER_PAUSE 432 | 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // RICON_PLAYER_STOP 433 | 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // RICON_PLAYER_NEXT 434 | 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // RICON_PLAYER_RECORD 435 | 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // RICON_MAGNET 436 | 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_CLOSE 437 | 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_OPEN 438 | 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // RICON_CLOCK 439 | 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // RICON_TOOLS 440 | 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // RICON_GEAR 441 | 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // RICON_GEAR_BIG 442 | 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // RICON_BIN 443 | 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // RICON_HAND_POINTER 444 | 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // RICON_LASER 445 | 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // RICON_COIN 446 | 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // RICON_EXPLOSION 447 | 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // RICON_1UP 448 | 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // RICON_PLAYER 449 | 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // RICON_PLAYER_JUMP 450 | 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // RICON_KEY 451 | 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // RICON_DEMON 452 | 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // RICON_TEXT_POPUP 453 | 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // RICON_GEAR_EX 454 | 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK 455 | 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK_POINTS 456 | 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // RICON_STAR 457 | 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // RICON_DOOR 458 | 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // RICON_EXIT 459 | 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // RICON_MODE_2D 460 | 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // RICON_MODE_3D 461 | 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE 462 | 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_TOP 463 | 0x7fe00000, 0x50386030, 0x47fe483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // RICON_CUBE_FACE_LEFT 464 | 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // RICON_CUBE_FACE_FRONT 465 | 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3ff27fe2, 0x0ffe1ffa, 0x000007fe, // RICON_CUBE_FACE_BOTTOM 466 | 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // RICON_CUBE_FACE_RIGHT 467 | 0x7fe00000, 0x7fe87ff0, 0x7ffe7fe4, 0x7fe27fe2, 0x7fe27fe2, 0x24127fe2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_BACK 468 | 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // RICON_CAMERA 469 | 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // RICON_SPECIAL 470 | 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // RICON_LINK_NET 471 | 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // RICON_LINK_BOXES 472 | 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // RICON_LINK_MULTI 473 | 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // RICON_LINK 474 | 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // RICON_LINK_BROKE 475 | 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_TEXT_NOTES 476 | 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // RICON_NOTEBOOK 477 | 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // RICON_SUITCASE 478 | 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // RICON_SUITCASE_ZIP 479 | 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // RICON_MAILBOX 480 | 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // RICON_MONITOR 481 | 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // RICON_PRINTER 482 | 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA 483 | 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA_FLASH 484 | 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // RICON_HOUSE 485 | 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // RICON_HEART 486 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // RICON_CORNER 487 | 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // RICON_VERTICAL_BARS 488 | 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // RICON_VERTICAL_BARS_FILL 489 | 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // RICON_LIFE_BARS 490 | 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // RICON_INFO 491 | 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // RICON_CROSSLINE 492 | 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // RICON_HELP 493 | 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // RICON_FILETYPE_ALPHA 494 | 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // RICON_FILETYPE_HOME 495 | 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS_VISIBLE 496 | 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS 497 | 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // RICON_WINDOW 498 | 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // RICON_HIDPI 499 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_200 500 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_201 501 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_202 502 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_203 503 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_204 504 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_205 505 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_206 506 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_207 507 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_208 508 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_209 509 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_210 510 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_211 511 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_212 512 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_213 513 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_214 514 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_215 515 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_216 516 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_217 517 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_218 518 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_219 519 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_220 520 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_221 521 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_222 522 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_223 523 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_224 524 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_225 525 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_226 526 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_227 527 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_228 528 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_229 529 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_230 530 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_231 531 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_232 532 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_233 533 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_234 534 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_235 535 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_236 536 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_237 537 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_238 538 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_239 539 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_240 540 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_241 541 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_242 542 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_243 543 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_244 544 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_245 545 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_246 546 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_247 547 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_248 548 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_249 549 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_250 550 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_251 551 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_252 552 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_253 553 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_254 554 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_255 555 | }; 556 | #endif // RICONS_IMPLEMENTATION -------------------------------------------------------------------------------- /synth/include/synth_platform.h: -------------------------------------------------------------------------------- 1 | /* date = March 25th 2021 0:38 pm */ 2 | 3 | #ifndef SYNTH_PLATFORM_H 4 | #define SYNTH_PLATFORM_H 5 | 6 | #include 7 | typedef int8_t i8; 8 | typedef int16_t i16; 9 | typedef int32_t i32; 10 | typedef int64_t i64; 11 | typedef uint8_t u8; 12 | typedef uint16_t u16; 13 | typedef uint32_t u32; 14 | typedef uint64_t u64; 15 | typedef size_t usize; 16 | typedef float f32; 17 | typedef double f64; 18 | 19 | #include 20 | #define F32_MAX FLT_MAX 21 | #include 22 | #define U16_MAX USHRT_MAX; 23 | #define U32_MAX UINT_MAX; 24 | #define U64_MAX ULONG_MAX; 25 | #define I16_MAX SHRT_MAX; 26 | #define I32_MAX INT_MAX; 27 | #define I64_MAX LONG_MAX; 28 | 29 | #define global static 30 | #define local_static static 31 | #define internal static 32 | #define ArrayCount(arr) (sizeof((arr)) / (sizeof((arr)[0]))) 33 | #define Kilobytes(number) ((number)*1024ull) 34 | #define Megabytes(number) (Kilobytes(number) * 1024ull) 35 | #define Gigabytes(number) (Megabytes(number) * 1024ull) 36 | #define Terabytes(number) (Gigabytes(number) * 1024ull) 37 | 38 | #define not ! 39 | #define InsideOpen(v, a, b) ((v > a) && (v < b)) 40 | #define InsideClosed(v, a, b) ((v >= a) && (v <= b)) 41 | #define InsideClosedOpen(v, a, b) ((v >= a) && (v < b)) 42 | #define InsideOpenClosed(v, a, b) ((v > a) && (v <= b)) 43 | #define InsideUpto InsideClosedOpen 44 | #define InsideDownto InsideOpenClosed 45 | #define InsideExclusive InsideOpen 46 | #define InsideInclusive InsideClosed 47 | #define OutsideExlusive !InsideInclusive 48 | #define OutsideInclusive !InsideExclusive 49 | 50 | #ifdef SYNTH_SLOW 51 | #define Assert(expression) \ 52 | if(!(expression)) { \ 53 | *(int *)0 = 0; \ 54 | } 55 | #else 56 | #define Assert(expression) 57 | #endif 58 | 59 | #define Unreachable Assert(!"Unreachable code") 60 | 61 | inline f32 62 | Log2f(f32 n) 63 | { 64 | return logf( n ) / logf( 2 ); 65 | } 66 | 67 | inline u32 68 | RandomU32(u32 seed) 69 | { 70 | local_static u32 z = 362436069; 71 | local_static u32 w = 521288629; 72 | local_static u32 jcong = 380116160; 73 | local_static u32 jsr = 123456789; 74 | u32 z_new = 36969 * ((z+seed) & 65535) + ((z+seed) >> 16); 75 | u32 w_new = 18000 * (w & 65535) + (w >> 16); 76 | u32 mwc = (z_new << 16) + w_new; 77 | u32 jcong_new = 69069 * jcong + 1234567; 78 | u32 jsr_new = jsr ^ (jsr << 17); 79 | jsr_new ^= (jsr >> 13); 80 | jsr_new ^= (jsr << 5); 81 | u32 result = (mwc ^ jcong_new) + jsr_new; 82 | z = z_new; 83 | w = w_new; 84 | jcong = jcong_new; 85 | jsr = jsr_new; 86 | return result; 87 | } 88 | 89 | inline f32 90 | RandomF32(u32 seed) 91 | { 92 | u32 val = RandomU32(seed); 93 | return (f32)val / (f32)U32_MAX; 94 | } 95 | 96 | #endif //SYNTH_PLATFORM_H 97 | -------------------------------------------------------------------------------- /synth/lib/tcc/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/lib/tcc/raylib.lib -------------------------------------------------------------------------------- /synth/lib/vs2019/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/lib/vs2019/raylib.lib -------------------------------------------------------------------------------- /synth/midi.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/midi.exe -------------------------------------------------------------------------------- /synth/midi.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "minimal_windows.h" 3 | #include "synth_platform.h" 4 | 5 | typedef MIDIINCAPS MidiDeviceInfo; 6 | typedef HMIDIIN MidiHandle; 7 | 8 | #define KEY_ON 144 9 | #define KEY_OFF 128 10 | #define BASE_MIDI_NOTE 69 // A4 11 | #define MAX_MIDI_VELOCITY 127.f 12 | #define POLYPHONIC_COUNT 16 13 | 14 | // @midi 15 | typedef union MidiMessage 16 | { 17 | u32 message; 18 | u8 data[4]; 19 | } MidiMessage; 20 | 21 | // @midi 22 | typedef struct MidiKey 23 | { 24 | u8 is_on; 25 | u8 note; 26 | f64 velocity_ratio; 27 | } MidiKey; 28 | 29 | // @midi 30 | typedef struct MidiKeyArray 31 | { 32 | MidiKey data[POLYPHONIC_COUNT]; 33 | u32 count; 34 | } MidiKeyArray; 35 | 36 | // @midi 37 | internal void CALLBACK 38 | SynthMidiHandler(MidiHandle midi, u32 msg_type, u32 *user_data, u32 param1, u32 param2) 39 | { 40 | switch(msg_type) 41 | { 42 | case MIM_DATA: { 43 | MidiKeyArray *keys = (MidiKeyArray*)user_data; 44 | MidiMessage msg = {param1}; 45 | u8 midi_event = msg.data[0]; 46 | u8 midi_note = msg.data[1]; 47 | u8 midi_velocity = msg.data[2]; 48 | u32 midi_timestamp = param2; 49 | 50 | if (midi_event == KEY_ON) 51 | { 52 | MidiKey *key = 0; 53 | for (u32 i = 0; i < keys->count; i++) 54 | { 55 | if (keys->data[i].is_on == 0) 56 | { 57 | key = keys->data + i; 58 | break; 59 | } 60 | } 61 | if (key) 62 | { 63 | key->is_on = 1; 64 | key->note = midi_note; 65 | key->velocity_ratio = (f32)midi_velocity / MAX_MIDI_VELOCITY; 66 | } 67 | } 68 | else if (midi_event == KEY_OFF) 69 | { 70 | MidiKey *key = 0; 71 | for (u32 i = 0; i < keys->count; i++) 72 | { 73 | if (keys->data[i].is_on && keys->data[i].note == midi_note) 74 | { 75 | keys->data[i].is_on = false; 76 | break; 77 | } 78 | } 79 | } 80 | break; 81 | } 82 | } 83 | } 84 | 85 | MidiHandle 86 | SynthMidiInit(u32 selected_device_id, MidiKeyArray *keys) 87 | { 88 | u32 num_midi_devices = midiInGetNumDevs(); 89 | for(u32 device_id = 0; device_id < num_midi_devices; device_id++) 90 | { 91 | MidiDeviceInfo device_info; 92 | u32 result = midiInGetDevCaps(device_id, 93 | &device_info, 94 | sizeof(MidiDeviceInfo)); 95 | if (result != MMSYSERR_NOERROR) 96 | { 97 | printf("Could not get MIDI device info\n"); 98 | return 0; 99 | } 100 | printf("MIDI device: %s\n", device_info.szPname); 101 | } 102 | 103 | MidiHandle midi; 104 | u32 result = midiInOpen(&midi, 105 | selected_device_id, 106 | (DWORD_PTR)SynthMidiHandler, 107 | (DWORD_PTR)keys, 108 | CALLBACK_FUNCTION); 109 | if (result != MMSYSERR_NOERROR) 110 | { 111 | printf("Could not open MIDI device %d.\n", selected_device_id); 112 | return 0; 113 | } 114 | 115 | result = midiInStart(midi); 116 | if (result != MMSYSERR_NOERROR) 117 | { 118 | printf("Could not start MIDI device %d.\n", selected_device_id); 119 | return 0; 120 | } 121 | 122 | return midi; 123 | } 124 | 125 | void 126 | SynthMidiStop(MidiHandle midi) 127 | { 128 | u32 result = midiInStop(midi); 129 | if (result != MMSYSERR_NOERROR) 130 | { 131 | printf("Could not stop MIDI device.\n"); 132 | return; 133 | } 134 | 135 | result = midiInClose(midi); 136 | if (result != MMSYSERR_NOERROR) 137 | { 138 | printf("Could not close MIDI device.\n"); 139 | return; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /synth/project.4coder: -------------------------------------------------------------------------------- 1 | version(1); 2 | 3 | project_name = "perkin_synth"; 4 | 5 | patterns = 6 | { 7 | "*.c", 8 | "*.cpp", 9 | "*.jai", 10 | "*.odin", 11 | "*.zig", 12 | "*.h", 13 | "*.inc", 14 | "*.bat", 15 | "*.sh", 16 | "*.4coder", 17 | "*.txt", 18 | }; 19 | 20 | blacklist_patterns = 21 | { 22 | ".*", 23 | }; 24 | 25 | load_paths = 26 | { 27 | { 28 | { {"."}, .recursive = true, .relative = true }, .os = "win" 29 | }, 30 | }; 31 | 32 | command_list = 33 | { 34 | { 35 | .name = "build", 36 | .out = "*compilation*", 37 | .footer_panel = true, 38 | .save_dirty_files = true, 39 | .cursor_at_end = false, 40 | .cmd = 41 | { 42 | { "build_vs.bat", .os = "win" }, 43 | { "echo Linux build command not implemented for 4coder project.", .os = "linux" }, 44 | }, 45 | }, 46 | 47 | { 48 | .name = "run", 49 | .out = "*compilation*", 50 | .footer_panel = true, 51 | .save_dirty_files = true, 52 | .cursor_at_end = false, 53 | .cmd = 54 | { 55 | { "synth.exe", .os = "win" }, 56 | { "echo Linux run command not implemented for 4coder project.", .os = "linux" }, 57 | }, 58 | }, 59 | { 60 | .name = "run_live_code", 61 | .out = "*compilation*", 62 | .footer_panel = true, 63 | .save_dirty_files = true, 64 | .cursor_at_end = false, 65 | .cmd = 66 | { 67 | {"blink.exe synth.exe", .os = "win"} 68 | } 69 | } 70 | }; 71 | 72 | fkey_command[1] = "build"; 73 | fkey_command[2] = "run"; 74 | fkey_command[3] = "run_live_code"; 75 | -------------------------------------------------------------------------------- /synth/recordings/sawtooth_and_fastsine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/recordings/sawtooth_and_fastsine.mp3 -------------------------------------------------------------------------------- /synth/resources.txt: -------------------------------------------------------------------------------- 1 | === RESOURCES === 2 | == Raygui 3 | = https://github.com/raysan5/raygui 4 | 5 | == MIDI input (windows) 6 | = https://docs.microsoft.com/en-us/windows/win32/multimedia/midi-reference 7 | 8 | == MIDI input example (windows 9 | = https://gist.github.com/yoggy/1485181 10 | 11 | == Building a Numerically Controlled Oscillator 12 | = https://zipcpu.com/dsp/2017/12/09/nco.html 13 | 14 | == http://www.slack.net/~ant/bl-synth/ (Offline, use wayback machine) 15 | 16 | == Generating PolyBLEP Waveforms 17 | = http://www.martin-finke.de/blog/articles/audio-plugins-018-polyblep-oscillator/ 18 | 19 | == Creating Threads 20 | = https://docs.microsoft.com/en-us/windows/win32/procthread/creating-threads 21 | 22 | == STB (useful collection of things) 23 | = https://github.com/nothings/stb/blob/master/stb.h 24 | 25 | == Cross-platform thread header. 26 | = https://github.com/mattiasgustavsson/newpixie/blob/main/source/pixie/thread.h 27 | 28 | == PADsynth 29 | = https://zynaddsubfx.sourceforge.io/doc/PADsynth/PADsynth.htm 30 | 31 | 32 | 33 | == Categories for Fourier Transform: 34 | = Complex numbers. 35 | = Euler formula/Eulers identity. 36 | = Roots of unity. 37 | = Signal processing. 38 | = https://ccrma.stanford.edu/~jos/log/Mathematics_DFT.html -------------------------------------------------------------------------------- /synth/styles/README.md: -------------------------------------------------------------------------------- 1 | ## raygui styles 2 | 3 | `raygui` comes with **8 custom styles** carefully designed for the best visual experience. Those styles have been created using [rGuiStyler](https://raylibtech.itch.io/rguistyler) tool and they complement internal [default style](default), always available by `raygui`. 4 | 5 | To use those styles with your `raygui` development, just need to call `GuiLoadStyle()` function at initialization, passing the `.rgs` file to load. Note that most of those styles depend on custom fonts that must be available together with the `.rgs` file. 6 | 7 | Here it is a quick overview of those styles, you can navigate to each directory for additional information. 8 | 9 | #### style: [default](default) 10 | ![default style](default/style_table.png) 11 | 12 | #### style: [ashes](ashes) 13 | ![ashes style](ashes/style_table.png) 14 | 15 | #### style: [bluish](bluish) 16 | ![bluish style](bluish/style_table.png) 17 | 18 | #### style: [candy](candy) 19 | ![candy style](candy/style_table.png) 20 | 21 | #### style: [cherry](cherry) 22 | ![cherry style](cherry/style_table.png) 23 | 24 | #### style: [cyber](cyber) 25 | ![cyber style](cyber/style_table.png) 26 | 27 | #### style: [jungle](jungle) 28 | ![jungle style](jungle/style_table.png) 29 | 30 | #### style: [lavanda](lavanda) 31 | ![lavanda style](lavanda/style_table.png) 32 | 33 | #### style: [terminal](terminal) 34 | ![terminal style](terminal/style_table.png) 35 | 36 | *NOTE: Those styles require latest raylib 2.6-dev and latest raygui 2.6-dev.* 37 | -------------------------------------------------------------------------------- /synth/styles/ashes/README.md: -------------------------------------------------------------------------------- 1 | style: ashes 2 | ------------- 3 | What once was life now is ashes, just as slight reminiscense covers the ground, a gray sequence of tones that reminds to a distant past. 4 | 5 | ![ashes style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![ashes style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "V5 Loxica Lixera" font by vFive Digital (Roberto Christen). 15 | 16 | 100% free font, downloaded from dafont.com: [v5loxica-lixera](https://www.dafont.com/v5loxica-lixera.font) 17 | -------------------------------------------------------------------------------- /synth/styles/ashes/ashes.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 16 0 v5loxical.ttf 9 | p 00 00 0xf0f0f0ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x868686ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0xe6e6e6ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0x929999ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0xeaeaeaff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0x98a1a8ff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0x3f3f3fff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0xf6f6f6ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0x414141ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x8b8b8bff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x777777ff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x959595ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x00000010 TEXT_SIZE 22 | p 00 17 0x00000001 TEXT_SPACING 23 | p 00 18 0x9dadb1ff DEFAULT_LINE_COLOR 24 | p 00 19 0x6b6b6bff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/ashes/font_readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/ashes/font_readme.txt -------------------------------------------------------------------------------- /synth/styles/ashes/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/ashes/screenshot.png -------------------------------------------------------------------------------- /synth/styles/ashes/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/ashes/style_table.png -------------------------------------------------------------------------------- /synth/styles/ashes/v5loxical.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/ashes/v5loxical.ttf -------------------------------------------------------------------------------- /synth/styles/bluish/README.md: -------------------------------------------------------------------------------- 1 | style: bluish 2 | -------------- 3 | Like a breeze, a slight touch of color cover the clear sky, a spacious and relaxing feeling. 4 | 5 | ![bluish style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![bluish style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Homespun BRK" font by AEnigma (Brian Kent). 15 | 16 | 100% free font, downloaded from dafont.com: [homespun-brk](https://www.dafont.com/homespun-brk.font) 17 | -------------------------------------------------------------------------------- /synth/styles/bluish/bluish.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 10 0 homespun.ttf 9 | p 00 00 0x5ca6a6ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0xb4e8f3ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0x447e77ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0x5f8792ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0xcdeff7ff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0x4c6c74ff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0x3b5b5fff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0xeaffffff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0x275057ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x96aaacff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0xc8d7d9ff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x8c9c9eff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x0000000a TEXT_SIZE 22 | p 00 17 0x00000001 TEXT_SPACING 23 | p 00 18 0x84adb7ff DEFAULT_LINE_COLOR 24 | p 00 19 0xe8eef1ff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/bluish/font_readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/bluish/font_readme.txt -------------------------------------------------------------------------------- /synth/styles/bluish/homespun.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/bluish/homespun.ttf -------------------------------------------------------------------------------- /synth/styles/bluish/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/bluish/screenshot.png -------------------------------------------------------------------------------- /synth/styles/bluish/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/bluish/style_table.png -------------------------------------------------------------------------------- /synth/styles/candy/README.md: -------------------------------------------------------------------------------- 1 | style: candy 2 | ------------- 3 | Sweet, colorful, tasty! Enjoy this funfair ride and be careful with the witch of the candy house! 4 | 5 | ![candy style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![candy style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "V5 Eastergothic" font by vFive Digital (Roberto Christen). 15 | 16 | 100% free font, downloaded from dafont.com: [v5eastergothic](https://www.dafont.com/v5eastergothic.font) 17 | -------------------------------------------------------------------------------- /synth/styles/candy/candy.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 15 0 v5easter.ttf 9 | p 00 00 0xe58b68ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0xfeda96ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0xe59b5fff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0xee813fff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0xfcd85bff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0xfc6955ff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0xb34848ff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0xeb7272ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0xbd4a4aff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x94795dff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0xc2a37aff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x9c8369ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x0000000f TEXT_SIZE 22 | p 00 17 0x00000001 TEXT_SPACING 23 | p 00 18 0xd77575ff DEFAULT_LINE_COLOR 24 | p 00 19 0xfff5e1ff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/candy/font_readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/candy/font_readme.txt -------------------------------------------------------------------------------- /synth/styles/candy/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/candy/screenshot.png -------------------------------------------------------------------------------- /synth/styles/candy/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/candy/style_table.png -------------------------------------------------------------------------------- /synth/styles/candy/v5easter.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/candy/v5easter.ttf -------------------------------------------------------------------------------- /synth/styles/cherry/README.md: -------------------------------------------------------------------------------- 1 | style: cherry 2 | -------------- 3 | Sweet with a touch of liquour, covered in chocolate, just give it a try! Not suitable for every palate, only the most demanding. 4 | 5 | ![cherry style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![cherry style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Westington" font by Hazel Abbiati. 15 | 16 | 100% free font, downloaded from dafont.com: [westington](https://www.dafont.com/westington.font) 17 | -------------------------------------------------------------------------------- /synth/styles/cherry/Westington.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cherry/Westington.ttf -------------------------------------------------------------------------------- /synth/styles/cherry/cherry.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 15 0 Westington.ttf 9 | p 00 00 0xda5757ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x753233ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0xe17373ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0xfaaa97ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0xe06262ff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0xfdb4aaff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0xe03c46ff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0x5b1e20ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0xc2474fff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0xa19292ff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x706060ff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x9e8585ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x0000000f TEXT_SIZE 22 | p 00 17 0x00000000 TEXT_SPACING 23 | p 00 18 0xfb8170ff DEFAULT_LINE_COLOR 24 | p 00 19 0x3a1720ff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/cherry/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cherry/screenshot.png -------------------------------------------------------------------------------- /synth/styles/cherry/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cherry/style_table.png -------------------------------------------------------------------------------- /synth/styles/cyber/Kyrou 7 Wide.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cyber/Kyrou 7 Wide.ttf -------------------------------------------------------------------------------- /synth/styles/cyber/README.md: -------------------------------------------------------------------------------- 1 | style: cyber 2 | ------------- 3 | Future is now! Neons and shadows, city never sleeps! Robots waiting in the corners and expensive vending machines! You got the style! 4 | 5 | ![cyber style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![cyber style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Grixel Kyrou 7 Wide" font by [Nikos Giannakopoulos](http://www.grixel.gr/). 15 | 16 | 100% free font, downloaded from dafont.com: [grixel-kyrou-7-wide](https://www.dafont.com/grixel-kyrou-7-wide.font) 17 | -------------------------------------------------------------------------------- /synth/styles/cyber/cyber.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 14 0 Kyrou 7 Wide.ttf 9 | p 00 00 0x2f7486ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x024658ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0x51bfd3ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0x82cde0ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0x3299b4ff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0xb6e1eaff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0xeb7630ff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0xffbc51ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0xd86f36ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x134b5aff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x02313dff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x17505fff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x0000000e DEFAULT_TEXT_SIZE 22 | p 00 17 0x00000000 DEFAULT_TEXT_SPACING 23 | p 00 18 0x81c0d0ff DEFAULT_LINE_COLOR 24 | p 00 19 0x00222bff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/cyber/font_readme.txt: -------------------------------------------------------------------------------- 1 | Thank you for downloading the free Grixel fonts. You can use them in your personal and commercial projects too. They include Western European, Central European, Turkish and Greek characters. They are Unicode TrueType fonts and are optimized to work in both Windows XP and Mac OS X platforms using Adobe Photoshop CS2 and Macromedia Flash 8. 2 | 3 | 4 | Grixel fonts are under Creative Commons Attribution-NoDerivs 2.5 License which can be found here: 5 | 6 | http://creativecommons.org/licenses/by-nd/2.5/ 7 | 8 | =============================================================== 9 | Attribution-NoDerivs 2.5 10 | 11 | You are free: 12 | 13 | * to copy, distribute, display, and perform the work 14 | * to make commercial use of the work 15 | 16 | Under the following conditions: 17 | 18 | by 19 | Attribution. You must attribute the work in the manner specified by the author or licensor. 20 | 21 | nd 22 | No Derivative Works. You may not alter, transform, or build upon this work. 23 | 24 | * For any reuse or distribution, you must make clear to others the license terms of this work. 25 | * Any of these conditions can be waived if you get permission from the copyright holder. 26 | 27 | Your fair use and other rights are in no way affected by the above. 28 | =============================================================== 29 | 30 | 31 | In no event shall Nikos Giannakopoulos be held liable to you for any consequential or incidental damages, including any lost revenue, profits, goodwill or savings, or for any claim by any third party caused by using these fonts. 32 | 33 | Please read the UsageGuides.pdf before you use them. 34 | 35 | 36 | Grixel - Greek pixel fonts | Nikos Giannakopoulos | www.grixel.gr -------------------------------------------------------------------------------- /synth/styles/cyber/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cyber/screenshot.png -------------------------------------------------------------------------------- /synth/styles/cyber/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/cyber/style_table.png -------------------------------------------------------------------------------- /synth/styles/default/README.md: -------------------------------------------------------------------------------- 1 | style: default 2 | --------------- 3 | raylib style, simple and easy-to-use. Light colors, wide borders, a sophisticated touch. 4 | 5 | ![default style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![default style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | raylib font by Ramon Santamaria ([@raysan5](https://twitter.com/raysan5)). 15 | -------------------------------------------------------------------------------- /synth/styles/default/default.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | p 00 00 0x838383ff DEFAULT_BORDER_COLOR_NORMAL 9 | p 00 01 0xc9c9c9ff DEFAULT_BASE_COLOR_NORMAL 10 | p 00 02 0x686868ff DEFAULT_TEXT_COLOR_NORMAL 11 | p 00 03 0x5bb2d9ff DEFAULT_BORDER_COLOR_FOCUSED 12 | p 00 04 0xc9effeff DEFAULT_BASE_COLOR_FOCUSED 13 | p 00 05 0x6c9bbcff DEFAULT_TEXT_COLOR_FOCUSED 14 | p 00 06 0x0492c7ff DEFAULT_BORDER_COLOR_PRESSED 15 | p 00 07 0x97e8ffff DEFAULT_BASE_COLOR_PRESSED 16 | p 00 08 0x368bafff DEFAULT_TEXT_COLOR_PRESSED 17 | p 00 09 0xb5c1c2ff DEFAULT_BORDER_COLOR_DISABLED 18 | p 00 10 0xe6e9e9ff DEFAULT_BASE_COLOR_DISABLED 19 | p 00 11 0xaeb7b8ff DEFAULT_TEXT_COLOR_DISABLED 20 | p 00 12 0x1 DEFAULT_BORDER_WIDTH 21 | p 00 13 0x0 DEFAULT_TEXT_PADDING 22 | p 00 14 0x1 DEFAULT_TEXT_ALIGNMENT 23 | p 00 15 0x0 DEFAULT_RESERVED 24 | p 00 16 0xa DEFAULT_TEXT_SIZE 25 | p 00 17 0x1 DEFAULT_TEXT_SPACING 26 | p 00 18 0x90abb5ff DEFAULT_LINE_COLOR 27 | p 00 19 0xf5f5f5ff DEFAULT_BACKGROUND_COLOR 28 | p 01 14 0x0 LABEL_TEXT_ALIGNMENT 29 | p 02 12 0x2 BUTTON_BORDER_WIDTH 30 | p 03 16 0x2 TOGGLE_GROUP_PADDING 31 | p 04 16 0xf SLIDER_SLIDER_WIDTH 32 | p 04 13 0x5 SLIDER_TEXT_PADDING 33 | p 05 16 0x1 PROGRESSBAR_PROGRESS_PADDING 34 | p 06 13 0x5 CHECKBOX_TEXT_PADDING 35 | p 06 14 0x2 CHECKBOX_TEXT_ALIGNMENT 36 | p 06 16 0x1 CHECKBOX_CHECK_PADDING 37 | p 07 16 0x1e COMBOBOX_COMBO_BUTTON_WIDTH 38 | p 07 17 0x2 COMBOBOX_COMBO_BUTTON_PADDING 39 | p 08 16 0x10 DROPDOWNBOX_ARROW_PADDING 40 | p 08 17 0x2 DROPDOWNBOX_DROPDOWN_ITEMS_PADDING 41 | p 09 13 0x5 TEXTBOX_TEXT_PADDING 42 | p 09 14 0x0 TEXTBOX_TEXT_ALIGNMENT 43 | p 09 16 0x5 TEXTBOX_TEXT_LINES_PADDING 44 | p 09 17 0xf0fffeff TEXTBOX_COLOR_SELECTED_FG 45 | p 09 18 0x839affe0 TEXTBOX_COLOR_SELECTED_BG 46 | p 10 13 0x4 VALUEBOX_TEXT_PADDING 47 | p 10 14 0x0 VALUEBOX_TEXT_ALIGNMENT 48 | p 11 13 0x4 SPINNER_TEXT_PADDING 49 | p 11 14 0x0 SPINNER_TEXT_ALIGNMENT 50 | p 11 16 0x14 SPINNER_SPIN_BUTTON_WIDTH 51 | p 11 17 0x2 SPINNER_SPIN_BUTTON_PADDING 52 | p 12 16 0x1e LISTVIEW_LIST_ITEMS_HEIGHT 53 | p 12 17 0x2 LISTVIEW_LIST_ITEMS_PADDING 54 | p 12 18 0xa LISTVIEW_SCROLLBAR_WIDTH 55 | p 12 19 0x2 LISTVIEW_SCROLLBAR_SIDE 56 | p 13 16 0x6 COLORPICKER_COLOR_SELECTOR_SIZE 57 | p 13 17 0x14 COLORPICKER_HUEBAR_WIDTH 58 | p 13 18 0xa COLORPICKER_HUEBAR_PADDING 59 | p 13 19 0x6 COLORPICKER_HUEBAR_SELECTOR_HEIGHT 60 | p 13 20 0x2 COLORPICKER_HUEBAR_SELECTOR_OVERFLOW 61 | p 14 12 0x0 SCROLLBAR_BORDER_WIDTH 62 | p 14 16 0x6 SCROLLBAR_ARROWS_SIZE 63 | p 14 17 0x0 SCROLLBAR_ARROWS_VISIBLE 64 | p 14 18 0x0 SCROLLBAR_SCROLL_SLIDER_PADDING 65 | p 14 19 0x10 SCROLLBAR_SCROLL_SLIDER_SIZE 66 | p 14 20 0x0 SCROLLBAR_SCROLL_PADDING 67 | p 14 21 0xa SCROLLBAR_SCROLL_SPEED 68 | p 15 13 0xa STATUSBAR_TEXT_PADDING 69 | p 15 14 0x0 STATUSBAR_TEXT_ALIGNMENT 70 | -------------------------------------------------------------------------------- /synth/styles/default/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/default/screenshot.png -------------------------------------------------------------------------------- /synth/styles/default/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/default/style_table.png -------------------------------------------------------------------------------- /synth/styles/jungle/Pixel Intv.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/jungle/Pixel Intv.otf -------------------------------------------------------------------------------- /synth/styles/jungle/README.md: -------------------------------------------------------------------------------- 1 | style: jungle 2 | -------------- 3 | Sunset in the jungle, trees do not let to see the last rays of sun on the horizon, small creek in the path, mug on the shoes, a touch of danger and the adventure feeling, get into your jeep and drive with this style. 4 | 5 | ![jungle style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![jungle style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Pixel Intv" font by [Pixel Sagas](http://www.pixelsagas.com) (Neale and Shayna Davidson). 15 | 16 | 100% free font, downloaded from dafont.com: [pixel-intv](https://www.dafont.com/pixel-intv.font) 17 | -------------------------------------------------------------------------------- /synth/styles/jungle/font_readme.txt: -------------------------------------------------------------------------------- 1 | Shareware/ Font License 2 | 3 | Pixel Sagas Freeware Fonts EULA (End User License Agreement) and Software Inclusion Agreement 4 | 5 | "Purchaser" and "User" may be used interchangeably in this agreement. 6 | 7 | "Pixel Sagas" and "Neale Davidson" may be used interchangeably in this agreement. These all refer to the intellectual and legal property of Neale Davidson. 8 | 9 | Usage 10 | 11 | Pixel Saga's Shareware Fonts are free to use for personal, non-commercial purposes. No payment is necessary to use Pixel Saga's Freeware Fonts for personal use, and there is no limit to the amount of prints, pages, or other medium to be produced using them. However, you cannot offer the font for commercial sale, or offer for direct download. The inclusion othe font name and/or site URL in the credits or documentation when it is used is appreciated, but this is not mandatory. 12 | 13 | Payment 14 | 15 | Payment is not required for the use of Pixel Saga's Shareware Fonts. Commercial use requires a modest fee which can be paid through the pixelsagas.com web site through Paypal.com's services. The transaction receipt for any shareware "commercial license" purchase will suffice as proof of license. 16 | 17 | Support 18 | 19 | Font installation help is available at http://www.pixelsagas.com. If you experience problems with any Pixel Saga's Freeware font (such as spacing issues or missing characters), please verify that you have the correct and current version of the fonts. In the case of Freeware fonts, downloading the font directly from the Pixel Sagas site will ensure that the font files have not been altered. 20 | 21 | Software Inclusion Agreement 22 | 23 | Pixel Saga's software products are protected by copyright laws and International copyright treaties, as well as other intellectual property laws and treaties. All Pixel Saga's software products are licensed, not sold. 24 | 25 | 1) GRANT OF LICENSE 26 | 27 | This document grants the user the following rights: 28 | 29 | Installation and Use. The user may install and use an unlimited number of copies of the software product. The user may not offer Pixel Sagas freeware fonts for direct download unless the user has received explicit, written permission from Neale Davidson. Otherwise please direct users to the http://www.pixelsagas.com website. Pixel Sagas freeware fonts may, however, be embedded for web, publication, or general software use. 30 | 31 | 2) WARRANTIES 32 | 33 | None 34 | 35 | Pixel Sagas expressly disclaims any warranty for the software product. The software product and any related documentation is provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or non-infringement. The entire risk arising out of use or performance of the software product remains with the user. 36 | 37 | No Liability For Consequential Damages. 38 | 39 | In no event shall Neale Davidson or Pixel Sagas be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this product, even if Pixel Sagas has been advised of the possibility of such damages. 40 | 41 | 3) MISCELLANEOUS 42 | 43 | Should the user have any questions concerning this document or you desire to contact Neale Davidson for any reason, please email jaynz@pixelsagas.com . 44 | 45 | Governing Law 46 | 47 | This agreement is governed by and subject to the laws of the United States of America. 48 | -------------------------------------------------------------------------------- /synth/styles/jungle/jungle.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 12 0 Pixel Intv.otf 9 | p 00 00 0x60827dff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x2c3334ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0x82a29fff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0x5f9aa8ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0x334e57ff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0x6aa9b8ff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0xa9cb8dff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0x3b6357ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0x97af81ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x5b6462ff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x2c3334ff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x666b69ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x0000000c TEXT_SIZE 22 | p 00 17 0x00000000 TEXT_SPACING 23 | p 00 18 0x638465ff DEFAULT_LINE_COLOR 24 | p 00 19 0x2b3a3aff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/jungle/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/jungle/screenshot.png -------------------------------------------------------------------------------- /synth/styles/jungle/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/jungle/style_table.png -------------------------------------------------------------------------------- /synth/styles/lavanda/Cartridge.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/lavanda/Cartridge.ttf -------------------------------------------------------------------------------- /synth/styles/lavanda/README.md: -------------------------------------------------------------------------------- 1 | style: lavanda 2 | --------------- 3 | Walk thought the fields full of lavanda, feels like a dream, a touch of fantasy, just relax and close your eyes, could you feel it? 4 | 5 | ![lavanda style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![lavanda style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Cartridge" font by [jeti](https://fontenddev.com/) 15 | 16 | Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), downloaded from dafont.com: [cartridge](https://www.dafont.com/cartridge.font) 17 | -------------------------------------------------------------------------------- /synth/styles/lavanda/font_readme.txt: -------------------------------------------------------------------------------- 1 | Cartridge by jeti: A decorative, Art Nouveau-inspired font with a dainty, fantastical hand-lettered feel. 2 | 3 | You are free to use this font for personal or commercial projects, all I ask is that you include credit. 4 | 5 | Licensed under CC BY 4.0: https://creativecommons.org/licenses/by/4.0/ 6 | More info: https://fontenddev.com/fonts/cartridge/ 7 | -------------------------------------------------------------------------------- /synth/styles/lavanda/lavanda.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 16 0 Cartridge.ttf 9 | p 00 00 0xab9bd3ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x3e4350ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0xdadaf4ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0xee84a0ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0xf4b7c7ff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0xb7657bff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0xd5c8dbff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0x966ec0ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0xd7ccf7ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x8fa2bdff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x6b798dff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x8292a9ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x00000010 TEXT_SIZE 22 | p 00 17 0x00000001 TEXT_SPACING 23 | p 00 18 0x84adb7ff DEFAULT_LINE_COLOR 24 | p 00 19 0x5b5b81ff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/styles/lavanda/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/lavanda/screenshot.png -------------------------------------------------------------------------------- /synth/styles/lavanda/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/lavanda/style_table.png -------------------------------------------------------------------------------- /synth/styles/terminal/Mecha.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/terminal/Mecha.ttf -------------------------------------------------------------------------------- /synth/styles/terminal/README.md: -------------------------------------------------------------------------------- 1 | style: terminal 2 | ---------------- 3 | Start your terminal and type your commands! Feel the connection the data flow, that's your style! 4 | 5 | ![terminal style table](style_table.png) 6 | 7 | screenshot 8 | ----------- 9 | 10 | ![terminal style screen](screenshot.png) 11 | 12 | about font 13 | ----------- 14 | "Mecha" font by Captain Falcon. 15 | 16 | 100% free font, downloaded from dafont.com: [mecha-cf](https://www.dafont.com/mecha-cf.font) 17 | -------------------------------------------------------------------------------- /synth/styles/terminal/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/terminal/screenshot.png -------------------------------------------------------------------------------- /synth/styles/terminal/style_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/styles/terminal/style_table.png -------------------------------------------------------------------------------- /synth/styles/terminal/terminal.rgs: -------------------------------------------------------------------------------- 1 | # 2 | # rgs style text file (v3.1) - raygui style file generated using rGuiStyler 3 | # 4 | # Style properties: 5 | # f 6 | # p 7 | # 8 | f 16 0 Mecha.ttf 9 | p 00 00 0x1c8d00ff DEFAULT_BORDER_COLOR_NORMAL 10 | p 00 01 0x161313ff DEFAULT_BASE_COLOR_NORMAL 11 | p 00 02 0x38f620ff DEFAULT_TEXT_COLOR_NORMAL 12 | p 00 03 0xc3fbc6ff DEFAULT_BORDER_COLOR_FOCUSED 13 | p 00 04 0x43bf2eff DEFAULT_BASE_COLOR_FOCUSED 14 | p 00 05 0xdcfadcff DEFAULT_TEXT_COLOR_FOCUSED 15 | p 00 06 0x1f5b19ff DEFAULT_BORDER_COLOR_PRESSED 16 | p 00 07 0x43ff28ff DEFAULT_BASE_COLOR_PRESSED 17 | p 00 08 0x1e6f15ff DEFAULT_TEXT_COLOR_PRESSED 18 | p 00 09 0x223b22ff DEFAULT_BORDER_COLOR_DISABLED 19 | p 00 10 0x182c18ff DEFAULT_BASE_COLOR_DISABLED 20 | p 00 11 0x244125ff DEFAULT_TEXT_COLOR_DISABLED 21 | p 00 16 0x00000010 TEXT_SIZE 22 | p 00 17 0x00000000 TEXT_SPACING 23 | p 00 18 0xe6fce3ff DEFAULT_LINE_COLOR 24 | p 00 19 0x0c1505ff DEFAULT_BACKGROUND_COLOR 25 | -------------------------------------------------------------------------------- /synth/synth.c: -------------------------------------------------------------------------------- 1 | #include // standard input and ouput. 2 | #include 3 | #include 4 | #include "raylib.h" 5 | #define RAYGUI_SUPPORT_ICONS 6 | #define RAYGUI_IMPLEMENTATION 7 | #include "raygui.h" 8 | #include "midi.h" 9 | 10 | #define SYNTH_SLOW 1 // run assertions. 11 | #define SCREEN_WIDTH 1024 12 | #define SCREEN_HEIGHT 768 13 | #define TARGET_FPS 60 14 | #define SAMPLE_RATE 44100 15 | #define SAMPLE_DURATION (1.0f / SAMPLE_RATE) 16 | #define STREAM_BUFFER_SIZE 1024 17 | #define MAX_OSCILLATORS 32 18 | #define MAX_UI_OSCILLATORS 32 19 | #define UI_PANEL_WIDTH 350 20 | #define BASE_NOTE_FREQ 440 21 | 22 | global MidiKeyArray midi_keys = {0}; 23 | global MidiHandle midi_input_handle = 0; 24 | 25 | typedef f32 (*WaveShapeFn)(const f32 phase_ratio, 26 | const f32 phase_dt, 27 | const f32 shape_param); 28 | 29 | #define WAVE_SHAPE_OPTIONS "None;Sine;Sawtooth;Square;Triangle;Rounded Square" 30 | typedef enum WaveShape { 31 | WaveShape_NONE = 0, 32 | WaveShape_SINE = 1, 33 | WaveShape_SAWTOOTH = 2, 34 | WaveShape_SQUARE = 3, 35 | WaveShape_TRIANGLE = 4, 36 | WaveShape_ROUNDEDSQUARE = 5, 37 | WaveShape_COUNT 38 | } WaveShape; 39 | 40 | typedef struct UiOscillator { 41 | f32 freq; 42 | f32 amplitude_ratio; 43 | f32 shape_parameter_0; 44 | WaveShape shape; 45 | bool is_dropdown_open; 46 | Rectangle shape_dropdown_rect; 47 | u8 modulation_state; // 0 = no modulation. 48 | } UiOscillator; 49 | 50 | typedef struct Oscillator { 51 | f32 phase_ratio; 52 | f32 phase_dt; 53 | f32 freq; 54 | f32 amplitude_ratio; 55 | f32 shape_parameter_0; 56 | u16 ui_id; 57 | bool is_modulator; 58 | f32 buffer[STREAM_BUFFER_SIZE]; 59 | } Oscillator; 60 | 61 | typedef struct OscillatorArray { 62 | Oscillator osc[MAX_OSCILLATORS]; 63 | usize count; 64 | WaveShapeFn wave_shape_fn; 65 | } OscillatorArray; 66 | 67 | typedef struct ModulationPair { 68 | Oscillator *modulator; 69 | Oscillator *carrier; 70 | u16 modulation_id; 71 | f32 modulation_ratio; 72 | } ModulationPair; 73 | 74 | typedef struct ModulationPairArray { 75 | ModulationPair data[MAX_OSCILLATORS]; 76 | usize count; 77 | } ModulationPairArray; 78 | 79 | typedef struct Synth { 80 | OscillatorArray oscillator_groups[WaveShape_COUNT-1]; 81 | usize oscillator_groups_count; 82 | 83 | f32 *signal; 84 | usize signal_count; 85 | f32 audio_frame_duration; 86 | 87 | UiOscillator ui_oscillator[MAX_UI_OSCILLATORS]; 88 | usize ui_oscillator_count; 89 | 90 | ModulationPairArray modulation_pairs; 91 | } Synth; 92 | 93 | internal f32 94 | FrequencyFromSemitone(f32 semitone) 95 | { 96 | return powf(2.f, semitone/12.f) * BASE_NOTE_FREQ; 97 | } 98 | 99 | internal f32 100 | SemitoneFromFrequency(f32 freq) 101 | { 102 | return 12.f * Log2f(freq / BASE_NOTE_FREQ); 103 | } 104 | 105 | internal Oscillator* 106 | NextOscillator(OscillatorArray* osc_array) 107 | { 108 | Assert(osc_array->count < MAX_OSCILLATORS); 109 | return osc_array->osc + (osc_array->count++); 110 | } 111 | 112 | internal void 113 | ClearOscillatorArray(OscillatorArray* osc_array) 114 | { 115 | osc_array->count = 0; 116 | } 117 | 118 | internal void 119 | UpdatePhase(f32 *phase_ratio, f32 *phase_dt, f32 freq, f32 freq_mod) 120 | { 121 | *phase_dt = ((freq + freq_mod) * SAMPLE_DURATION); 122 | *phase_ratio = *phase_ratio + *phase_dt; 123 | if (*phase_ratio < 0.0f) 124 | *phase_ratio += 1.0f; 125 | if (*phase_ratio >= 1.0f) 126 | *phase_ratio -= 1.0f; 127 | } 128 | 129 | internal void 130 | UpdatePhaseInOsc(Oscillator *osc) 131 | { 132 | osc->phase_dt = ((osc->freq) * SAMPLE_DURATION); 133 | osc->phase_ratio += osc->phase_dt; 134 | if (osc->phase_ratio < 0.0f) 135 | osc->phase_ratio += 1.0f; 136 | if (osc->phase_ratio >= 1.0f) 137 | osc->phase_ratio -= 1.0f; 138 | } 139 | 140 | internal void 141 | ZeroSignal(f32* signal) 142 | { 143 | for(usize t = 0; t < STREAM_BUFFER_SIZE; t++) 144 | { 145 | signal[t] = 0.0f; 146 | } 147 | } 148 | 149 | // @shapefn 150 | internal f32 151 | BandlimitedRipple(f32 phase_ratio, f32 phase_dt) 152 | { 153 | if (phase_ratio < phase_dt) 154 | { 155 | phase_ratio /= phase_dt; 156 | return (phase_ratio+phase_ratio) - (phase_ratio*phase_ratio) - 1.0f; 157 | } 158 | else if (phase_ratio > 1.0f - phase_dt) 159 | { 160 | phase_ratio = (phase_ratio - 1.0f) / phase_dt; 161 | return (phase_ratio*phase_ratio) + (phase_ratio+phase_ratio) + 1.0f; 162 | } 163 | else return 0.0f; 164 | } 165 | 166 | 167 | // NOTE(luke): Remove this before next episode 168 | inline f32 169 | SineFast(f32 x) 170 | { 171 | //x = fmodf(x, 2*PI); 172 | f32 a = 0.083f; 173 | f32 a2 = 9.424778f * a; 174 | f32 a3 = 19.739209f * a; 175 | f32 xx = x*x; 176 | f32 xxx = xx*x; 177 | return (a * xxx) - (a2 * xx) + (a3 * x); 178 | } 179 | 180 | // @shapefn 181 | internal f32 182 | SineShape(const f32 phase_ratio, const f32 phase_dt, const f32 shape_param) 183 | { 184 | return SineFast(2.f * PI * phase_ratio); 185 | } 186 | 187 | // @shapefn 188 | internal f32 189 | SawtoothShape(const f32 phase_ratio, const f32 phase_dt, const f32 shape_param) 190 | { 191 | f32 sample = (phase_ratio * 2.0f) - 1.0f; 192 | sample -= BandlimitedRipple(phase_ratio, phase_dt); 193 | return sample; 194 | } 195 | 196 | // @shapefn 197 | internal f32 198 | TriangleShape(const f32 phase_ratio, const f32 phase_dt, const f32 shape_param) 199 | { 200 | // TODO: Make this band-limited. 201 | if (phase_ratio < 0.5f) 202 | return (phase_ratio * 4.0f) - 1.0f; 203 | else 204 | return (phase_ratio * -4.0f) + 3.0f; 205 | } 206 | 207 | // @shapefn 208 | internal f32 209 | SquareShape(const f32 phase_ratio, const f32 phase_dt, const f32 shape_param) 210 | { 211 | f32 duty_cycle = shape_param; 212 | f32 sample = (phase_ratio < duty_cycle) ? 1.0f : -1.0f; 213 | sample += BandlimitedRipple(phase_ratio, phase_dt); 214 | sample -= BandlimitedRipple(fmodf(phase_ratio + (1.f - duty_cycle), 1.0f), phase_dt); 215 | return sample; 216 | } 217 | 218 | // @shapefn 219 | internal f32 220 | RoundedSquareShape(const f32 phase_ratio, const f32 phase_dt, const f32 shape_param) 221 | { 222 | f32 s = (shape_param * 8.f) + 2.f; 223 | f32 base = (f32)fabs(s); 224 | f32 power = s * sinf(phase_ratio * PI * 2); 225 | f32 denominator = powf(base, power) + 1.f; 226 | f32 sample = (2.f / denominator) - 1.f; 227 | return sample; 228 | } 229 | 230 | internal void 231 | UpdateOscArray(OscillatorArray *osc_array, ModulationPairArray *mod_array) 232 | { 233 | for (i32 i = 0; i < osc_array->count; i++) 234 | { 235 | Oscillator *osc = &(osc_array->osc[i]); 236 | if (osc->freq > (SAMPLE_RATE/2) || osc->freq < -(SAMPLE_RATE/2)) continue; 237 | 238 | ModulationPair *modulation = 0; 239 | for(usize mod_i = 0; 240 | mod_i < mod_array->count; 241 | mod_i++) 242 | { 243 | if (mod_array->data[mod_i].carrier == osc) 244 | { 245 | modulation = &mod_array->data[mod_i]; 246 | break; 247 | } 248 | } 249 | 250 | 251 | for(usize t = 0; t < STREAM_BUFFER_SIZE; t++) 252 | { 253 | f32 freq_mod = 0.0f; 254 | if (modulation) 255 | { 256 | freq_mod = modulation->modulator->buffer[t] * modulation->modulation_ratio; 257 | } 258 | 259 | UpdatePhase(&osc->phase_ratio, 260 | &osc->phase_dt, 261 | osc->freq, 262 | freq_mod); 263 | 264 | f32 sample = osc_array->wave_shape_fn(osc->phase_ratio, 265 | osc->phase_dt, 266 | osc->shape_parameter_0); 267 | sample *= osc->amplitude_ratio; 268 | osc->buffer[t] = sample; 269 | } 270 | } 271 | } 272 | 273 | internal void 274 | AccumulateOscillatorsIntoSignal(Synth *synth) 275 | { 276 | for (usize i = 0; 277 | i < synth->oscillator_groups_count; 278 | i++) 279 | { 280 | OscillatorArray *osc_array = &synth->oscillator_groups[i]; 281 | for (usize osc_i = 0; 282 | osc_i < osc_array->count; 283 | osc_i++) 284 | { 285 | Oscillator *osc = &(osc_array->osc[osc_i]); 286 | 287 | if (osc->is_modulator) continue; 288 | 289 | for (usize t = 0; 290 | t < STREAM_BUFFER_SIZE; 291 | t++) 292 | { 293 | synth->signal[t] += osc->buffer[t]; 294 | } 295 | } 296 | } 297 | } 298 | 299 | // @mainloop 300 | internal void 301 | HandleAudioStream(AudioStream stream, Synth* synth) 302 | { 303 | f32 audio_frame_duration = 0.0f; 304 | if (IsAudioStreamProcessed(stream)) 305 | { 306 | const f32 audio_frame_start_time = GetTime(); 307 | ZeroSignal(synth->signal); 308 | for (usize i = 0; 309 | i < synth->oscillator_groups_count; 310 | i++) 311 | { 312 | OscillatorArray *osc_array = &synth->oscillator_groups[i]; 313 | UpdateOscArray(osc_array, &synth->modulation_pairs); 314 | } 315 | 316 | AccumulateOscillatorsIntoSignal(synth); 317 | UpdateAudioStream(stream, synth->signal, synth->signal_count); 318 | synth->audio_frame_duration = GetTime() - audio_frame_start_time; 319 | } 320 | } 321 | 322 | // @drawfn 323 | internal void 324 | DrawSignal(Synth *synth) 325 | { 326 | // Drawing the signal. 327 | { 328 | i32 zero_crossing_index = 0; 329 | for (i32 i = 1; 330 | i < synth->signal_count; 331 | i++) 332 | { 333 | if (synth->signal[i] >= 0.0f && synth->signal[i-1] < 0.0f) // zero-crossing 334 | { 335 | zero_crossing_index = i; 336 | break; 337 | } 338 | } 339 | 340 | Vector2 signal_points[STREAM_BUFFER_SIZE]; 341 | const f32 screen_vertical_midpoint = (SCREEN_HEIGHT/2); 342 | for (i32 point_idx = 0; 343 | point_idx < synth->signal_count; 344 | point_idx++) 345 | { 346 | const i32 signal_idx = (point_idx + zero_crossing_index) % STREAM_BUFFER_SIZE; 347 | signal_points[point_idx].x = (f32)point_idx + UI_PANEL_WIDTH; 348 | signal_points[point_idx].y = screen_vertical_midpoint + (i32)(synth->signal[signal_idx] * 300); 349 | } 350 | DrawLineStrip(signal_points, STREAM_BUFFER_SIZE - zero_crossing_index, RED); 351 | } 352 | } 353 | 354 | 355 | // @drawfn 356 | internal void 357 | DrawUi(Synth *synth) 358 | { 359 | const i32 panel_x_start = 0; 360 | const i32 panel_y_start = 0; 361 | const i32 panel_width = UI_PANEL_WIDTH; 362 | const i32 panel_height = SCREEN_WIDTH; 363 | 364 | bool is_shape_dropdown_open = false; 365 | i32 shape_index = 0; 366 | 367 | GuiGrid((Rectangle){0,0,SCREEN_WIDTH,SCREEN_HEIGHT}, SCREEN_HEIGHT/8, 2); 368 | GuiPanel((Rectangle){ 369 | panel_x_start, 370 | panel_y_start, 371 | panel_width, 372 | panel_height 373 | }); 374 | 375 | bool click_add_oscillator = GuiButton((Rectangle){ 376 | panel_x_start + 10, 377 | panel_y_start + 10, 378 | panel_width - 20, 379 | 25 380 | }, "Add Oscillator"); 381 | if (click_add_oscillator) 382 | { 383 | synth->ui_oscillator_count += 1; 384 | // Set defaults: 385 | UiOscillator *ui_osc = synth->ui_oscillator + (synth->ui_oscillator_count - 1); 386 | ui_osc->shape = WaveShape_SINE; 387 | ui_osc->freq = BASE_NOTE_FREQ; 388 | ui_osc->amplitude_ratio = 0.1f; 389 | ui_osc->shape_parameter_0 = 0.5f; 390 | } 391 | 392 | f32 panel_y_offset = 0; 393 | for (i32 ui_osc_i = 0; ui_osc_i < synth->ui_oscillator_count; ui_osc_i++) 394 | { 395 | UiOscillator* ui_osc = &synth->ui_oscillator[ui_osc_i]; 396 | const bool has_shape_param = (ui_osc->shape == WaveShape_SQUARE || ui_osc->shape == WaveShape_ROUNDEDSQUARE); 397 | 398 | const i32 osc_panel_width = panel_width - 20; 399 | const i32 osc_panel_height = has_shape_param ? 130 : 100; 400 | const i32 osc_panel_x = panel_x_start + 10; 401 | const i32 osc_panel_y = panel_y_start + 50 + panel_y_offset; 402 | panel_y_offset += osc_panel_height + 5; 403 | GuiPanel((Rectangle){ 404 | osc_panel_x, 405 | osc_panel_y, 406 | osc_panel_width, 407 | osc_panel_height 408 | }); 409 | 410 | const f32 slider_padding = 50.f; 411 | const f32 el_spacing = 5.f; 412 | Rectangle el_rect = { 413 | .x = osc_panel_x + slider_padding + 30, 414 | .y = osc_panel_y + 10, 415 | .width = osc_panel_width - (slider_padding * 2), 416 | .height = 25 417 | }; 418 | 419 | // Frequency slider 420 | u8 freq_slider_label[16]; 421 | sprintf(freq_slider_label, "%.1fHz", ui_osc->freq); 422 | f32 log_freq = log10f(ui_osc->freq); 423 | log_freq = GuiSlider(el_rect, 424 | freq_slider_label, 425 | "", 426 | log_freq, 427 | -1.0f, 428 | log10f((f32)(SAMPLE_RATE/2)) 429 | ); 430 | ui_osc->freq = powf(10.f, log_freq); 431 | el_rect.y += el_rect.height + el_spacing; 432 | 433 | // Amplitude slider 434 | f32 decibels = (20.f * log10f(ui_osc->amplitude_ratio)); 435 | u8 amp_slider_label[32]; 436 | sprintf(amp_slider_label, "%.1f dB", decibels); 437 | decibels = GuiSlider(el_rect, 438 | amp_slider_label, 439 | "", 440 | decibels, 441 | -60.0f, 442 | 0.0f 443 | ); 444 | ui_osc->amplitude_ratio = powf(10.f, decibels * (1.f/20.f)); 445 | el_rect.y += el_rect.height + el_spacing; 446 | 447 | // Shape parameter slider 448 | if (has_shape_param) 449 | { 450 | f32 shape_param = ui_osc->shape_parameter_0; 451 | u8 shape_param_label[32]; 452 | sprintf(shape_param_label, "%.1f", shape_param); 453 | shape_param = GuiSlider(el_rect, 454 | shape_param_label, 455 | "", 456 | shape_param, 457 | 0.f, 458 | 1.f 459 | ); 460 | ui_osc->shape_parameter_0 = shape_param; 461 | el_rect.y += el_rect.height + el_spacing; 462 | } 463 | 464 | // Defer shape drop-down box. 465 | ui_osc->shape_dropdown_rect = el_rect; 466 | el_rect.y += el_rect.height + el_spacing; 467 | 468 | Rectangle delete_button_rect = el_rect; 469 | delete_button_rect.x = osc_panel_x + 5; 470 | delete_button_rect.y -= el_rect.height + el_spacing; 471 | delete_button_rect.width = 30; 472 | bool is_delete_button_pressed = GuiButton(delete_button_rect, "X"); 473 | if (is_delete_button_pressed) 474 | { 475 | memmove( 476 | synth->ui_oscillator + ui_osc_i, 477 | synth->ui_oscillator + ui_osc_i + 1, 478 | (synth->ui_oscillator_count - ui_osc_i) * sizeof(UiOscillator) 479 | ); 480 | synth->ui_oscillator_count -= 1; 481 | } 482 | 483 | Rectangle modulation_button_rect = delete_button_rect; 484 | modulation_button_rect.x += 40; 485 | char *modulation_button_text = (ui_osc->modulation_state == 0) ? "N/A" : TextFormat("%d", ui_osc->modulation_state); 486 | bool modulation_button_pressed = GuiButton(modulation_button_rect, modulation_button_text); 487 | if (modulation_button_pressed) 488 | { 489 | ui_osc->modulation_state += 1; 490 | if (ui_osc->modulation_state == 8) 491 | { 492 | ui_osc->modulation_state = 0; 493 | } 494 | } 495 | } 496 | 497 | for (i32 ui_osc_i = 0; 498 | ui_osc_i < synth->ui_oscillator_count; 499 | ui_osc_i += 1) 500 | { 501 | UiOscillator* ui_osc = &synth->ui_oscillator[ui_osc_i]; 502 | // Shape select 503 | i32 shape_index = (i32)(ui_osc->shape); 504 | bool is_dropdown_click = GuiDropdownBox(ui_osc->shape_dropdown_rect, 505 | WAVE_SHAPE_OPTIONS, 506 | &shape_index, 507 | ui_osc->is_dropdown_open 508 | ); 509 | ui_osc->shape = (WaveShape)(shape_index); 510 | if (is_dropdown_click) 511 | { 512 | ui_osc->is_dropdown_open = !ui_osc->is_dropdown_open; 513 | } 514 | if (ui_osc->is_dropdown_open) break; 515 | } 516 | } 517 | 518 | internal void 519 | ApplyUiState(Synth *synth) 520 | { 521 | // Reset synth 522 | // TODO(luke): make this something we can iterate. 523 | for (usize i = 0; 524 | i < synth->oscillator_groups_count; 525 | i++) 526 | { 527 | ClearOscillatorArray(&synth->oscillator_groups[i]); 528 | } 529 | synth->modulation_pairs.count = 0; 530 | 531 | for (i32 ui_osc_i = 0; 532 | ui_osc_i < synth->ui_oscillator_count; 533 | ui_osc_i++) 534 | { 535 | UiOscillator ui_osc = synth->ui_oscillator[ui_osc_i]; 536 | 537 | for(i32 note_idx = midi_keys.count-1; 538 | note_idx >= 0; 539 | note_idx--) 540 | { 541 | MidiKey midi_key = midi_keys.data[note_idx]; 542 | if (!midi_key.is_on) continue; 543 | 544 | Oscillator *osc = NULL; 545 | if (ui_osc.shape > 0 && ui_osc.shape < WaveShape_COUNT) 546 | { 547 | osc = NextOscillator(&synth->oscillator_groups[ui_osc.shape-1]); 548 | } 549 | 550 | if (osc != NULL) 551 | { 552 | osc->ui_id = ui_osc_i; 553 | f32 ui_semitone = SemitoneFromFrequency(ui_osc.freq); 554 | f32 midi_semitone = (f32)(midi_key.note - BASE_MIDI_NOTE); 555 | f32 osc_freq = FrequencyFromSemitone(ui_semitone + midi_semitone); 556 | osc->freq = osc_freq; 557 | osc->amplitude_ratio = ui_osc.amplitude_ratio; 558 | osc->shape_parameter_0 = ui_osc.shape_parameter_0; 559 | osc->is_modulator = false; 560 | 561 | if (ui_osc.modulation_state > 0 && (ui_osc.modulation_state-1) < synth->ui_oscillator_count) 562 | { 563 | ModulationPair *mod_pair = synth->modulation_pairs.data + synth->modulation_pairs.count++; 564 | mod_pair->modulator = 0; 565 | mod_pair->carrier = osc; 566 | mod_pair->modulation_id = ui_osc.modulation_state - 1; 567 | mod_pair->modulation_ratio = 100.0f; 568 | } 569 | } 570 | } 571 | } 572 | 573 | for(usize mod_i = 0; 574 | mod_i < synth->modulation_pairs.count; 575 | mod_i++) 576 | { 577 | ModulationPair *mod_pair = &synth->modulation_pairs.data[mod_i]; 578 | u16 shape_id = (u16)synth->ui_oscillator[mod_pair->modulation_id].shape; 579 | OscillatorArray *osc_array = &synth->oscillator_groups[shape_id-1]; 580 | // TODO(luke): modulators (LFOs) should not be per-note. 581 | for (usize osc_i = 0; 582 | osc_i < osc_array->count; 583 | osc_i++) 584 | { 585 | Oscillator *osc = &osc_array->osc[osc_i]; 586 | if (osc->ui_id == mod_pair->modulation_id) 587 | { 588 | if (mod_pair->modulator == 0) 589 | mod_pair->modulator = osc; 590 | osc->is_modulator = true; 591 | } 592 | } 593 | } 594 | } 595 | 596 | i32 597 | main(i32 argc, char **argv) 598 | { 599 | const i32 screen_width = 1024; 600 | const i32 screen_height = 768; 601 | InitWindow(screen_width, screen_height, "Synth"); 602 | SetTargetFPS(TARGET_FPS); 603 | InitAudioDevice(); 604 | midi_keys.count = ArrayCount(midi_keys.data); 605 | midi_input_handle = SynthMidiInit(0, &midi_keys); 606 | GuiLoadStyle(".\\styles\\jungle\\jungle.rgs"); 607 | 608 | u32 sample_rate = SAMPLE_RATE; 609 | SetAudioStreamBufferSizeDefault(STREAM_BUFFER_SIZE); 610 | AudioStream synth_stream = InitAudioStream(sample_rate, 611 | sizeof(f32) * 8, 612 | 1); 613 | SetAudioStreamVolume(synth_stream, 0.01f); 614 | PlayAudioStream(synth_stream); 615 | 616 | ModulationPair modulation_pairs[256] = {0}; 617 | f32 signal[STREAM_BUFFER_SIZE] = {0}; 618 | 619 | printf("Oscillator size: %lld\n", sizeof(Oscillator)); 620 | printf("UiOscillator size: %lld\n", sizeof(UiOscillator)); 621 | printf("OscillatorArray size: %lld\n", sizeof(OscillatorArray)); 622 | printf("Synth size: %lld\n", sizeof(Synth)); 623 | 624 | Synth *synth = (Synth *)malloc(sizeof(Synth)); 625 | synth->oscillator_groups_count = ArrayCount(synth->oscillator_groups); 626 | synth->signal = signal; 627 | synth->signal_count = ArrayCount(signal); 628 | 629 | synth->oscillator_groups[WaveShape_SINE-1].count = 0; 630 | synth->oscillator_groups[WaveShape_SINE-1].wave_shape_fn = SineShape; 631 | synth->oscillator_groups[WaveShape_SAWTOOTH-1].count = 0; 632 | synth->oscillator_groups[WaveShape_SAWTOOTH-1].wave_shape_fn = SawtoothShape; 633 | synth->oscillator_groups[WaveShape_TRIANGLE-1].count = 0; 634 | synth->oscillator_groups[WaveShape_TRIANGLE-1].wave_shape_fn = TriangleShape; 635 | synth->oscillator_groups[WaveShape_SQUARE-1].count = 0; 636 | synth->oscillator_groups[WaveShape_SQUARE-1].wave_shape_fn = SquareShape; 637 | synth->oscillator_groups[WaveShape_ROUNDEDSQUARE-1].count = 0; 638 | synth->oscillator_groups[WaveShape_ROUNDEDSQUARE-1].wave_shape_fn = RoundedSquareShape; 639 | 640 | synth->modulation_pairs.count = 0; 641 | 642 | #if 0 643 | synth->modulation_pairs.count = 1; 644 | synth->modulation_pairs.data[0].modulator = &synth->oscillator_groups[WaveShape_SINE-1].osc[0]; 645 | synth->modulation_pairs.data[0].carrier = &synth->oscillator_groups[WaveShape_SINE-1].osc[1]; 646 | synth->modulation_pairs.data[0].modulation_ratio = 100.0f; 647 | #endif 648 | 649 | // @mainloop 650 | while(!WindowShouldClose()) 651 | { 652 | HandleAudioStream(synth_stream, synth); 653 | BeginDrawing(); 654 | ClearBackground(BLACK); 655 | DrawUi(synth); 656 | ApplyUiState(synth); 657 | DrawSignal(synth); 658 | 659 | const f32 total_frame_duration = GetFrameTime(); 660 | DrawText(FormatText("Frame time: %.3f%%, Audio budget: %.3f%%", 661 | (100.0f / (total_frame_duration * TARGET_FPS)), 662 | 100.0f / ((1.0f / synth->audio_frame_duration) / ((f32)SAMPLE_RATE/STREAM_BUFFER_SIZE))), 663 | UI_PANEL_WIDTH + 10, 10, 664 | 20, 665 | RED); 666 | DrawText(FormatText("Fundemental Freq: %.1f", 667 | synth->oscillator_groups[0].osc[0].freq), 668 | UI_PANEL_WIDTH + 10, 30, 669 | 20, 670 | RED); 671 | EndDrawing(); 672 | } 673 | 674 | if (midi_input_handle) 675 | { 676 | SynthMidiStop(midi_input_handle); 677 | } 678 | CloseAudioStream(synth_stream); 679 | CloseAudioDevice(); 680 | CloseWindow(); 681 | 682 | return 0; 683 | } -------------------------------------------------------------------------------- /synth/synth.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perky/coding_a_synth_in_c/37dfcc33c158090ae9f853eab03e087ad601fb83/synth/synth.exe --------------------------------------------------------------------------------