Add debug log to cosmoaudio and add examples

This commit is contained in:
Justine Tunney 2024-09-11 02:14:38 -07:00
parent a5c0189bf6
commit 0f3457c172
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
38 changed files with 504 additions and 371 deletions

View file

@ -18,7 +18,9 @@
*/
#include "dsp/audio/cosmoaudio/cosmoaudio.h"
#include "dsp/audio/describe.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
@ -201,7 +203,7 @@ static void *cosmoaudio_dlopen(const char *name) {
return 0;
}
static void cosmoaudio_setup(void) {
static void cosmoaudio_setup_impl(void) {
void *handle;
if (IsOpenbsd())
return; // no dlopen support yet
@ -239,6 +241,12 @@ WeAreGood:
g_audio.poll = cosmo_dlsym(handle, "cosmoaudio_poll");
}
static void cosmoaudio_setup(void) {
BLOCK_CANCELATION;
cosmoaudio_setup_impl();
ALLOW_CANCELATION;
}
static void cosmoaudio_init(void) {
pthread_once(&g_audio.once, cosmoaudio_setup);
}
@ -249,10 +257,13 @@ COSMOAUDIO_ABI int cosmoaudio_open(
char sbuf[32];
char dbuf[256];
cosmoaudio_init();
if (g_audio.open)
if (g_audio.open) {
BLOCK_SIGNALS;
status = g_audio.open(out_ca, options);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
STRACE("cosmoaudio_open([%p], %s) → %s",
out_ca ? *out_ca : (struct CosmoAudio *)-1,
cosmoaudio_describe_open_options(dbuf, sizeof(dbuf), options),
@ -263,10 +274,13 @@ COSMOAUDIO_ABI int cosmoaudio_open(
COSMOAUDIO_ABI int cosmoaudio_close(struct CosmoAudio *ca) {
int status;
char sbuf[32];
if (g_audio.close)
if (g_audio.close) {
BLOCK_SIGNALS;
status = g_audio.close(ca);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
STRACE("cosmoaudio_close(%p) → %s", ca,
cosmoaudio_describe_status(sbuf, sizeof(sbuf), status));
return status;
@ -276,10 +290,13 @@ COSMOAUDIO_ABI int cosmoaudio_write(struct CosmoAudio *ca, const float *data,
int frames) {
int status;
char sbuf[32];
if (g_audio.write)
if (g_audio.write) {
BLOCK_SIGNALS;
status = g_audio.write(ca, data, frames);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
if (frames <= 0 || frames >= 160)
DATATRACE("cosmoaudio_write(%p, %p, %d) → %s", ca, data, frames,
cosmoaudio_describe_status(sbuf, sizeof(sbuf), status));
@ -290,10 +307,13 @@ COSMOAUDIO_ABI int cosmoaudio_read(struct CosmoAudio *ca, float *data,
int frames) {
int status;
char sbuf[32];
if (g_audio.read)
if (g_audio.read) {
BLOCK_SIGNALS;
status = g_audio.read(ca, data, frames);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
if (frames <= 0 || frames >= 160)
DATATRACE("cosmoaudio_read(%p, %p, %d) → %s", ca, data, frames,
cosmoaudio_describe_status(sbuf, sizeof(sbuf), status));
@ -303,10 +323,13 @@ COSMOAUDIO_ABI int cosmoaudio_read(struct CosmoAudio *ca, float *data,
COSMOAUDIO_ABI int cosmoaudio_flush(struct CosmoAudio *ca) {
int status;
char sbuf[32];
if (g_audio.flush)
if (g_audio.flush) {
BLOCK_SIGNALS;
status = g_audio.flush(ca);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
DATATRACE("cosmoaudio_flush(%p) → %s", ca,
cosmoaudio_describe_status(sbuf, sizeof(sbuf), status));
return status;
@ -318,10 +341,13 @@ COSMOAUDIO_ABI int cosmoaudio_poll(struct CosmoAudio *ca,
int status;
char sbuf[32];
char fbuf[2][20];
if (g_audio.poll)
if (g_audio.poll) {
BLOCK_SIGNALS;
status = g_audio.poll(ca, in_out_readFrames, in_out_writeFrames);
else
ALLOW_SIGNALS;
} else {
status = COSMOAUDIO_ELINK;
}
DATATRACE("cosmoaudio_poll(%p, %s, %s) → %s", ca,
cosmoaudio_describe_poll_frames(fbuf[0], sizeof(fbuf[0]),
in_out_readFrames),

View file

@ -19,25 +19,19 @@
#include <stdlib.h>
#include <string.h>
#define MA_STATIC
#define MA_DEBUG_OUTPUT
#define MA_DR_MP3_NO_STDIO
#define MA_NO_DECODING
#define MA_NO_ENCODING
#define MA_NO_ENGINE
#define MA_NO_GENERATION
#define MA_NO_NODE_GRAPH
#define MA_NO_RESOURCE_MANAGER
#ifdef NDEBUG
#define MA_DR_MP3_NO_STDIO
#endif
#define MA_STATIC
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#ifndef NDEBUG
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define LOG(...) (void)0
#endif
struct CosmoAudio {
enum CosmoAudioDeviceType deviceType;
ma_uint32 outputBufferFrames;
@ -45,14 +39,16 @@ struct CosmoAudio {
int sampleRate;
int channels;
int isLeft;
ma_context context;
ma_device device;
ma_pcm_rb output;
ma_pcm_rb input;
ma_event event;
ma_log log;
};
static int read_ring_buffer(ma_pcm_rb* rb, float* pOutput, ma_uint32 frameCount,
ma_uint32 channels) {
static int read_ring_buffer(ma_log* log, ma_pcm_rb* rb, float* pOutput,
ma_uint32 frameCount, ma_uint32 channels) {
ma_result result;
ma_uint32 framesRead;
ma_uint32 framesToRead;
@ -61,7 +57,9 @@ static int read_ring_buffer(ma_pcm_rb* rb, float* pOutput, ma_uint32 frameCount,
void* pMappedBuffer;
result = ma_pcm_rb_acquire_read(rb, &framesToRead, &pMappedBuffer);
if (result != MA_SUCCESS) {
LOG("ma_pcm_rb_acquire_read failed: %s\n", ma_result_description(result));
ma_log_postf(log, MA_LOG_LEVEL_WARNING,
"ma_pcm_rb_acquire_read failed: %s\n",
ma_result_description(result));
return COSMOAUDIO_ERROR;
}
if (!framesToRead)
@ -74,14 +72,16 @@ static int read_ring_buffer(ma_pcm_rb* rb, float* pOutput, ma_uint32 frameCount,
framesRead += framesToRead;
break;
}
LOG("ma_pcm_rb_commit_read failed: %s\n", ma_result_description(result));
ma_log_postf(log, MA_LOG_LEVEL_WARNING,
"ma_pcm_rb_commit_read failed: %s\n",
ma_result_description(result));
return COSMOAUDIO_ERROR;
}
}
return framesRead;
}
static int write_ring_buffer(ma_pcm_rb* rb, const float* pInput,
static int write_ring_buffer(ma_log* log, ma_pcm_rb* rb, const float* pInput,
ma_uint32 frameCount, ma_uint32 channels) {
ma_result result;
ma_uint32 framesWritten;
@ -92,8 +92,9 @@ static int write_ring_buffer(ma_pcm_rb* rb, const float* pInput,
void* pMappedBuffer;
result = ma_pcm_rb_acquire_write(rb, &framesToWrite, &pMappedBuffer);
if (result != MA_SUCCESS) {
LOG("ma_pcm_rb_acquire_write failed: %s\n",
ma_result_description(result));
ma_log_postf(log, MA_LOG_LEVEL_WARNING,
"ma_pcm_rb_acquire_write failed: %s\n",
ma_result_description(result));
return COSMOAUDIO_ERROR;
}
if (!framesToWrite)
@ -106,7 +107,9 @@ static int write_ring_buffer(ma_pcm_rb* rb, const float* pInput,
framesWritten += framesToWrite;
break;
}
LOG("ma_pcm_rb_commit_write failed: %s\n", ma_result_description(result));
ma_log_postf(log, MA_LOG_LEVEL_WARNING,
"ma_pcm_rb_commit_write failed: %s\n",
ma_result_description(result));
return COSMOAUDIO_ERROR;
}
}
@ -126,8 +129,8 @@ static void data_callback_f32(ma_device* pDevice, float* pOutput,
// —Quoth miniaudio documentation § 16.1. Low Level API
//
if (ca->isLeft) {
int framesCopied =
read_ring_buffer(&ca->output, pOutput, frameCount, ca->channels);
int framesCopied = read_ring_buffer(&ca->log, &ca->output, pOutput,
frameCount, ca->channels);
if (framesCopied < (int)frameCount)
ca->isLeft = 0;
} else {
@ -140,13 +143,14 @@ static void data_callback_f32(ma_device* pDevice, float* pOutput,
frameOffset = frameCount - availableFrames;
frameCount = availableFrames;
}
read_ring_buffer(&ca->output, pOutput + frameOffset * ca->channels,
frameCount, ca->channels);
read_ring_buffer(&ca->log, &ca->output,
pOutput + frameOffset * ca->channels, frameCount,
ca->channels);
ca->isLeft = 1;
}
}
if (ca->deviceType & kCosmoAudioDeviceTypeCapture)
write_ring_buffer(&ca->input, pInput, frameCount, ca->channels);
write_ring_buffer(&ca->log, &ca->input, pInput, frameCount, ca->channels);
ma_event_signal(&ca->event);
}
@ -211,6 +215,25 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
return COSMOAUDIO_ERROR;
}
// Create audio log.
if (ma_log_init(NULL, &ca->log) != MA_SUCCESS) {
ma_event_uninit(&ca->event);
free(ca);
return COSMOAUDIO_ERROR;
}
if (!options->debugLog)
ca->log.callbackCount = 0;
// Create audio context.
ma_context_config contextConfig = ma_context_config_init();
contextConfig.pLog = &ca->log;
if (ma_context_init(NULL, 0, &contextConfig, &ca->context) != MA_SUCCESS) {
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_ERROR;
}
// Initialize device.
ma_result result;
ma_device_config deviceConfig;
@ -227,9 +250,11 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
}
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = ca;
result = ma_device_init(NULL, &deviceConfig, &ca->device);
result = ma_device_init(&ca->context, &deviceConfig, &ca->device);
if (result != MA_SUCCESS) {
ma_context_uninit(&ca->context);
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_ERROR;
}
@ -248,7 +273,9 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
NULL, NULL, &ca->output);
if (result != MA_SUCCESS) {
ma_device_uninit(&ca->device);
ma_context_uninit(&ca->context);
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_ERROR;
}
@ -268,10 +295,12 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
result = ma_pcm_rb_init(ma_format_f32, ca->channels, ca->inputBufferFrames,
NULL, NULL, &ca->input);
if (result != MA_SUCCESS) {
ma_device_uninit(&ca->device);
if (ca->deviceType & kCosmoAudioDeviceTypePlayback)
ma_pcm_rb_uninit(&ca->output);
ma_device_uninit(&ca->device);
ma_context_uninit(&ca->context);
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_ERROR;
}
@ -280,12 +309,14 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
// Start audio playback.
if (ma_device_start(&ca->device) != MA_SUCCESS) {
ma_device_uninit(&ca->device);
if (ca->deviceType & kCosmoAudioDeviceTypePlayback)
ma_pcm_rb_uninit(&ca->output);
if (ca->deviceType & kCosmoAudioDeviceTypeCapture)
ma_pcm_rb_uninit(&ca->input);
ma_device_uninit(&ca->device);
ma_context_uninit(&ca->context);
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_ERROR;
}
@ -311,12 +342,14 @@ COSMOAUDIO_ABI int cosmoaudio_open( //
COSMOAUDIO_ABI int cosmoaudio_close(struct CosmoAudio* ca) {
if (!ca)
return COSMOAUDIO_EINVAL;
ma_device_uninit(&ca->device); // do this first
if (ca->deviceType & kCosmoAudioDeviceTypePlayback)
ma_pcm_rb_uninit(&ca->output);
if (ca->deviceType & kCosmoAudioDeviceTypeCapture)
ma_pcm_rb_uninit(&ca->input);
ma_device_uninit(&ca->device);
ma_context_uninit(&ca->context);
ma_event_uninit(&ca->event);
ma_log_uninit(&ca->log);
free(ca);
return COSMOAUDIO_SUCCESS;
}
@ -330,6 +363,12 @@ COSMOAUDIO_ABI int cosmoaudio_close(struct CosmoAudio* ca) {
* repeatedly called at a regular time interval. The caller should
* have its own sleep loop for this purpose.
*
* This function never blocks. Programs that don't have their own timer
* can use cosmoaudio_poll() to wait until audio may be written.
*
* For any given CosmoAudio object, it's assumed that only a single
* thread will call this function.
*
* @param ca is CosmoAudio object returned earlier by cosmoaudio_open()
* @param data is pointer to raw audio samples, expected to be in the range
* -1.0 to 1.0, where channels are interleaved
@ -351,17 +390,23 @@ COSMOAUDIO_ABI int cosmoaudio_write(struct CosmoAudio* ca, const float* data,
return 0;
if (!data)
return COSMOAUDIO_EINVAL;
return write_ring_buffer(&ca->output, data, frames, ca->channels);
return write_ring_buffer(&ca->log, &ca->output, data, frames, ca->channels);
}
/**
* Reads raw audio data from microphone.
*
* The data is read from a ring buffer in real-time, which is then
* played back very soon on the audio device. This has tolerence for
* a certain amount of buffering, but expects that this function is
* repeatedly called at a regular time interval. The caller should
* have its own sleep loop for this purpose.
* played back on the audio device. This has tolerence for a certain
* amount of buffering (based on the `bufferFrames` parameter passed to
* cosmoaudio_open(), which by default assumes this function will be
* called at at a regular time interval.
*
* This function never blocks. Programs that don't have their own timer
* can use cosmoaudio_poll() to wait until audio may be read.
*
* For any given CosmoAudio object, it's assumed that only a single
* thread will call this function.
*
* @param ca is CosmoAudio object returned earlier by cosmoaudio_open()
* @param data is pointer to raw audio samples, expected to be in the range
@ -382,11 +427,16 @@ COSMOAUDIO_ABI int cosmoaudio_read(struct CosmoAudio* ca, float* data,
return 0;
if (!data)
return COSMOAUDIO_EINVAL;
return read_ring_buffer(&ca->input, data, frames, ca->channels);
return read_ring_buffer(&ca->log, &ca->input, data, frames, ca->channels);
}
/**
* Waits for read and/or write to become possible.
* Waits until it's possible to read/write audio.
*
* This function is uninterruptible. All signals are masked throughout
* the duration of time this function may block, including cancelation
* signals, because this is not a cancelation point. Cosmopolitan Libc
* applies this masking in its dlopen wrapper.
*
* @param ca is CosmoAudio object returned earlier by cosmoaudio_open()
* @param in_out_readFrames if non-NULL specifies how many frames of
@ -447,6 +497,11 @@ COSMOAUDIO_ABI int cosmoaudio_poll(struct CosmoAudio* ca,
*
* This function is only valid to call in playback or duplex mode.
*
* This function is uninterruptible. All signals are masked throughout
* the duration of time this function may block, including cancelation
* signals, because this is not a cancelation point. Cosmopolitan Libc
* applies this masking in its dlopen wrapper.
*
* @param ca is CosmoAudio object returned earlier by cosmoaudio_open()
* @return 0 on success, or negative error code on failure
*/

Binary file not shown.

View file

@ -59,6 +59,9 @@ struct CosmoAudioOpenOptions {
// sample for each channel. Set to 0 for default. If this is less than
// the device period size times two, it'll be increased to that value.
int bufferFrames;
// Enables debug logging if non-zero.
int debugLog;
};
COSMOAUDIO_API int cosmoaudio_version(void) COSMOAUDIO_ABI;

View file

@ -53,7 +53,7 @@ int main() {
float t = (float)g++ / SAMPLING_RATE;
float s = sinf(2 * M_PIf * WAVE_INTERVAL * t);
for (int c = 0; c < CHANNELS; c++)
buf[f * CHANNELS + c] = s;
buf[f * CHANNELS + c] = s * .3f;
}
status = cosmoaudio_write(ca, buf, frames);
if (status != frames) {

View file

@ -90,6 +90,13 @@ const char *cosmoaudio_describe_open_options(
gotsome = true;
}
if (options->debugLog) {
if (gotsome)
append(", ");
append(".debugLog=%d", options->debugLog);
gotsome = true;
}
if (options->sizeofThis) {
if (gotsome)
append(", ");

80
examples/a440.c Normal file
View file

@ -0,0 +1,80 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include <cosmoaudio.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/**
* @fileoverview plays pure A.440 tone on speakers for 1 second
* @see https://en.wikipedia.org/wiki/A440_%28pitch_standard%29
*/
#define SAMPLING_RATE 44100
#define WAVE_INTERVAL 440
#define CHANNELS 2
#define LOUDNESS .3
#define DEBUG_LOG 1
int main() {
struct CosmoAudioOpenOptions cao = {0};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
cao.deviceType = kCosmoAudioDeviceTypePlayback;
cao.sampleRate = SAMPLING_RATE;
cao.debugLog = DEBUG_LOG;
cao.channels = CHANNELS;
int status;
struct CosmoAudio *ca;
status = cosmoaudio_open(&ca, &cao);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to open audio: %d\n", status);
return 1;
}
float buf[256 * CHANNELS];
for (int g = 0; g < SAMPLING_RATE;) {
int frames = 1;
status = cosmoaudio_poll(ca, NULL, &frames);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to poll output: %d\n", status);
return 2;
}
if (frames > 256)
frames = 256;
if (frames > SAMPLING_RATE - g)
frames = SAMPLING_RATE - g;
for (int f = 0; f < frames; ++f) {
float t = (float)g++ / SAMPLING_RATE;
float s = sinf(2 * M_PIf * WAVE_INTERVAL * t);
for (int c = 0; c < CHANNELS; c++)
buf[f * CHANNELS + c] = s * LOUDNESS;
}
status = cosmoaudio_write(ca, buf, frames);
if (status != frames) {
fprintf(stderr, "failed to write output: %d\n", status);
return 3;
}
}
status = cosmoaudio_flush(ca);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to flush output: %d\n", status);
return 4;
}
status = cosmoaudio_close(ca);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to close audio: %d\n", status);
return 5;
}
}

View file

@ -14,16 +14,16 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <unistd.h>
#include <cassert>
#include <cinttypes>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include "libc/assert.h"
// high performance high accuracy matrix multiplication in ansi c
#define MATH __target_clones("avx512f,fma")
#define MATH __target_clones("avx512f,fma,avx")
namespace {
namespace ansiBLAS {

View file

@ -7,7 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include <unistd.h>
// clears teletypewriter display
//

View file

@ -7,12 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
#include <cosmo.h>
/**
* @fileoverview How to print backtraces and cpu state on crash.

View file

@ -7,18 +7,11 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.h"
#include "libc/nt/enum/timezoneid.h"
#include "libc/nt/struct/timezoneinformation.h"
#include "libc/nt/time.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/thread/threads.h"
#include "libc/time.h"
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <time.h>
#include <unistd.h>
/**
* @fileoverview High performance ISO-8601 timestamp formatter.
@ -27,6 +20,8 @@
* Consider using something like this instead for your loggers.
*/
#define ABS(X) ((X) >= 0 ? (X) : -(X))
char *GetTimestamp(void) {
int x;
struct timespec ts;

View file

@ -7,11 +7,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/dlopen/dlfcn.h"
#include "libc/fmt/itoa.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/runtime.h"
#include <cosmo.h>
#include <dlfcn.h>
#include <stdlib.h>
/**
* @fileoverview cosmopolitan dynamic runtime linking demo

View file

@ -1,10 +1,21 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include <stdio.h>
#include <stdlib.h>
/**
* @fileoverview prints environment variables
*/
int main(int argc, char* argv[]) {
fprintf(stderr, "%s (%s)\n", argv[0], GetProgramExecutableName());
for (char** p = environ; *p; ++p) {
printf("%s\n", *p);
}
for (char** p = environ; *p; ++p)
puts(*p);
return 0;
}

View file

@ -23,8 +23,6 @@
#include <sys/auxv.h>
#include <sys/socket.h>
#include <time.h>
#include "libc/mem/leaks.h"
#include "libc/runtime/runtime.h"
/**
* @fileoverview greenbean lightweight threaded web server

View file

@ -36,14 +36,10 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time.h"
#include "third_party/zlib/zlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
// clang-format off
#define DICT "usr/share/dict/hangman"

View file

@ -7,9 +7,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/stdio/stdio.h"
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}

View file

@ -7,7 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include <unistd.h>
int main() {
write(1, "hello world\n", 12);

View file

@ -1,15 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/time.h"
int main(int argc, char *argv[]) {
int64_t t = 0;
localtime(&t);
}

133
examples/loudness.c Normal file
View file

@ -0,0 +1,133 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include <cosmoaudio.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/**
* @fileoverview prints ascii meter of microphone loudness
*
* 0. -60 dB is nearly silent, barely audible, even in a quiet room
* 1. -50 dB is very quiet background sounds
* 2. -40 dB is quiet ambient noise
* 3. -30 dB is clear but soft sounds
* 4. -20 dB is moderate volume, comfortable for extended listening
* 5. -10 dB is fairly loud, but not uncomfortable
* 6. -6 dB is loud, but not at full volume
* 7. -3 dB is very loud, approaching system limits
* 8. -1 dB is extremely loud, just below maximum
* 9. -0 dB is maximum volume without distortion
*/
#define SAMPLING_RATE 44100
#define ASCII_METER_WIDTH 20
#define FRAMES_PER_SECOND 30
#define MIN_DECIBEL -60
#define MAX_DECIBEL 0
#define DEBUG_LOG 1
sig_atomic_t g_done;
void on_signal(int sig) {
g_done = 1;
}
// computes root of mean squares
double rms(float* p, int n) {
double s = 0;
for (int i = 0; i < n; ++i)
s += p[i] * p[i];
return sqrt(s / n);
}
// converts rms to decibel
double rms_to_db(double rms) {
double db = 20 * log10(rms);
db = fmin(db, MAX_DECIBEL);
db = fmax(db, MIN_DECIBEL);
return db;
}
int main() {
signal(SIGINT, on_signal);
// how many samples should we process at once
int chunkFrames = SAMPLING_RATE / FRAMES_PER_SECOND;
// configure cosmo audio
struct CosmoAudioOpenOptions cao = {0};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
cao.deviceType = kCosmoAudioDeviceTypeCapture;
cao.sampleRate = SAMPLING_RATE;
cao.bufferFrames = chunkFrames * 2;
cao.debugLog = DEBUG_LOG;
cao.channels = 1;
// connect to microphone
int status;
struct CosmoAudio* ca;
status = cosmoaudio_open(&ca, &cao);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to open microphone: %d\n", status);
return 1;
}
// allocate memory for audio work area
float* chunk = malloc(chunkFrames * sizeof(float));
if (!chunk) {
fprintf(stderr, "out of memory\n");
return 1;
}
while (!g_done) {
// wait for full chunk of audio to become available
int need_in_frames = chunkFrames;
status = cosmoaudio_poll(ca, &need_in_frames, NULL);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to poll microphone: %d\n", status);
return 2;
}
// read audio frames from microphone ring buffer
status = cosmoaudio_read(ca, chunk, chunkFrames);
if (status != chunkFrames) {
fprintf(stderr, "failed to read microphone: %d\n", status);
return 3;
}
// convert audio chunk to to ascii meter
char s[ASCII_METER_WIDTH + 1] = {0};
double db = rms_to_db(rms(chunk, chunkFrames));
double db_range = MAX_DECIBEL - MIN_DECIBEL;
int filled_length = (db - MIN_DECIBEL) / db_range * ASCII_METER_WIDTH;
for (int i = 0; i < ASCII_METER_WIDTH; ++i) {
if (i < filled_length) {
s[i] = '=';
} else {
s[i] = ' ';
}
}
printf("\r%s| %+6.2f dB", s, db);
fflush(stdout);
}
printf("\n");
// clean up resources
status = cosmoaudio_close(ca);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to close microphone: %d\n", status);
return 5;
}
free(chunk);
}

View file

@ -1,83 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/log/check.h"
#include "libc/mem/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/s.h"
#include "libc/x/xasprintf.h"
struct stat st;
const char *TypeToString(uint8_t type) {
switch (type) {
case DT_UNKNOWN:
return "DT_UNKNOWN";
case DT_FIFO:
return "DT_FIFO";
case DT_CHR:
return "DT_CHR";
case DT_DIR:
return "DT_DIR";
case DT_BLK:
return "DT_BLK";
case DT_REG:
return "DT_REG";
case DT_LNK:
return "DT_LNK";
case DT_SOCK:
return "DT_SOCK";
default:
return "UNKNOWN";
}
}
void List(const char *path) {
DIR *d;
struct dirent *e;
const char *vpath;
if (strcmp(path, ".") == 0) {
vpath = "";
} else if (!endswith(path, "/")) {
vpath = gc(xasprintf("%s/", path));
} else {
vpath = path;
}
if (stat(path, &st) != -1) {
if (S_ISDIR(st.st_mode)) {
CHECK((d = opendir(path)));
while ((e = readdir(d))) {
printf("0x%016x 0x%016x %-10s %s%s\n", e->d_ino, e->d_off,
TypeToString(e->d_type), vpath, e->d_name);
}
closedir(d);
} else {
printf("%s\n", path);
}
} else {
fprintf(stderr, "not found: %s\n", path);
}
}
int main(int argc, char *argv[]) {
int i;
if (argc == 1) {
List(".");
} else {
for (i = 1; i < argc; ++i) {
List(argv[i]);
}
}
return 0;
}

View file

@ -7,25 +7,16 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/linger.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/shut.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/musl/netdb.h"
#include <cosmo.h>
#include <getopt.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
// clang-format off
/**
* @fileoverview netcat clone
@ -36,12 +27,14 @@
* Here's an example usage:
*
* make -j8 o//examples/nc.com
* printf 'GET /\r\nHost: justine.lol\r\n\r\n' | o//examples/nc.com
* justine.lol 80
* printf 'GET /\r\nHost: justine.lol\r\n\r\n' | o//examples/nc.com justine.lol 80
*
* Once upon time we called this command "telnet"
* Once upon time we called this command basically "telnet"
*/
#define ARRAYLEN(A) \
((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))
int main(int argc, char *argv[]) {
ssize_t rc;
size_t i, got;

View file

@ -1,3 +1,12 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include <stdio.h>
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \

View file

@ -7,10 +7,10 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/fmt/itoa.h"
#include "libc/str/str.h"
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
volatile int g_sig;
@ -21,16 +21,13 @@ void OnSig(int sig) {
int main(int argc, char *argv[]) {
// listen for all signals
for (int sig = 1; sig <= NSIG; ++sig) {
for (int sig = 1; sig <= NSIG; ++sig)
signal(sig, OnSig);
}
// wait for a signal
char ibuf[12];
FormatInt32(ibuf, getpid());
tinyprint(2, "waiting for signal to be sent to ", ibuf, "\n", NULL);
printf("waiting for signal to be sent to my pid %d\n", getpid());
pause();
// report the signal
tinyprint(1, "got ", strsignal(g_sig), "\n", NULL);
printf("got %s\n", strsignal(g_sig));
}

View file

@ -32,12 +32,9 @@
* . Formatted as per Cosmopolitan's standards.
*/
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { PICOL_OK, PICOL_ERR, PICOL_RETURN, PICOL_BREAK, PICOL_CONTINUE };
enum { PT_ESC, PT_STR, PT_CMD, PT_VAR, PT_SEP, PT_EOL, PT_EOF };

View file

@ -7,7 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/runtime/runtime.h"
#include <cosmo.h>
int main() {
__printargs("");

View file

@ -13,11 +13,11 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "libc/ctype.h"
/**
* @fileoverview Roman Transliteration, e.g.

View file

@ -29,29 +29,20 @@
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bswap.h"
#include "libc/log/bsd.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/select.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time.h"
#include "third_party/getopt/getopt.internal.h"
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <pty.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
// clang-format off
/**

View file

@ -7,9 +7,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include <cosmo.h>
#include <stdlib.h>
/**
* @fileoverview Prints sequence of numbers.

View file

@ -7,12 +7,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/ucontext.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
/**
* @fileoverview swapcontext() and makecontext() example
@ -33,18 +30,16 @@ static ucontext_t uctx_func2;
static void func1(void) {
say("func1: started\n");
say("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
if (swapcontext(&uctx_func1, &uctx_func2) == -1) {
if (swapcontext(&uctx_func1, &uctx_func2) == -1)
handle_error("swapcontext");
}
say("func1: returning\n");
}
static void func2(void) {
say("func2: started\n");
say("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
if (swapcontext(&uctx_func2, &uctx_func1) == -1) {
if (swapcontext(&uctx_func2, &uctx_func1) == -1)
handle_error("swapcontext");
}
say("func2: returning\n");
}
@ -52,17 +47,15 @@ int main(int argc, char *argv[]) {
char func1_stack[8192];
char func2_stack[8192];
if (getcontext(&uctx_func1) == -1) {
if (getcontext(&uctx_func1) == -1)
handle_error("getcontext");
}
uctx_func1.uc_stack.ss_sp = func1_stack;
uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
uctx_func1.uc_link = &uctx_main;
makecontext(&uctx_func1, func1, 0);
if (getcontext(&uctx_func2) == -1) {
if (getcontext(&uctx_func2) == -1)
handle_error("getcontext");
}
uctx_func2.uc_stack.ss_sp = func2_stack;
uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
/* Successor context is f1(), unless argc > 1 */
@ -70,9 +63,8 @@ int main(int argc, char *argv[]) {
makecontext(&uctx_func2, func2, 0);
say("main: swapcontext(&uctx_main, &uctx_func2)\n");
if (swapcontext(&uctx_main, &uctx_func2) == -1) {
if (swapcontext(&uctx_main, &uctx_func2) == -1)
handle_error("swapcontext");
}
say("main: exiting\n");
exit(EXIT_SUCCESS);

View file

@ -7,17 +7,15 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time.h"
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
/**
* @fileoverview interval timer tutorial
*/
volatile bool gotalrm;

View file

@ -7,24 +7,20 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/weirdtypes.h"
#include "libc/mem/mem.h"
#include "libc/proc/posix_spawn.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include <spawn.h>
#include <stdalign.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#define ITERATIONS 10
_Alignas(128) int a;
_Alignas(128) int b;
_Alignas(128) atomic_int lock;
alignas(128) int a;
alignas(128) int b;
alignas(128) atomic_int lock;
static struct timespec SubtractTime(struct timespec a, struct timespec b) {
a.tv_sec -= b.tv_sec;

View file

@ -7,19 +7,12 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/struct/stat.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/time.h"
#include <assert.h>
#include <cosmo.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
/**
* @fileoverview File metadata viewer.
@ -72,9 +65,15 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
printf("\n%s:", pathname);
if (numeric) {
fd = atoi(pathname);
CHECK_NE(-1, fstat(fd, st), "fd=%d", fd);
if (fstat(fd, st)) {
perror(pathname);
exit(1);
}
} else {
CHECK_NE(-1, stat(pathname, st), "pathname=%s", pathname);
if (stat(pathname, st)) {
perror(pathname);
exit(1);
}
}
printf("\n"
"%-32s%,ld\n"

View file

@ -7,18 +7,19 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/struct/statfs.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/nt/enum/statfs.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/st.h"
#include <cosmo.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/vfs.h>
dontinline void ShowIt(const char *path) {
void ShowIt(const char *path) {
char ibuf[21];
struct statfs sf = {0};
CHECK_NE(-1, statfs(path, &sf));
if (statfs(path, &sf)) {
perror(path);
exit(1);
}
printf("filesystem %s\n", path);
printf("f_type = %#x (%s)\n", sf.f_type, sf.f_fstypename);

View file

@ -1,36 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/stdio/append.h"
#include "libc/str/str.h"
/**
* @fileoverview Fast Growable Strings Tutorial
*/
int main(int argc, char *argv[]) {
char *b = 0;
appendf(&b, "hello "); // guarantees nul terminator
CHECK_EQ(6, strlen(b));
CHECK_EQ(6, appendz(b).i);
appendf(&b, " world\n");
CHECK_EQ(13, strlen(b));
CHECK_EQ(13, appendz(b).i);
appendd(&b, "\0", 1); // supports binary
CHECK_EQ(13, strlen(b));
CHECK_EQ(14, appendz(b).i);
appendf(&b, "%d arg%s\n", argc, argc == 1 ? "" : "s");
appendf(&b, "%s\n", "have a nice day");
write(1, b, appendz(b).i);
free(b);
return 0;
}

View file

@ -7,8 +7,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/runtime/sysconf.h"
#include "libc/stdio/stdio.h"
#include <stdio.h>
#include <unistd.h>
#define SYSCONF(NAME) printf("%-24s %,ld\n", #NAME, sysconf(NAME))

View file

@ -7,19 +7,19 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/timespec.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/log/check.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/clock.h"
#include <cosmo.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
int main(int argc, char *argv[]) {
int64_t x;
char ibuf[21];
struct sysinfo si;
CHECK_NE(-1, sysinfo(&si));
if (sysinfo(&si)) {
perror("sysinfo");
exit(1);
}
printf("%-16s", "uptime");
x = si.uptime / (24 * 60 * 60);

View file

@ -7,9 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include <stdlib.h>
/**
* @fileoverview Cosmopolitan Command Interpreter Demo

View file

@ -1,4 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_SYS_VFS_H_
#define COSMOPOLITAN_LIBC_ISYSTEM_SYS_VFS_H_
#include "libc/calls/struct/statfs.h"
#include "libc/sysv/consts/st.h"
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_SYS_VFS_H_ */