Monorepo for Aesthetic.Computer
aesthetic.computer
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