Skip to content

Instantly share code, notes, and snippets.

@rymdolle
Created April 18, 2024 13:34
Show Gist options
  • Save rymdolle/31f2991c0774021392efaa3ebd57eb22 to your computer and use it in GitHub Desktop.
Save rymdolle/31f2991c0774021392efaa3ebd57eb22 to your computer and use it in GitHub Desktop.
create c header file with PCM samples from mp3 file
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cassert>
#define MINIMP3_ONLY_MP3
/*#define MINIMP3_ONLY_SIMD*/
/*#define MINIMP3_NONSTANDARD_BUT_LOGICAL*/
#define MINIMP3_IMPLEMENTATION
#include "lib/minimp3/minimp3.h"
uint8_t* id3_skip_header(uint8_t *buffer) {
std::cout << "/*\n";
if (!memcmp(buffer, "ID3", 3)) {
std::cout << " * ID3 tag found\n"
<< " * vmajor: " << (int) *(buffer+3) << '\n'
<< " * vminor: " << (int) *(buffer+4) << '\n'
<< " * flags: " << (int) *(buffer+5);
buffer += 6;
uint32_t size = 0;
for (int i = 0; i < 4; ++i) {
size <<= 7;
size += buffer[i] & 0x7f;
}
std::cout << "size: " << size << "\n";
return buffer + 4 + size;
}
return buffer;
}
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "No file input\n";
exit(1);
}
size_t limit = 1000000;
if (argc > 2) {
limit = std::atoi(argv[2]);
}
mp3dec_t mp3d;
mp3dec_frame_info_t info;
constexpr int BUFFER_SIZE = 16 * 1024;
size_t len;
uint8_t buffer[BUFFER_SIZE];
short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
mp3dec_init(&mp3d);
std::fstream file(argv[1], std::ios::in);
if (!file) {
std::cerr << "Invalid\n" << strerror(errno) << '\n';
exit(1);
}
file.read(reinterpret_cast<char*>(buffer), BUFFER_SIZE);
len = file.gcount();
size_t total_frames = 0;
size_t total_bytes = len;
size_t total_pcm = 0;
uint8_t *pos = id3_skip_header(buffer);
len -= pos - buffer;
std::cout << " */\n\n"
<< "const int16_t __in_flash() wav[] = {\n";
for (int frame = 0; frame < 1000; ++frame) {
int ret = mp3dec_decode_frame(&mp3d, pos, len, pcm, &info);
if (ret > 0 && total_pcm + ret * info.channels > limit) {
// Limit reached
break;
}
std::cout << " // Samples: " << ret << '\n'
<< " // Bytes: " << info.frame_bytes << ' ' << len << '\n'
<< " // Buffer: " << (void*) buffer << '\n'
<< " // Pos: " << (void*) pos << '\n'
<< " // Index: " << (pos-buffer) << '\n'
<< " // Offset: " << info.frame_offset << '\n'
<< " // Channels: " << info.channels << '\n'
<< " // Layer: " << info.layer << '\n'
<< " // Bitrate: " << info.bitrate_kbps << '\n'
<< " // Sampling: " << info.hz << '\n'
<< " // " << pcm[0] << '\n'
<< '\n';
if (ret > 0) {
std::cout << " // frame " << frame;
for (int i = 0; i < ret; ++i) {
if (i % 12 == 0)
std::cout << "\n ";
std::cout << pcm[i] << ",";
}
std::cout << std::dec << "\n\n";
++total_frames;
pos += info.frame_bytes;
len -= info.frame_bytes;
total_pcm += ret * info.channels;
if ((pos - buffer) + info.frame_bytes * 10 >= BUFFER_SIZE) {
if (file.eof()) {
std::cout << " // File eof\n";
break;
}
// Read more data if one more frame doesn't fit
// Move rest of data to beginning of buffer
memmove(buffer, pos, len);
// Read more data from file
file.read(reinterpret_cast<char*>(buffer + len), BUFFER_SIZE - len);
std::cout << " // Read more " << file.gcount() << ' ' << len << "\n";
total_bytes += file.gcount();
len += file.gcount();
assert(len <= BUFFER_SIZE);
pos = buffer;
}
} else if (info.frame_bytes > 0) {
std::cout << " // Skip " << info.frame_bytes << '\n';
pos += info.frame_bytes;
len -= info.frame_bytes;
} else {
std::cerr << " // Done.\n";
break;
}
}
std::cout << "};\n\n";
std::cout << "// total bytes: " << total_bytes << '\n';
std::cout << "// total frames: " << total_frames << '\n';
std::cout << "// total pcm: " << total_pcm << '\n';
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment