minimal playback of basic fm operator
This commit is contained in:
commit
9923a7270e
130
Source/Maker/main.c
Normal file
130
Source/Maker/main.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define SOKOL_IMPL
|
||||||
|
#define SOKOL_GLCORE
|
||||||
|
#include "sokol_app.h"
|
||||||
|
#include "sokol_audio.h"
|
||||||
|
#include "sokol_log.h"
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
#include "../oscillators.c"
|
||||||
|
#include "../phaser.c"
|
||||||
|
|
||||||
|
static struct stfu_sinewave sine0;
|
||||||
|
static struct stfu_phaser phaser0;
|
||||||
|
static struct stfu_phaser phaser1;
|
||||||
|
|
||||||
|
static float key_frequency = STFU_C4_FREQUENCY;
|
||||||
|
|
||||||
|
static void stream(float *buffer, int num_frames, int num_channels) {
|
||||||
|
for (int i = 0; i < num_frames; ++i) {
|
||||||
|
// sine0 = stfu_pump_sinewave(sine0); // Carrier
|
||||||
|
phaser0 = stfu_pump_phaser(phaser0);
|
||||||
|
phaser1 = stfu_pump_phaser(phaser1);
|
||||||
|
buffer[2 * i + 0] = sinf(phaser0.v + sinf(phaser1.v));
|
||||||
|
buffer[2 * i + 1] = sinf(phaser0.v + sinf(phaser1.v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(void) {
|
||||||
|
saudio_setup(&(saudio_desc){
|
||||||
|
.sample_rate = STFU_AUDIO_FRAME_RATE,
|
||||||
|
.num_channels = STFU_AUDIO_CHANNEL_COUNT,
|
||||||
|
// .stream_cb = stream,
|
||||||
|
});
|
||||||
|
|
||||||
|
// sine0 = stfu_init_sinewave(STFU_A4_FREQUENCY / 2.0f, 0.0f, 0.8f);
|
||||||
|
phaser0 = stfu_init_phaser(key_frequency);
|
||||||
|
phaser1 = stfu_init_phaser(key_frequency * 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup(void) { saudio_shutdown(); }
|
||||||
|
|
||||||
|
static void event(const sapp_event *e) {
|
||||||
|
switch (e->type) {
|
||||||
|
case SAPP_EVENTTYPE_KEY_DOWN: {
|
||||||
|
if (e->key_repeat)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (e->key_code) {
|
||||||
|
case SAPP_KEYCODE_Z:
|
||||||
|
key_frequency = STFU_C4_FREQUENCY;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_X:
|
||||||
|
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_C:
|
||||||
|
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
|
||||||
|
STFU_NOTE_UPSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_V:
|
||||||
|
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
|
||||||
|
STFU_NOTE_UPSCALE_FACTOR * STFU_NOTE_UPSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_B:
|
||||||
|
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
|
||||||
|
STFU_NOTE_UPSCALE_FACTOR * STFU_NOTE_UPSCALE_FACTOR *
|
||||||
|
STFU_NOTE_UPSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_N:
|
||||||
|
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
|
||||||
|
STFU_NOTE_DOWNSCALE_FACTOR * STFU_NOTE_DOWNSCALE_FACTOR *
|
||||||
|
STFU_NOTE_DOWNSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_M:
|
||||||
|
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
|
||||||
|
STFU_NOTE_DOWNSCALE_FACTOR * STFU_NOTE_DOWNSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_COMMA:
|
||||||
|
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
|
||||||
|
STFU_NOTE_DOWNSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_PERIOD:
|
||||||
|
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
case SAPP_KEYCODE_SLASH:
|
||||||
|
key_frequency = STFU_A4_FREQUENCY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
phaser0 = stfu_set_phaser_frequency(phaser0, key_frequency);
|
||||||
|
phaser1 = stfu_set_phaser_frequency(phaser1, key_frequency * 0.25);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frame(void) {
|
||||||
|
int frames = (int)(sapp_frame_duration() * (float)STFU_AUDIO_FRAME_RATE);
|
||||||
|
int expected = saudio_expect();
|
||||||
|
frames = frames > expected ? expected : frames;
|
||||||
|
// todo: Prevent drifting apart.
|
||||||
|
static float buffer[STFU_AUDIO_FRAME_RATE * STFU_AUDIO_CHANNEL_COUNT];
|
||||||
|
while (frames > 0) {
|
||||||
|
int now = frames > STFU_AUDIO_FRAME_RATE ? STFU_AUDIO_FRAME_RATE : frames;
|
||||||
|
stream(buffer, now, STFU_AUDIO_CHANNEL_COUNT);
|
||||||
|
saudio_push(buffer, now);
|
||||||
|
frames -= now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sapp_desc sokol_main(int argc, char *argv[]) {
|
||||||
|
return (sapp_desc){
|
||||||
|
.width = 640,
|
||||||
|
.height = 480,
|
||||||
|
.init_cb = init,
|
||||||
|
.frame_cb = frame,
|
||||||
|
.cleanup_cb = cleanup,
|
||||||
|
.event_cb = event,
|
||||||
|
.logger.func = slog_func,
|
||||||
|
.gl_major_version = 2,
|
||||||
|
.gl_minor_version = 0,
|
||||||
|
// .swap_interval = 0,
|
||||||
|
};
|
||||||
|
}
|
11819
Source/Maker/sokol_app.h
Normal file
11819
Source/Maker/sokol_app.h
Normal file
File diff suppressed because it is too large
Load Diff
2598
Source/Maker/sokol_audio.h
Normal file
2598
Source/Maker/sokol_audio.h
Normal file
File diff suppressed because it is too large
Load Diff
343
Source/Maker/sokol_log.h
Normal file
343
Source/Maker/sokol_log.h
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
#if defined(SOKOL_IMPL) && !defined(SOKOL_LOG_IMPL)
|
||||||
|
#define SOKOL_LOG_IMPL
|
||||||
|
#endif
|
||||||
|
#ifndef SOKOL_LOG_INCLUDED
|
||||||
|
/*
|
||||||
|
sokol_log.h -- common logging callback for sokol headers
|
||||||
|
|
||||||
|
Project URL: https://github.com/floooh/sokol
|
||||||
|
|
||||||
|
Example code: https://github.com/floooh/sokol-samples
|
||||||
|
|
||||||
|
Do this:
|
||||||
|
#define SOKOL_IMPL or
|
||||||
|
#define SOKOL_LOG_IMPL
|
||||||
|
before you include this file in *one* C or C++ file to create the
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Optionally provide the following defines when building the implementation:
|
||||||
|
|
||||||
|
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
||||||
|
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
|
||||||
|
SOKOL_LOG_API_DECL - public function declaration prefix (default: extern)
|
||||||
|
SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
|
||||||
|
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
||||||
|
|
||||||
|
Optionally define the following for verbose output:
|
||||||
|
|
||||||
|
SOKOL_DEBUG - by default this is defined if _DEBUG is defined
|
||||||
|
|
||||||
|
|
||||||
|
OVERVIEW
|
||||||
|
========
|
||||||
|
sokol_log.h provides a default logging callback for other sokol headers.
|
||||||
|
|
||||||
|
To use the default log callback, just include sokol_log.h and provide
|
||||||
|
a function pointer to the 'slog_func' function when setting up the
|
||||||
|
sokol library:
|
||||||
|
|
||||||
|
For instance with sokol_audio.h:
|
||||||
|
|
||||||
|
#include "sokol_log.h"
|
||||||
|
...
|
||||||
|
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
|
||||||
|
|
||||||
|
Logging output goes to stderr and/or a platform specific logging subsystem
|
||||||
|
(which means that in some scenarios you might see logging messages duplicated):
|
||||||
|
|
||||||
|
- Windows: stderr + OutputDebugStringA()
|
||||||
|
- macOS/iOS/Linux: stderr + syslog()
|
||||||
|
- Emscripten: console.info()/warn()/error()
|
||||||
|
- Android: __android_log_write()
|
||||||
|
|
||||||
|
On Windows with sokol_app.h also note the runtime config items to make
|
||||||
|
stdout/stderr output visible on the console for WinMain() applications
|
||||||
|
via sapp_desc.win32_console_attach or sapp_desc.win32_console_create,
|
||||||
|
however when running in a debugger on Windows, the logging output should
|
||||||
|
show up on the debug output UI panel.
|
||||||
|
|
||||||
|
In debug mode, a log message might look like this:
|
||||||
|
|
||||||
|
[sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0:
|
||||||
|
SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas
|
||||||
|
|
||||||
|
The source path and line number is formatted like compiler errors, in some IDEs (like VSCode)
|
||||||
|
such error messages are clickable.
|
||||||
|
|
||||||
|
In release mode, logging is less verbose as to not bloat the executable with string data, but you still get
|
||||||
|
enough information to identify the type and location of an error:
|
||||||
|
|
||||||
|
[sspine][error][id:12][line:3472]
|
||||||
|
|
||||||
|
RULES FOR WRITING YOUR OWN LOGGING FUNCTION
|
||||||
|
===========================================
|
||||||
|
- must be re-entrant because it might be called from different threads
|
||||||
|
- must treat **all** provided string pointers as optional (can be null)
|
||||||
|
- don't store the string pointers, copy the string data instead
|
||||||
|
- must not return for log level panic
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
=======
|
||||||
|
zlib/libpng license
|
||||||
|
|
||||||
|
Copyright (c) 2023 Andre Weissflog
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
In no event will the authors be held liable for any damages arising from the
|
||||||
|
use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software in a
|
||||||
|
product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not
|
||||||
|
be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
#define SOKOL_LOG_INCLUDED (1)
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(SOKOL_API_DECL) && !defined(SOKOL_LOG_API_DECL)
|
||||||
|
#define SOKOL_LOG_API_DECL SOKOL_API_DECL
|
||||||
|
#endif
|
||||||
|
#ifndef SOKOL_LOG_API_DECL
|
||||||
|
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_LOG_IMPL)
|
||||||
|
#define SOKOL_LOG_API_DECL __declspec(dllexport)
|
||||||
|
#elif defined(_WIN32) && defined(SOKOL_DLL)
|
||||||
|
#define SOKOL_LOG_API_DECL __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define SOKOL_LOG_API_DECL extern
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Plug this function into the 'logger.func' struct item when initializing any of the sokol
|
||||||
|
headers. For instance for sokol_audio.h it would loom like this:
|
||||||
|
|
||||||
|
saudio_setup(&(saudio_desc){
|
||||||
|
.logger = {
|
||||||
|
.func = slog_func
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif // SOKOL_LOG_INCLUDED
|
||||||
|
|
||||||
|
// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██
|
||||||
|
// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
|
||||||
|
// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████
|
||||||
|
//
|
||||||
|
// >>implementation
|
||||||
|
#ifdef SOKOL_LOG_IMPL
|
||||||
|
#define SOKOL_LOG_IMPL_INCLUDED (1)
|
||||||
|
|
||||||
|
#ifndef SOKOL_API_IMPL
|
||||||
|
#define SOKOL_API_IMPL
|
||||||
|
#endif
|
||||||
|
#ifndef SOKOL_DEBUG
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define SOKOL_DEBUG
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef SOKOL_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define SOKOL_ASSERT(c) assert(c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SOKOL_PRIVATE
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define _SOKOL_PRIVATE __attribute__((unused)) static
|
||||||
|
#else
|
||||||
|
#define _SOKOL_PRIVATE static
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SOKOL_UNUSED
|
||||||
|
#define _SOKOL_UNUSED(x) (void)(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// platform detection
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define _SLOG_APPLE (1)
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
#define _SLOG_EMSCRIPTEN (1)
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define _SLOG_WINDOWS (1)
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
#define _SLOG_ANDROID (1)
|
||||||
|
#elif defined(__linux__) || defined(__unix__)
|
||||||
|
#define _SLOG_LINUX (1)
|
||||||
|
#else
|
||||||
|
#error "sokol_log.h: unknown platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h> // abort
|
||||||
|
#include <stdio.h> // fputs
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
#if defined(_SLOG_EMSCRIPTEN)
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#elif defined(_SLOG_WINDOWS)
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_SLOG_ANDROID)
|
||||||
|
#include <android/log.h>
|
||||||
|
#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
|
||||||
|
#include <syslog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// size of line buffer (on stack!) in bytes including terminating zero
|
||||||
|
#define _SLOG_LINE_LENGTH (512)
|
||||||
|
|
||||||
|
_SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, char* end) {
|
||||||
|
if (str) {
|
||||||
|
char c;
|
||||||
|
while (((c = *str++) != 0) && (dst < (end - 1))) {
|
||||||
|
*dst++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
_SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) {
|
||||||
|
const size_t max_digits_and_null = 11;
|
||||||
|
if (buf_size < max_digits_and_null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char* p = buf + max_digits_and_null;
|
||||||
|
*--p = 0;
|
||||||
|
do {
|
||||||
|
*--p = '0' + (x % 10);
|
||||||
|
x /= 10;
|
||||||
|
} while (x != 0);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_SLOG_EMSCRIPTEN)
|
||||||
|
EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), {
|
||||||
|
const str = UTF8ToString(c_str);
|
||||||
|
switch (level) {
|
||||||
|
case 0: console.error(str); break;
|
||||||
|
case 1: console.error(str); break;
|
||||||
|
case 2: console.warn(str); break;
|
||||||
|
default: console.info(str); break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) {
|
||||||
|
_SOKOL_UNUSED(user_data);
|
||||||
|
|
||||||
|
const char* log_level_str;
|
||||||
|
switch (log_level) {
|
||||||
|
case 0: log_level_str = "panic"; break;
|
||||||
|
case 1: log_level_str = "error"; break;
|
||||||
|
case 2: log_level_str = "warning"; break;
|
||||||
|
default: log_level_str = "info"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build log output line
|
||||||
|
char line_buf[_SLOG_LINE_LENGTH];
|
||||||
|
char* str = line_buf;
|
||||||
|
char* end = line_buf + sizeof(line_buf);
|
||||||
|
char num_buf[32];
|
||||||
|
if (tag) {
|
||||||
|
str = _slog_append("[", str, end);
|
||||||
|
str = _slog_append(tag, str, end);
|
||||||
|
str = _slog_append("]", str, end);
|
||||||
|
}
|
||||||
|
str = _slog_append("[", str, end);
|
||||||
|
str = _slog_append(log_level_str, str, end);
|
||||||
|
str = _slog_append("]", str, end);
|
||||||
|
str = _slog_append("[id:", str, end);
|
||||||
|
str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end);
|
||||||
|
str = _slog_append("]", str, end);
|
||||||
|
// if a filename is provided, build a clickable log message that's compatible with compiler error messages
|
||||||
|
if (filename) {
|
||||||
|
str = _slog_append(" ", str, end);
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// MSVC compiler error format
|
||||||
|
str = _slog_append(filename, str, end);
|
||||||
|
str = _slog_append("(", str, end);
|
||||||
|
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
|
||||||
|
str = _slog_append("): ", str, end);
|
||||||
|
#else
|
||||||
|
// gcc/clang compiler error format
|
||||||
|
str = _slog_append(filename, str, end);
|
||||||
|
str = _slog_append(":", str, end);
|
||||||
|
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
|
||||||
|
str = _slog_append(":0: ", str, end);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
str = _slog_append("[line:", str, end);
|
||||||
|
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
|
||||||
|
str = _slog_append("] ", str, end);
|
||||||
|
}
|
||||||
|
if (message) {
|
||||||
|
str = _slog_append("\n\t", str, end);
|
||||||
|
str = _slog_append(message, str, end);
|
||||||
|
}
|
||||||
|
str = _slog_append("\n\n", str, end);
|
||||||
|
if (0 == log_level) {
|
||||||
|
str = _slog_append("ABORTING because of [panic]\n", str, end);
|
||||||
|
(void)str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print to stderr?
|
||||||
|
#if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE)
|
||||||
|
fputs(line_buf, stderr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// platform specific logging calls
|
||||||
|
#if defined(_SLOG_WINDOWS)
|
||||||
|
OutputDebugStringA(line_buf);
|
||||||
|
#elif defined(_SLOG_ANDROID)
|
||||||
|
int prio;
|
||||||
|
switch (log_level) {
|
||||||
|
case 0: prio = ANDROID_LOG_FATAL; break;
|
||||||
|
case 1: prio = ANDROID_LOG_ERROR; break;
|
||||||
|
case 2: prio = ANDROID_LOG_WARN; break;
|
||||||
|
default: prio = ANDROID_LOG_INFO; break;
|
||||||
|
}
|
||||||
|
__android_log_write(prio, "SOKOL", line_buf);
|
||||||
|
#elif defined(_SLOG_EMSCRIPTEN)
|
||||||
|
slog_js_log(log_level, line_buf);
|
||||||
|
#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
|
||||||
|
int prio;
|
||||||
|
switch (log_level) {
|
||||||
|
case 0: prio = LOG_CRIT; break;
|
||||||
|
case 1: prio = LOG_ERR; break;
|
||||||
|
case 2: prio = LOG_WARNING; break;
|
||||||
|
default: prio = LOG_INFO; break;
|
||||||
|
}
|
||||||
|
syslog(prio, "%s", line_buf);
|
||||||
|
#endif
|
||||||
|
if (0 == log_level) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // SOKOL_LOG_IMPL
|
11
Source/config.h
Normal file
11
Source/config.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
/* Determines output framerate, in times per second. */
|
||||||
|
#define STFU_AUDIO_FRAME_RATE 44100
|
||||||
|
#define STFU_AUDIO_CHANNEL_COUNT 2
|
||||||
|
|
||||||
|
#define STFU_C4_FREQUENCY 261.63f
|
||||||
|
#define STFU_A4_FREQUENCY 440.0f
|
||||||
|
#define STFU_NOTE_UPSCALE_FACTOR 1.059463094f
|
||||||
|
#define STFU_NOTE_DOWNSCALE_FACTOR 0.943874313f
|
||||||
|
|
||||||
|
// todo: Array of precomputed note frequencies?
|
78
Source/oscillators.c
Normal file
78
Source/oscillators.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/* https://multimed.org/student/eim/en/04-FM.pdf */
|
||||||
|
|
||||||
|
/* Intended to be executed offline with values then embedded in the binary.
|
||||||
|
* By having usage of glibc sin and cos functions strictly offline it's easier
|
||||||
|
* to have it freestanding
|
||||||
|
*/
|
||||||
|
struct stfu_sinewave {
|
||||||
|
float f, s, c;
|
||||||
|
} stfu_init_sinewave(float frequency, float phase, float amplitude) {
|
||||||
|
struct stfu_sinewave r;
|
||||||
|
r.f = 2.f * sinf((float)M_PI * frequency / STFU_AUDIO_FRAME_RATE);
|
||||||
|
r.s = amplitude * sinf(phase);
|
||||||
|
r.c = amplitude * cosf(phase);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use `s` for sine value and `c` for cosine on caller side */
|
||||||
|
struct stfu_sinewave stfu_pump_sinewave(struct stfu_sinewave wave) {
|
||||||
|
wave.s -= wave.f * wave.c;
|
||||||
|
wave.c += wave.f * wave.s;
|
||||||
|
return wave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implemented over sinewave */
|
||||||
|
struct stfu_sqrtwave {
|
||||||
|
struct stfu_sinewave w;
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t u;
|
||||||
|
} v;
|
||||||
|
} stfu_init_sqrtwave(float frequency, float phase, float amplitude) {
|
||||||
|
struct stfu_sqrtwave r;
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t u;
|
||||||
|
} v, a;
|
||||||
|
r.w = stfu_init_sinewave(frequency, phase, 1.f);
|
||||||
|
v.f = r.w.s;
|
||||||
|
a.f = amplitude;
|
||||||
|
r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use floating point bit representation to infer sign, all other bits are set
|
||||||
|
* to amplitude */
|
||||||
|
struct stfu_sqrtwave stfu_pump_sqrtwave(struct stfu_sqrtwave wave) {
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t u;
|
||||||
|
} v;
|
||||||
|
stfu_pump_sinewave(wave.w);
|
||||||
|
v.f = wave.w.s;
|
||||||
|
wave.v.u = (wave.v.u & 0x7fffffff) | (v.u & 0x80000000);
|
||||||
|
return wave;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stfu_sawtooth {
|
||||||
|
float v, a, i;
|
||||||
|
} stfu_init_sawtooth(float frequency, float phase, float amplitude) {
|
||||||
|
struct stfu_sawtooth r;
|
||||||
|
r.v = sinf(phase) * amplitude;
|
||||||
|
r.a = amplitude;
|
||||||
|
r.i = 2.f * frequency / STFU_AUDIO_FRAME_RATE * amplitude;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple amplitude overflow check with truncation */
|
||||||
|
struct stfu_sawtooth stfu_pump_sawtooth(struct stfu_sawtooth wave) {
|
||||||
|
wave.v += wave.i;
|
||||||
|
if (wave.v > wave.a)
|
||||||
|
wave.v -= wave.a * 2.f;
|
||||||
|
return wave;
|
||||||
|
}
|
31
Source/phaser.c
Normal file
31
Source/phaser.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
struct stfu_phaser stfu_pump_phaser(struct stfu_phaser phaser);
|
||||||
|
struct stfu_phaser stfu_set_phaser_frequency(struct stfu_phaser phaser,
|
||||||
|
float frequency);
|
||||||
|
|
||||||
|
/* Useful for feeding into phase parameters of oscillators and such.
|
||||||
|
* Repeats over [-PI, PI)
|
||||||
|
*/
|
||||||
|
struct stfu_phaser {
|
||||||
|
float v, a;
|
||||||
|
} stfu_init_phaser(float frequency) {
|
||||||
|
struct stfu_phaser r = {0};
|
||||||
|
r = stfu_set_phaser_frequency(r, frequency);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stfu_phaser stfu_pump_phaser(struct stfu_phaser phaser) {
|
||||||
|
phaser.v += phaser.a;
|
||||||
|
if (phaser.v >= (float)M_PI)
|
||||||
|
phaser.v -= (float)M_PI * 2.0f;
|
||||||
|
return phaser;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stfu_phaser stfu_set_phaser_frequency(struct stfu_phaser phaser,
|
||||||
|
float frequency) {
|
||||||
|
phaser.a = 2 * ((float)M_PI / (float)STFU_AUDIO_FRAME_RATE) * frequency;
|
||||||
|
return phaser;
|
||||||
|
}
|
20
Source/timer.c
Normal file
20
Source/timer.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
struct stfu_timer {
|
||||||
|
float v, a;
|
||||||
|
} stfu_init_timer() {
|
||||||
|
struct stfu_timer r;
|
||||||
|
r.v = 0;
|
||||||
|
r.a = (1.0f / STFU_AUDIO_FRAME_RATE);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: Pass period parameter?
|
||||||
|
struct stfu_timer stfu_pump_timer(struct stfu_timer wave) {
|
||||||
|
wave.v += wave.a;
|
||||||
|
if (wave.v > 1000)
|
||||||
|
wave.v -= 1000;
|
||||||
|
return wave;
|
||||||
|
}
|
10
readme.md
Normal file
10
readme.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# STFU ! SoundTracker Format Unirepo
|
||||||
|
Grassroot music format specifically designed for game soundtracks with accent on binary efficiency in its various forms.
|
||||||
|
|
||||||
|
- Separation of Maker and Player binaries, with Player being absolutely dependency free.
|
||||||
|
- Samples and instruments are stored outside of tracks in a shared data base allowing reuse.
|
||||||
|
- Sound synthesis from piping basic blocks.
|
||||||
|
- Live and proceduraly editable.
|
||||||
|
|
||||||
|
## Maker
|
||||||
|
Crossplatform Sokol headers based live editor.
|
Loading…
Reference in New Issue
Block a user