{"id":37227323,"url":"https://github.com/vampirefrog/muxaudio","last_synced_at":"2026-01-24T01:04:16.782Z","repository":{"id":331582805,"uuid":"1129416480","full_name":"vampirefrog/muxaudio","owner":"vampirefrog","description":"Audio encoding (mp3, ogg, vorbis, opus, flac) and multiplexing library with support for a side channel for data, for speech events (visemes, phonemes)","archived":false,"fork":false,"pushed_at":"2026-01-10T17:57:46.000Z","size":106,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-11T01:56:02.543Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vampirefrog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-07T04:13:15.000Z","updated_at":"2026-01-10T17:57:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vampirefrog/muxaudio","commit_stats":null,"previous_names":["vampirefrog/muxaudio"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vampirefrog/muxaudio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vampirefrog%2Fmuxaudio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vampirefrog%2Fmuxaudio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vampirefrog%2Fmuxaudio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vampirefrog%2Fmuxaudio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vampirefrog","download_url":"https://codeload.github.com/vampirefrog/muxaudio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vampirefrog%2Fmuxaudio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28442267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"online","status_checked_at":"2026-01-15T02:00:08.019Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-15T03:20:22.460Z","updated_at":"2026-01-15T03:20:23.245Z","avatar_url":"https://github.com/vampirefrog.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Native Build](https://github.com/vampirefrog/muxaudio/actions/workflows/build-native.yml/badge.svg)](https://github.com/vampirefrog/muxaudio/actions/workflows/build-native.yml)\n[![Windows Build](https://github.com/vampirefrog/muxaudio/actions/workflows/build-windows.yml/badge.svg)](https://github.com/vampirefrog/muxaudio/actions/workflows/build-windows.yml)\n[![WASM Build](https://github.com/vampirefrog/muxaudio/actions/workflows/build-wasm.yml/badge.svg)](https://github.com/vampirefrog/muxaudio/actions/workflows/build-wasm.yml)\n[![Test Matrix](https://github.com/vampirefrog/muxaudio/actions/workflows/test-matrix.yml/badge.svg)](https://github.com/vampirefrog/muxaudio/actions/workflows/test-matrix.yml)\n[![Release](https://github.com/vampirefrog/muxaudio/actions/workflows/release.yml/badge.svg)](https://github.com/vampirefrog/muxaudio/actions/workflows/release.yml)\n\n# muxaudio\n\nA lightweight, efficient audio codec multiplexing library with support for multiple formats and side channel data.\n\n## Features\n\n- **6 Audio Codecs**: PCM, MP3, Vorbis, Opus, FLAC, AAC\n- **Lossless \u0026 Lossy**: Choose between quality and compression\n- **Side Channel Multiplexing**: Embed metadata alongside audio\n- **Simple API**: Clean C99 interface\n- **Command-Line Tools**: Encode/decode from stdin/stdout\n- **Zero Dependencies**: Only codec libraries needed\n- **Frame-Level Streaming**: Low latency, real-time capable\n\n## Supported Codecs\n\n| Codec  | Type     | Use Case               | Dependencies        | Status |\n|--------|----------|------------------------|---------------------|--------|\n| PCM    | Lossless | Uncompressed           | None                | ✅     |\n| FLAC   | Lossless | Archive, mastering     | libFLAC, libogg     | ✅     |\n| Opus   | Lossy    | VoIP, low latency      | libopus, libogg     | ✅     |\n| Vorbis | Lossy    | Music, streaming       | libvorbis, libogg   | ✅     |\n| MP3    | Lossy    | Wide compatibility     | libmp3lame, libmpg123 | ✅   |\n| AAC    | Lossy    | High quality, mobile   | libfdk-aac          | ✅     |\n\n## Quick Start\n\n### Installation\n\n```bash\n# Install dependencies (Debian/Ubuntu)\nsudo apt-get install libogg-dev libvorbis-dev libopus-dev \\\n                     libflac-dev libmp3lame-dev libmpg123-dev \\\n                     libfdk-aac-dev\n\n# Build\nmkdir build \u0026\u0026 cd build\ncmake ..\nmake\nsudo make install\n```\n\n### Basic Usage\n\n```c\n#include \u003cmux.h\u003e\n\n// Encode audio with FLAC\nstruct mux_encoder *enc = mux_encoder_new(MUX_CODEC_FLAC, 44100, 2, NULL, 0);\nmux_encoder_encode(enc, pcm_data, pcm_size, \u0026consumed, MUX_STREAM_AUDIO);\nmux_encoder_finalize(enc);\nmux_encoder_read(enc, output, sizeof(output), \u0026written);\nmux_encoder_destroy(enc);\n\n// Decode\nstruct mux_decoder *dec = mux_decoder_new(MUX_CODEC_FLAC, NULL, 0);\nmux_decoder_decode(dec, input, input_size, \u0026consumed);\nmux_decoder_finalize(dec);\nmux_decoder_read(dec, pcm_out, sizeof(pcm_out), \u0026written, \u0026stream_type);\nmux_decoder_destroy(dec);\n```\n\n---\n\n## API Reference\n\n### Types\n\n#### `enum mux_codec_type`\nSupported codec types.\n\n```c\nenum mux_codec_type {\n    MUX_CODEC_PCM,     // Uncompressed PCM\n    MUX_CODEC_OPUS,    // Opus codec\n    MUX_CODEC_VORBIS,  // Vorbis codec\n    MUX_CODEC_FLAC,    // FLAC lossless\n    MUX_CODEC_MP3,     // MP3 (MPEG-1 Layer III)\n    MUX_CODEC_AAC,     // AAC (Advanced Audio Coding)\n    MUX_CODEC_MAX\n};\n```\n\n#### `struct mux_param`\nCodec configuration parameter.\n\n```c\nstruct mux_param {\n    const char *name;          // Parameter name (e.g., \"bitrate\")\n    union {\n        int i;                 // Integer value\n        float f;               // Float value\n    } value;\n};\n```\n\n#### `struct mux_error_info`\nDetailed error information.\n\n```c\nstruct mux_error_info {\n    int code;                  // Error code (MUX_OK, MUX_ERROR_*, etc.)\n    const char *message;       // Human-readable message\n    const char *source;        // Source component (e.g., \"libFLAC\")\n    int source_code;           // Source-specific error code\n    const char *source_msg;    // Source error message\n};\n```\n\n### Constants\n\n```c\n#define MUX_STREAM_AUDIO        0  // Audio stream type\n#define MUX_STREAM_SIDE_CHANNEL 1  // Side channel (metadata) stream type\n```\n\n### Error Codes\n\n```c\n#define MUX_OK            0   // Success\n#define MUX_ERROR_NOMEM   1   // Out of memory\n#define MUX_ERROR_INVAL   2   // Invalid argument\n#define MUX_ERROR_INIT    3   // Initialization failed\n#define MUX_ERROR_ENCODE  4   // Encoding error\n#define MUX_ERROR_DECODE  5   // Decoding error\n#define MUX_ERROR_FORMAT  6   // Format error\n#define MUX_ERROR_NOCODEC 7   // Codec not available\n#define MUX_ERROR_AGAIN   8   // Try again (need more data)\n```\n\n---\n\n## Core API Functions\n\n### Codec Discovery\n\n#### `mux_list_codecs`\nList all available codecs.\n\n```c\nint mux_list_codecs(const struct mux_codec_info **codecs, int *count);\n```\n\n**Returns**: `MUX_OK` on success\n**Parameters**:\n- `codecs`: Pointer to receive codec info array\n- `count`: Pointer to receive number of codecs\n\n**Example**:\n```c\nconst struct mux_codec_info *codecs;\nint count;\nmux_list_codecs(\u0026codecs, \u0026count);\nfor (int i = 0; i \u003c count; i++) {\n    printf(\"%s: %s\\n\", codecs[i].name, codecs[i].description);\n}\n```\n\n#### `mux_codec_from_name`\nConvert codec name to type.\n\n```c\nint mux_codec_from_name(const char *name, enum mux_codec_type *codec);\n```\n\n**Returns**: `MUX_OK` if found, `MUX_ERROR_INVAL` if not found\n**Parameters**:\n- `name`: Codec name (\"pcm\", \"mp3\", \"vorbis\", \"opus\", \"flac\", \"aac\")\n- `codec`: Pointer to receive codec type\n\n**Example**:\n```c\nenum mux_codec_type codec;\nif (mux_codec_from_name(\"flac\", \u0026codec) == MUX_OK) {\n    // Use codec\n}\n```\n\n#### `mux_codec_to_name`\nConvert codec type to name.\n\n```c\nconst char *mux_codec_to_name(enum mux_codec_type codec);\n```\n\n**Returns**: Codec name string or `NULL` if invalid\n**Example**:\n```c\nconst char *name = mux_codec_to_name(MUX_CODEC_FLAC);  // Returns \"flac\"\n```\n\n### Parameter Introspection\n\n#### `mux_get_encoder_params`\nGet available encoder parameters for a codec.\n\n```c\nint mux_get_encoder_params(enum mux_codec_type codec_type,\n                           const struct mux_param_desc **params,\n                           int *count);\n```\n\n**Returns**: `MUX_OK` on success\n**Example**:\n```c\nconst struct mux_param_desc *params;\nint count;\nmux_get_encoder_params(MUX_CODEC_OPUS, \u0026params, \u0026count);\nfor (int i = 0; i \u003c count; i++) {\n    printf(\"%s: %s (default: %d)\\n\",\n           params[i].name, params[i].description, params[i].range.i.def);\n}\n```\n\n#### `mux_get_decoder_params`\nGet available decoder parameters for a codec.\n\n```c\nint mux_get_decoder_params(enum mux_codec_type codec_type,\n                           const struct mux_param_desc **params,\n                           int *count);\n```\n\n#### `mux_get_supported_sample_rates`\nQuery supported sample rates for a codec.\n\n```c\nint mux_get_supported_sample_rates(enum mux_codec_type codec_type,\n                                   struct mux_sample_rate_list *list);\n```\n\n**Returns**: `MUX_OK` on success\n**Example**:\n```c\nstruct mux_sample_rate_list list;\nmux_get_supported_sample_rates(MUX_CODEC_OPUS, \u0026list);\nif (list.is_range) {\n    printf(\"Supports %d-%d Hz\\n\", list.rates[0], list.rates[1]);\n} else {\n    for (int i = 0; i \u003c list.count; i++) {\n        printf(\"Supports %d Hz\\n\", list.rates[i]);\n    }\n}\n```\n\n---\n\n## Encoder API\n\n### Dynamic Allocation\n\n#### `mux_encoder_new`\nCreate a new encoder.\n\n```c\nstruct mux_encoder *mux_encoder_new(enum mux_codec_type codec_type,\n                                    int sample_rate,\n                                    int num_channels,\n                                    const struct mux_param *params,\n                                    int num_params);\n```\n\n**Returns**: Encoder instance or `NULL` on error\n**Parameters**:\n- `codec_type`: Codec to use\n- `sample_rate`: Sample rate in Hz (e.g., 44100)\n- `num_channels`: Number of channels (1=mono, 2=stereo)\n- `params`: Optional parameters array (can be `NULL`)\n- `num_params`: Number of parameters (0 if `params` is `NULL`)\n\n**Example**:\n```c\n// FLAC with compression level 8\nstruct mux_param params[] = {\n    { .name = \"compression\", .value.i = 8 }\n};\nstruct mux_encoder *enc = mux_encoder_new(MUX_CODEC_FLAC, 44100, 2, params, 1);\n```\n\n#### `mux_encoder_destroy`\nDestroy an encoder.\n\n```c\nvoid mux_encoder_destroy(struct mux_encoder *enc);\n```\n\n### Static Allocation\n\n#### `mux_encoder_init`\nInitialize a statically allocated encoder.\n\n```c\nint mux_encoder_init(struct mux_encoder *enc,\n                     enum mux_codec_type codec_type,\n                     int sample_rate,\n                     int num_channels,\n                     const struct mux_param *params,\n                     int num_params);\n```\n\n#### `mux_encoder_deinit`\nDeinitialize an encoder.\n\n```c\nvoid mux_encoder_deinit(struct mux_encoder *enc);\n```\n\n### Encoding Operations\n\n#### `mux_encoder_encode`\nEncode audio or side channel data.\n\n```c\nint mux_encoder_encode(struct mux_encoder *enc,\n                       const void *input,\n                       size_t input_size,\n                       size_t *input_consumed,\n                       int stream_type);\n```\n\n**Returns**: `MUX_OK` on success, error code on failure\n**Parameters**:\n- `enc`: Encoder instance\n- `input`: Input data (PCM audio as int16_t for audio, any data for side channel)\n- `input_size`: Size of input in bytes\n- `input_consumed`: Pointer to receive bytes consumed\n- `stream_type`: `MUX_STREAM_AUDIO` or `MUX_STREAM_SIDE_CHANNEL`\n\n**Example**:\n```c\nint16_t audio[8192];\nsize_t consumed;\nint ret = mux_encoder_encode(enc, audio, sizeof(audio), \u0026consumed, MUX_STREAM_AUDIO);\n```\n\n#### `mux_encoder_read`\nRead encoded/multiplexed output.\n\n```c\nint mux_encoder_read(struct mux_encoder *enc,\n                     void *output,\n                     size_t output_size,\n                     size_t *output_written);\n```\n\n**Returns**: `MUX_OK` on success, `MUX_ERROR_AGAIN` if no data available\n**Example**:\n```c\nuint8_t buffer[4096];\nsize_t written;\nwhile (mux_encoder_read(enc, buffer, sizeof(buffer), \u0026written) == MUX_OK) {\n    // Write buffer to file/stream\n}\n```\n\n#### `mux_encoder_finalize`\nFlush any buffered data.\n\n```c\nint mux_encoder_finalize(struct mux_encoder *enc);\n```\n\n**Note**: Call before destroying encoder or when done encoding.\n\n#### `mux_encoder_get_error`\nGet detailed error information.\n\n```c\nconst struct mux_error_info *mux_encoder_get_error(struct mux_encoder *enc);\n```\n\n**Example**:\n```c\nif (mux_encoder_encode(enc, data, size, \u0026consumed, MUX_STREAM_AUDIO) != MUX_OK) {\n    const struct mux_error_info *err = mux_encoder_get_error(enc);\n    fprintf(stderr, \"Error: %s\\n\", err-\u003emessage);\n}\n```\n\n---\n\n## Decoder API\n\n### Dynamic Allocation\n\n#### `mux_decoder_new`\nCreate a new decoder.\n\n```c\nstruct mux_decoder *mux_decoder_new(enum mux_codec_type codec_type,\n                                    const struct mux_param *params,\n                                    int num_params);\n```\n\n**Returns**: Decoder instance or `NULL` on error\n**Example**:\n```c\nstruct mux_decoder *dec = mux_decoder_new(MUX_CODEC_OPUS, NULL, 0);\n```\n\n#### `mux_decoder_destroy`\nDestroy a decoder.\n\n```c\nvoid mux_decoder_destroy(struct mux_decoder *dec);\n```\n\n### Static Allocation\n\n#### `mux_decoder_init`\nInitialize a statically allocated decoder.\n\n```c\nint mux_decoder_init(struct mux_decoder *dec,\n                     enum mux_codec_type codec_type,\n                     const struct mux_param *params,\n                     int num_params);\n```\n\n#### `mux_decoder_deinit`\nDeinitialize a decoder.\n\n```c\nvoid mux_decoder_deinit(struct mux_decoder *dec);\n```\n\n### Decoding Operations\n\n#### `mux_decoder_decode`\nDecode multiplexed input.\n\n```c\nint mux_decoder_decode(struct mux_decoder *dec,\n                       const void *input,\n                       size_t input_size,\n                       size_t *input_consumed);\n```\n\n**Returns**: `MUX_OK` on success\n**Parameters**:\n- `dec`: Decoder instance\n- `input`: Encoded/multiplexed input data\n- `input_size`: Size of input in bytes\n- `input_consumed`: Pointer to receive bytes consumed\n\n**Example**:\n```c\nuint8_t encoded[4096];\nsize_t consumed;\nmux_decoder_decode(dec, encoded, sizeof(encoded), \u0026consumed);\n```\n\n#### `mux_decoder_read`\nRead decoded audio or side channel data.\n\n```c\nint mux_decoder_read(struct mux_decoder *dec,\n                     void *output,\n                     size_t output_size,\n                     size_t *output_written,\n                     int *stream_type);\n```\n\n**Returns**: `MUX_OK` on success, `MUX_ERROR_AGAIN` if no data available\n**Parameters**:\n- `stream_type`: Receives `MUX_STREAM_AUDIO` or `MUX_STREAM_SIDE_CHANNEL`\n\n**Example**:\n```c\nint16_t pcm[8192];\nsize_t written;\nint stream_type;\nwhile (mux_decoder_read(dec, pcm, sizeof(pcm), \u0026written, \u0026stream_type) == MUX_OK) {\n    if (stream_type == MUX_STREAM_AUDIO) {\n        // Process audio\n    } else {\n        // Process side channel data\n    }\n}\n```\n\n#### `mux_decoder_finalize`\nFlush any buffered decoded data.\n\n```c\nint mux_decoder_finalize(struct mux_decoder *dec);\n```\n\n#### `mux_decoder_get_error`\nGet detailed error information.\n\n```c\nconst struct mux_error_info *mux_decoder_get_error(struct mux_decoder *dec);\n```\n\n---\n\n## Command-Line Tools\n\n### mux\n\nEncode raw PCM audio from stdin with optional side channel data from fd 3.\n\n```bash\nmux [options] \u003c input.raw \u003e output.mux\n```\n\n**Options**:\n- `-c, --codec CODEC` - Codec: pcm, mp3, vorbis, opus, flac, aac (default: flac)\n- `-r, --rate RATE` - Sample rate in Hz (default: 44100)\n- `-n, --channels NUM` - Number of channels (default: 2)\n- `-b, --bitrate KBPS` - Bitrate for lossy codecs in kbps (default: 128)\n- `-l, --level LEVEL` - Compression level 0-8 for FLAC (default: 5)\n- `-h, --help` - Show help\n\n**Examples**:\n```bash\n# FLAC encoding\ncat audio.raw | mux -c flac -r 44100 -n 2 \u003e output.mux\n\n# Opus with custom bitrate\nmux -c opus -b 96 \u003c input.raw \u003e output.mux\n\n# With side channel metadata\nmux -c flac \u003c audio.raw 3\u003c metadata.txt \u003e output.mux\n```\n\n### demux\n\nDecode multiplexed stream from stdin to PCM audio and side channel data.\n\n```bash\ndemux [options] \u003c input.mux \u003e output.raw\n```\n\n**Options**:\n- `-c, --codec CODEC` - Codec: pcm, mp3, vorbis, opus, flac, aac (default: flac)\n- `-v, --verbose` - Print stream information to stderr\n- `-h, --help` - Show help\n\n**Examples**:\n```bash\n# Decode to PCM\ndemux -c flac \u003c input.mux \u003e output.raw\n\n# Decode with side channel extraction\ndemux -c opus \u003c input.mux \u003e audio.raw 3\u003e metadata.txt\n\n# Verbose output\ndemux -c flac -v \u003c input.mux \u003e output.raw\n```\n\n---\n\n## Complete Examples\n\n### Example 1: FLAC Lossless Compression\n\n```c\n#include \u003cmux.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cstdint.h\u003e\n\nint main(void) {\n    // Allocate test audio\n    int16_t audio[88200];  // 1 second stereo at 44100 Hz\n\n    // Generate 440 Hz sine wave\n    for (int i = 0; i \u003c 44100; i++) {\n        int16_t sample = 10000 * sin(2 * M_PI * 440 * i / 44100);\n        audio[i * 2] = sample;     // Left\n        audio[i * 2 + 1] = sample; // Right\n    }\n\n    // Create FLAC encoder with max compression\n    struct mux_param params[] = {\n        { .name = \"compression\", .value.i = 8 }\n    };\n    struct mux_encoder *enc = mux_encoder_new(MUX_CODEC_FLAC, 44100, 2, params, 1);\n\n    // Encode\n    size_t consumed;\n    mux_encoder_encode(enc, audio, sizeof(audio), \u0026consumed, MUX_STREAM_AUDIO);\n    mux_encoder_finalize(enc);\n\n    // Read output\n    uint8_t output[65536];\n    size_t total = 0;\n    size_t written;\n    while (mux_encoder_read(enc, output + total, sizeof(output) - total, \u0026written) == MUX_OK) {\n        total += written;\n    }\n\n    printf(\"Compressed %zu bytes to %zu bytes (%.1f%%)\\n\",\n           sizeof(audio), total, total * 100.0 / sizeof(audio));\n\n    mux_encoder_destroy(enc);\n\n    // Decode back\n    struct mux_decoder *dec = mux_decoder_new(MUX_CODEC_FLAC, NULL, 0);\n    mux_decoder_decode(dec, output, total, \u0026consumed);\n    mux_decoder_finalize(dec);\n\n    int16_t decoded[88200];\n    int stream_type;\n    size_t decoded_size = 0;\n    while (mux_decoder_read(dec, decoded + decoded_size / sizeof(int16_t),\n                           sizeof(decoded) - decoded_size,\n                           \u0026written, \u0026stream_type) == MUX_OK) {\n        decoded_size += written;\n    }\n\n    // Verify lossless\n    if (memcmp(audio, decoded, sizeof(audio)) == 0) {\n        printf(\"Perfect lossless compression verified!\\n\");\n    }\n\n    mux_decoder_destroy(dec);\n    return 0;\n}\n```\n\n### Example 2: Opus with Side Channel Metadata\n\n```c\n#include \u003cmux.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cstdint.h\u003e\n#include \u003cstring.h\u003e\n\nint main(void) {\n    // Create Opus encoder (48 kHz required for Opus)\n    struct mux_param params[] = {\n        { .name = \"bitrate\", .value.i = 64 }  // 64 kbps\n    };\n    struct mux_encoder *enc = mux_encoder_new(MUX_CODEC_OPUS, 48000, 2, params, 1);\n\n    // Encode audio chunks with timestamp metadata\n    for (int chunk = 0; chunk \u003c 10; chunk++) {\n        // Generate 20ms of audio (960 samples at 48kHz)\n        int16_t audio[960 * 2];\n        // ... fill with audio data ...\n\n        size_t consumed;\n        mux_encoder_encode(enc, audio, sizeof(audio), \u0026consumed, MUX_STREAM_AUDIO);\n\n        // Add timestamp metadata for this chunk\n        char metadata[64];\n        snprintf(metadata, sizeof(metadata), \"timestamp=%d\", chunk * 20);\n        mux_encoder_encode(enc, metadata, strlen(metadata) + 1,\n                          \u0026consumed, MUX_STREAM_SIDE_CHANNEL);\n    }\n\n    mux_encoder_finalize(enc);\n\n    // Read multiplexed output\n    uint8_t muxed[65536];\n    size_t total = 0;\n    size_t written;\n    while (mux_encoder_read(enc, muxed + total, sizeof(muxed) - total, \u0026written) == MUX_OK) {\n        total += written;\n    }\n\n    mux_encoder_destroy(enc);\n\n    // Decode - audio and metadata come out interleaved\n    struct mux_decoder *dec = mux_decoder_new(MUX_CODEC_OPUS, NULL, 0);\n    mux_decoder_decode(dec, muxed, total, \u0026consumed);\n    mux_decoder_finalize(dec);\n\n    uint8_t buffer[8192];\n    int stream_type;\n    while (mux_decoder_read(dec, buffer, sizeof(buffer), \u0026written, \u0026stream_type) == MUX_OK) {\n        if (stream_type == MUX_STREAM_AUDIO) {\n            printf(\"Audio: %zu bytes\\n\", written);\n        } else {\n            printf(\"Metadata: %s\\n\", (char *)buffer);\n        }\n    }\n\n    mux_decoder_destroy(dec);\n    return 0;\n}\n```\n\n### Example 3: Codec Parameter Discovery\n\n```c\n#include \u003cmux.h\u003e\n#include \u003cstdio.h\u003e\n\nvoid print_codec_info(enum mux_codec_type codec) {\n    const char *name = mux_codec_to_name(codec);\n    printf(\"\\n=== %s ===\\n\", name);\n\n    // Get encoder parameters\n    const struct mux_param_desc *params;\n    int count;\n    if (mux_get_encoder_params(codec, \u0026params, \u0026count) == MUX_OK) {\n        printf(\"Encoder parameters:\\n\");\n        for (int i = 0; i \u003c count; i++) {\n            printf(\"  %s: %s\\n\", params[i].name, params[i].description);\n            if (params[i].type == MUX_PARAM_TYPE_INT) {\n                printf(\"    Range: %d-%d (default: %d)\\n\",\n                       params[i].range.i.min,\n                       params[i].range.i.max,\n                       params[i].range.i.def);\n            }\n        }\n    }\n\n    // Get sample rate info\n    struct mux_sample_rate_list sr_list;\n    if (mux_get_supported_sample_rates(codec, \u0026sr_list) == MUX_OK) {\n        printf(\"Sample rates: \");\n        if (sr_list.is_range) {\n            printf(\"%d-%d Hz (continuous)\\n\", sr_list.rates[0], sr_list.rates[1]);\n        } else {\n            for (int i = 0; i \u003c sr_list.count; i++) {\n                printf(\"%d%s\", sr_list.rates[i], i \u003c sr_list.count - 1 ? \", \" : \"\");\n            }\n            printf(\" Hz (discrete)\\n\");\n        }\n    }\n}\n\nint main(void) {\n    // List all codecs\n    const struct mux_codec_info *codecs;\n    int count;\n    mux_list_codecs(\u0026codecs, \u0026count);\n\n    for (int i = 0; i \u003c count; i++) {\n        print_codec_info(codecs[i].type);\n    }\n\n    return 0;\n}\n```\n\n---\n\n## Codec-Specific Parameters\n\n### FLAC\n```c\nstruct mux_param params[] = {\n    { .name = \"compression\", .value.i = 8 }  // 0 (fast) - 8 (best)\n};\n```\n\n### MP3\n```c\nstruct mux_param params[] = {\n    { .name = \"bitrate\", .value.i = 192 }  // kbps: 8-320\n};\n```\n\n### Vorbis\n```c\nstruct mux_param params[] = {\n    { .name = \"quality\", .value.f = 0.6f }  // 0.0 (low) - 1.0 (high)\n};\n// Or:\nstruct mux_param params[] = {\n    { .name = \"bitrate\", .value.i = 128 }  // kbps\n};\n```\n\n### Opus\n```c\nstruct mux_param params[] = {\n    { .name = \"bitrate\", .value.i = 128 },     // kbps: 6-510\n    { .name = \"complexity\", .value.i = 10 },   // 0-10\n    { .name = \"vbr\", .value.i = 1 }            // 0=CBR, 1=VBR\n};\n```\n\n### AAC\n```c\nstruct mux_param params[] = {\n    { .name = \"bitrate\", .value.i = 128 },   // kbps: 8-512\n    { .name = \"profile\", .value.i = 2 }      // 2=LC, 5=HE, 29=HEv2\n};\n```\n\n---\n\n## Building \u0026 Dependencies\n\n### Required Dependencies\n- CMake 3.10+\n- C99 compiler (GCC, Clang)\n\n### Optional Dependencies (Codecs)\n- **MP3**: libmp3lame-dev, libmpg123-dev\n- **Vorbis**: libogg-dev, libvorbis-dev\n- **Opus**: libogg-dev, libopus-dev\n- **FLAC**: libogg-dev, libflac-dev\n- **AAC**: libfdk-aac-dev (note: FDK-AAC has custom license restrictions)\n\n### Build Options\n```bash\nmkdir build \u0026\u0026 cd build\n\n# Build with all available codecs\ncmake ..\nmake\n\n# Build without specific codec\ncmake -DHAVE_MP3=OFF ..\n\n# Install\nsudo make install\n```\n\n### Checking Available Codecs\nAfter building, check which codecs are available:\n\n```bash\n./mux --help  # Lists available codecs\n```\n\nOr programmatically:\n\n```c\nconst struct mux_codec_ops *ops = mux_get_codec_ops(MUX_CODEC_AAC);\nif (ops) {\n    printf(\"AAC is available\\n\");\n} else {\n    printf(\"AAC is not available\\n\");\n}\n```\n\n---\n\n## Performance\n\nTypical compression ratios (1 second, 44100 Hz stereo, 440 Hz sine wave):\n\n| Codec       | Settings      | Size  | Ratio | Type     |\n|-------------|---------------|-------|-------|----------|\n| PCM         | -             | 176KB | 100%  | Lossless |\n| FLAC        | Level 8       | 18KB  | 10%   | Lossless |\n| Vorbis      | Quality 0.4   | 8KB   | 4.4%  | Lossy    |\n| Opus        | 128 kbps      | 14KB  | 8.2%  | Lossy    |\n| MP3         | 192 kbps      | 25KB  | 14.6% | Lossy    |\n| AAC         | 128 kbps      | 15KB  | 8.5%  | Lossy    |\n\n---\n\n## Error Handling\n\nAll functions return an error code or NULL on failure. Get detailed error information:\n\n```c\nif (mux_encoder_encode(enc, data, size, \u0026consumed, MUX_STREAM_AUDIO) != MUX_OK) {\n    const struct mux_error_info *err = mux_encoder_get_error(enc);\n    fprintf(stderr, \"Error %d: %s\\n\", err-\u003ecode, err-\u003emessage);\n    if (err-\u003esource) {\n        fprintf(stderr, \"Source: %s (code %d)\\n\", err-\u003esource, err-\u003esource_code);\n        if (err-\u003esource_msg) {\n            fprintf(stderr, \"Details: %s\\n\", err-\u003esource_msg);\n        }\n    }\n}\n```\n\n---\n\n## Testing\n\n```bash\n# Run all tests\nmake test\n\n# Run specific test\n./test_flac_simple\n./test_opus_simple\n./test_vorbis_validation\n./test_flac_validation\n```\n\n---\n\n## License\n\nGPL-3.0-or-later\n\n**Note**: AAC support uses libfdk-aac which has its own license restrictions (not GPL).\n\n---\n\n## Contributing\n\nContributions welcome! Please ensure:\n- Code follows existing style\n- All tests pass\n- New features include tests\n- API changes are documented\n\n---\n\n## See Also\n\n- Example code in `tests/` directory\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvampirefrog%2Fmuxaudio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvampirefrog%2Fmuxaudio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvampirefrog%2Fmuxaudio/lists"}