Skip to content

Instantly share code, notes, and snippets.

@makefunstuff
Created July 5, 2024 13:34
Show Gist options
  • Save makefunstuff/513e7e2cae68541e035bbed4f0700426 to your computer and use it in GitHub Desktop.
Save makefunstuff/513e7e2cae68541e035bbed4f0700426 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <mpg123.h>
#include <alsa/asoundlib.h>
#define PCM_DEVICE "default"
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s <mp3 file>\n", argv[0]);
return 1;
}
const char *filename = argv[1];
// Initialize the MPG123 library
mpg123_init();
mpg123_handle *mh = mpg123_new(NULL, NULL);
if (mpg123_open(mh, filename) != MPG123_OK) {
fprintf(stderr, "Error opening %s: %s\n", filename, mpg123_strerror(mh));
return 1;
}
// Retrieve the format of the MP3 file
long rate;
int channels, encoding;
if (mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK) {
fprintf(stderr, "Error getting format: %s\n", mpg123_strerror(mh));
return 1;
}
// Set the output format
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
int pcm;
snd_pcm_uframes_t frames;
char *buffer;
int size;
// Open the PCM device
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf(stderr, "Error opening PCM device %s: %s\n", PCM_DEVICE, snd_strerror(pcm));
return 1;
}
// Allocate hardware parameters object
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
// Set the desired hardware parameters
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm_handle, params, channels);
snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0);
// Write the parameters to the driver
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0) {
fprintf(stderr, "Error setting HW params: %s\n", snd_strerror(pcm));
return 1;
}
// Decode and play the MP3 file
size_t buffer_size = mpg123_outblock(mh);
unsigned char *mpg123_buffer = (unsigned char *) malloc(buffer_size * sizeof(unsigned char));
size_t done;
int err;
while ((err = mpg123_read(mh, mpg123_buffer, buffer_size, &done)) == MPG123_OK) {
// Convert the mpg123_buffer to the correct format and copy to the buffer
memcpy(buffer, mpg123_buffer, done);
snd_pcm_writei(pcm_handle, buffer, done / (channels * 2)); // 2 bytes/sample
}
// Clean up
free(buffer);
free(mpg123_buffer);
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
mpg123_close(mh);
mpg123_delete(mh);
mpg123_exit();
return 0;
}
const std = @import("std");
const c = @cImport({
@cInclude("mpg123.h");
@cInclude("alsa/asoundlib.h");
});
pub fn brr(allocator: std.mem.Allocator, file: []const u8) !void {
_ = c.mpg123_init();
const handle = c.mpg123_new(null, null) orelse {
std.log.warn("Failed to create mpg123 handle\n", .{});
return;
};
const file_path: [*c]const u8 = @ptrCast(file);
if (c.mpg123_open(handle, file_path) != c.MPG123_OK) {
std.log.warn("Failed to open the file: {s}\n", .{file_path});
return;
}
var encoding: c_int = 0;
var channels: c_int = 0;
var rate: c_long = 0;
if (c.mpg123_getformat(handle, &rate, &channels, &encoding) != c.MPG123_OK) {
std.log.warn("Failed to get format\n", .{});
return;
}
var pcm: ?*c.snd_pcm_t = undefined;
if (c.snd_pcm_open(&pcm, "default", c.SND_PCM_STREAM_PLAYBACK, 0) < 0) {
std.log.warn("Failed to open ALSA device\n", .{});
return;
}
var dir: c_int = 0;
var params: ?*c.snd_pcm_hw_params_t = null;
if (c.snd_pcm_hw_params_malloc(&params) < 0) {
std.log.warn("Failed to allocate ALSA hardware parameters\n", .{});
return;
}
_ = c.snd_pcm_hw_params_any(pcm, params);
_ = c.snd_pcm_hw_params(pcm, params);
_ = c.snd_pcm_hw_params_set_access(pcm, params, c.SND_PCM_ACCESS_RW_INTERLEAVED);
_ = c.snd_pcm_hw_params_set_format(pcm, params, c.SND_PCM_FORMAT_S16_LE);
_ = c.snd_pcm_hw_params_set_channels(pcm, params, @as(c_uint, @intCast(channels)));
_ = c.snd_pcm_hw_params_set_rate_near(pcm, params, @as(*c_uint, @ptrCast(&rate)), &dir);
if (c.snd_pcm_hw_params(pcm, params) < 0) {
std.log.warn("Failed to set ALSA hardware parameters\n", .{});
return;
}
const buffer_size = c.mpg123_outblock(handle);
var done: usize = 0;
var mpg123_buffer: []u8 = try allocator.alloc(u8, buffer_size);
_ = &mpg123_buffer;
defer allocator.free(mpg123_buffer);
while (c.mpg123_read(handle, @as(?*anyopaque, @ptrCast(mpg123_buffer.ptr)), buffer_size, &done) == c.MPG123_OK) {
_ = c.snd_pcm_writei(pcm, @as(?*anyopaque, @ptrCast(mpg123_buffer.ptr)), done / 4);
}
_ = c.mpg123_delete(handle);
_ = c.snd_pcm_hw_params_free(params);
_ = c.snd_pcm_close(pcm);
_ = c.mpg123_exit();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment