Monorepo for Aesthetic.Computer aesthetic.computer
at main 147 lines 5.8 kB view raw
1// audio-decode.h — Streaming audio file decoder for DJ decks 2// Uses FFmpeg (libavformat/libavcodec/libswresample) to decode MP3/WAV/FLAC/OGG/AAC 3// into a lock-free stereo float ring buffer consumed by the audio thread. 4 5#ifndef AC_AUDIO_DECODE_H 6#define AC_AUDIO_DECODE_H 7 8#ifdef HAVE_AVCODEC 9 10#include <pthread.h> 11#include <stdint.h> 12 13// ~5 seconds of stereo float at 192kHz = ~7.7 MB per decoder 14#define DECK_RING_SECONDS 5 15 16typedef struct ACDeckDecoder { 17 // Ring buffer: interleaved stereo float (L, R, L, R, ...) 18 float *ring; 19 int ring_size; // capacity in frames (not samples) 20 volatile int ring_write; // monotonic write position (frames) 21 volatile int ring_read; // monotonic read position (frames) 22 23 // Decoder thread 24 pthread_t thread; 25 pthread_mutex_t mutex; 26 pthread_cond_t cond; 27 volatile int thread_running; // thread alive 28 volatile int decoding; // actively decoding (vs paused/finished) 29 30 // Seek request (set by main thread, consumed by decoder thread) 31 volatile int seek_requested; 32 volatile double seek_target; // seconds 33 34 // Speed control (pitch-coupled, like vinyl) 35 volatile double speed; // 1.0 = normal, negative = reverse 36 double ring_frac; // fractional read position for interpolated speed 37 38 // Track metadata 39 double duration; // total duration in seconds 40 volatile double position; // current playback position in seconds 41 int src_sample_rate; // source file sample rate 42 int src_channels; // source file channels 43 unsigned int out_rate; // output sample rate (e.g. 192000) 44 char path[512]; 45 char title[256]; 46 char artist[256]; 47 48 // Status 49 volatile int loaded; // file opened successfully 50 volatile int finished; // reached end of file 51 volatile int error; 52 char error_msg[128]; 53 54 // FFmpeg state (opaque, managed internally) 55 void *fmt_ctx; // AVFormatContext* 56 void *codec_ctx; // AVCodecContext* 57 void *swr; // SwrContext* 58 int stream_idx; // audio stream index 59 60 // Waveform peaks (decimated max-amplitude samples for visualization) 61 // Generated once on load by scanning the entire file via separate pass. 62 float *peaks; // [0..1] amplitude peaks 63 int peak_count; // number of peaks (typically 1024) 64 65 // Optional downscaled video preview frames for pieces like tapes.mjs. 66 // Frames are stored as opaque ARGB32 pixels (0xAARRGGBB) in a flat array: 67 // [frame0 pixels][frame1 pixels]... 68 uint32_t *video_frames; 69 int video_frame_count; 70 int video_width; 71 int video_height; 72 double video_fps; 73 volatile int video_ready; 74} ACDeckDecoder; 75 76// Create a decoder instance for the given output sample rate 77ACDeckDecoder *deck_decoder_create(unsigned int output_rate); 78 79// Load an audio file. Starts decoder thread. Returns 0 on success, -1 on error. 80int deck_decoder_load(ACDeckDecoder *d, const char *path); 81 82// Playback control 83void deck_decoder_play(ACDeckDecoder *d); 84void deck_decoder_pause(ACDeckDecoder *d); 85void deck_decoder_seek(ACDeckDecoder *d, double seconds); 86void deck_decoder_set_speed(ACDeckDecoder *d, double speed); // 0.5–2.0 87 88// Unload current file and stop thread (decoder can be reused with another load) 89void deck_decoder_unload(ACDeckDecoder *d); 90 91// Generate peaks for the loaded file (call after deck_decoder_load). 92// Decodes the entire file once and writes max-amplitude peaks per chunk. 93// Safe to call from main thread; takes a few hundred ms for typical tracks. 94int deck_decoder_generate_peaks(ACDeckDecoder *d, int target_count); 95 96// Generate a lightweight downscaled video preview strip for the loaded file. 97// Safe to call from main thread; intended for UI playback rather than full-res video. 98int deck_decoder_generate_video_preview(ACDeckDecoder *d, int width, int height, int fps); 99 100// Destroy decoder and free all resources 101void deck_decoder_destroy(ACDeckDecoder *d); 102 103#else // !HAVE_AVCODEC 104 105// Stubs when FFmpeg is not available 106typedef struct ACDeckDecoder { 107 volatile int loaded; 108 volatile int playing; 109 volatile int finished; 110 volatile double position; 111 double duration; 112 volatile double speed; 113 char title[256]; 114 char artist[256]; 115 char error_msg[128]; 116 volatile int error; 117 // Ring buffer stubs for audio thread 118 float *ring; 119 int ring_size; 120 volatile int ring_write; 121 volatile int ring_read; 122 uint32_t *video_frames; 123 int video_frame_count; 124 int video_width; 125 int video_height; 126 double video_fps; 127 volatile int video_ready; 128} ACDeckDecoder; 129 130static inline ACDeckDecoder *deck_decoder_create(unsigned int output_rate) { 131 (void)output_rate; return 0; 132} 133static inline int deck_decoder_load(ACDeckDecoder *d, const char *path) { 134 (void)d; (void)path; return -1; 135} 136static inline void deck_decoder_play(ACDeckDecoder *d) { (void)d; } 137static inline void deck_decoder_pause(ACDeckDecoder *d) { (void)d; } 138static inline void deck_decoder_seek(ACDeckDecoder *d, double s) { (void)d; (void)s; } 139static inline void deck_decoder_set_speed(ACDeckDecoder *d, double s) { (void)d; (void)s; } 140static inline void deck_decoder_unload(ACDeckDecoder *d) { (void)d; } 141static inline void deck_decoder_destroy(ACDeckDecoder *d) { (void)d; } 142static inline int deck_decoder_generate_video_preview(ACDeckDecoder *d, int width, int height, int fps) { 143 (void)d; (void)width; (void)height; (void)fps; return -1; 144} 145 146#endif // HAVE_AVCODEC 147#endif // AC_AUDIO_DECODE_H