1
1
Fork 0
mirror of https://github.com/QB64Official/qb64.git synced 2024-09-15 06:53:51 +00:00
qb64/internal/c/parts/audio/decode/ogg/download/sample.c

261 lines
7.5 KiB
C

#define STB_DEFINE
#define STB_ONLY
#include "stb.h" /* http://nothings.org/stb.h */
#include "stb_vorbis.c"
void write_floats(FILE *g, int len, float *left, float *right);
void show_info(stb_vorbis *v);
// stb_vorbis_decode_filename: decode an entire file to interleaved shorts
void test_decode_filename(FILE *g, char *filename)
{
short *decoded;
int channels, len;
len = stb_vorbis_decode_filename(filename, &channels, &decoded);
if (len)
fwrite(decoded, 2, len*channels, g);
else
stb_fatal("Couldn't open {%s}", filename);
}
void test_get_frame_short_interleaved(FILE *g, char *filename)
{
short sbuffer[8000];
int n, error;
stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL);
if (!v) stb_fatal("Couldn't open {%s}", filename);
show_info(v);
while (0 != (n=stb_vorbis_get_frame_short_interleaved(v, 2, sbuffer, 8000))) {
fwrite(sbuffer, 2, n*2, g);
}
stb_vorbis_close(v);
}
void test_get_samples_short_interleaved(FILE *g, char *filename)
{
int error;
stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL);
if (!v) stb_fatal("Couldn't open {%s}", filename);
show_info(v);
for(;;) {
int16 sbuffer[333];
int n;
n = stb_vorbis_get_samples_short_interleaved(v, 2, sbuffer, 333);
if (n == 0)
break;
fwrite(sbuffer, 2, n*2, g);
}
stb_vorbis_close(v);
}
void test_get_frame_float(FILE *g, char *filename)
{
int error;
stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL);
if (!v) stb_fatal("Couldn't open {%s}", filename);
show_info(v);
for(;;) {
int n;
float *left, *right;
float **outputs;
int num_c;
n = stb_vorbis_get_frame_float(v, &num_c, &outputs);
if (n == 0)
break;
left = outputs[0];
right = outputs[num_c > 1];
write_floats(g, n, left, right);
}
stb_vorbis_close(v);
}
// in push mode, you can load your data any way you want, then
// feed it a little bit at a time. this is the preferred way to
// handle reading from a packed file or some custom stream format;
// instead of putting callbacks inside stb_vorbis, you just keep
// a little buffer (it needs to be big enough for one packet of
// audio, except at the beginning where you need to buffer up the
// entire header).
//
// for this test, I just load all the data and just lie to stb_vorbis
// and claim I only have a little of it
void test_decode_frame_pushdata(FILE *g, char *filename)
{
int p,q, len, error, used;
stb_vorbis *v;
uint8 *data = stb_file(filename, &len);
if (!data) stb_fatal("Couldn't open {%s}", filename);
p = 0;
q = 1;
retry:
v = stb_vorbis_open_pushdata(data, q, &used, &error, NULL);
if (v == NULL) {
if (error == VORBIS_need_more_data) {
q += 1;
goto retry;
}
fprintf(stderr, "Error %d\n", error);
exit(1);
}
p += used;
show_info(v);
for(;;) {
int k=0;
int n;
float *left, *right;
uint32 next_t=0;
float **outputs;
int num_c;
q = 32;
retry3:
if (q > len-p) q = len-p;
used = stb_vorbis_decode_frame_pushdata(v, data+p, q, &num_c, &outputs, &n);
if (used == 0) {
if (p+q == len) break; // no more data, stop
if (q < 128) q = 128;
q *= 2;
goto retry3;
}
p += used;
if (n == 0) continue; // seek/error recovery
left = outputs[0];
right = num_c > 1 ? outputs[1] : outputs[0];
write_floats(g, n, left, right);
}
stb_vorbis_close(v);
}
void write_floats(FILE *g, int len, float *left, float *right)
{
const float scale = 32768;
int j;
for (j=0; j < len; ++j) {
int16 x,y;
x = (int) stb_clamp((int) (scale * left[j]), -32768, 32767);
y = (int) stb_clamp((int) (scale * right[j]), -32768, 32767);
fwrite(&x, 2, 1, g);
fwrite(&y, 2, 1, g);
}
}
void show_info(stb_vorbis *v)
{
if (v) {
stb_vorbis_info info = stb_vorbis_get_info(v);
printf("%d channels, %d samples/sec\n", info.channels, info.sample_rate);
printf("Predicted memory needed: %d (%d + %d)\n", info.setup_memory_required + info.temp_memory_required,
info.setup_memory_required, info.temp_memory_required);
}
}
int main(int argc, char **argv)
{
FILE *g=NULL;
char *outfile = "vorbis_test.out";
char *infile;
int n=0;
if (argc > 1 && argv[1][1] == 0 && argv[1][0] >= '1' && argv[1][0] <= '5')
n = atoi(argv[1]);
if (argc < 3 || argc > 4 || n == 0) {
stbprint("Usage: sample {code} {vorbis-filename} [{output-filename}]\n"
"Code is one of:\n"
" 1 - test stb_vorbis_decode_filename\n"
" 2 - test stb_vorbis_get_frame_short_interleaved\n"
" 3 - test stb_vorbis_get_samples_short_interleaved\n"
" 4 - test stb_vorbis_get_frame_float\n"
" 5 - test stb_vorbis_decode_frame_pushdata\n");
return argc != 1;
}
infile = argv[2];
if (argc > 3)
outfile = argv[3];
if (strlen(outfile) >= 4 && 0==stb_stricmp(outfile + strlen(outfile) - 4, ".ogg"))
stb_fatal("You specified a .ogg file as your output file, which you probably didn't actually want.");
if (!strcmp(outfile, "stdout") || !strcmp(outfile, "-") || !strcmp(outfile, "-stdout"))
g = stdout;
else
g = fopen(outfile, "wb");
if (!g) stb_fatal("Couldn't open {%s} for writing", outfile);
switch (n) {
case 1: test_decode_filename(g, infile); break;
case 2: test_get_frame_short_interleaved(g, infile); break;
case 3: test_get_samples_short_interleaved(g, infile); break;
case 4: test_get_frame_float(g, infile); break;
case 5: test_decode_frame_pushdata(g, infile); break;
default: stb_fatal("Unknown option {%d}", n);
}
fclose(g);
return 0;
}
void test_push_mode_forever(FILE *g, char *filename)
{
int p,q, len, error, used;
uint8 *data = stb_file(filename, &len);
stb_vorbis *v;
if (!data) stb_fatal("Couldn't open {%s}", filename);
p = 0;
q = 1;
retry:
v = stb_vorbis_open_pushdata(data, q, &used, &error, NULL);
if (v == NULL) {
if (error == VORBIS_need_more_data) {
q += 1;
goto retry;
}
printf("Error %d\n", error);
exit(1);
}
p += used;
show_info(v);
for(;;) {
int k=0;
int n;
float *left, *right;
float **outputs;
int num_c;
q = 32;
retry3:
if (q > len-p) q = len-p;
used = stb_vorbis_decode_frame_pushdata(v, data+p, q, &num_c, &outputs, &n);
if (used == 0) {
if (p+q == len) {
// seek randomly when at end... this makes sense when listening to it, but dumb when writing to file
p = stb_rand();
if (p < 0) p = -p;
p %= (len - 8000);
stb_vorbis_flush_pushdata(v);
q = 128;
goto retry3;
}
if (q < 128) q = 128;
q *= 2;
goto retry3;
}
p += used;
if (n == 0) continue;
left = outputs[0];
right = num_c > 1 ? outputs[1] : outputs[0];
write_floats(g, n, left, right);
}
stb_vorbis_close(v);
}