ref: a291bbdeddfd41a2f0907ecbd7b819f0eedffdaf
dir: /sys/src/cmd/audio/flacdec/flacdec.c/
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include "FLAC/stream_decoder.h" static int ifd = -1; static int sts; static FLAC__StreamDecoderReadStatus decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data) { int n = *bytes; n = fread(buffer,1,n,stdin); if(n <= 0){ *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } else { *bytes = n; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } } static FLAC__StreamDecoderWriteStatus decoutput(FLAC__StreamDecoder *dec, FLAC__Frame *frame, FLAC__int32 *buffer[], void *client_data) { static int rate, chans, bits; static unsigned char *buf; static int nbuf; FLAC__int32 *s, v; unsigned char *p; int i, j, n, b, len; /* start converter if format changed */ if(rate != frame->header.sample_rate || chans != frame->header.channels || bits != frame->header.bits_per_sample){ int pid, pfd[2]; char fmt[32]; rate = frame->header.sample_rate; chans = frame->header.channels; bits = frame->header.bits_per_sample; sprintf(fmt, "s%dr%dc%d", bits, rate, chans); if(ifd >= 0){ close(ifd); wait(&sts); } if(pipe(pfd) < 0){ fprintf(stderr, "Error creating pipe\n"); exit(1); } pid = fork(); if(pid < 0){ fprintf(stderr, "Error forking\n"); exit(1); } if(pid == 0){ dup2(pfd[1], 0); close(pfd[1]); close(pfd[0]); execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, NULL); fprintf(stderr, "Error executing converter\n"); exit(1); } close(pfd[1]); ifd = pfd[0]; } len = frame->header.blocksize; b = (bits+7)/8; n = b * chans * len; if(n > nbuf){ nbuf = n; buf = realloc(buf, nbuf); if(buf == NULL){ fprintf(stderr, "Error allocating memory\n"); exit(1); } } p = buf; for(j=0; j < chans; j++){ s = buffer[j]; p = buf + j*b; for(i=0; i < len; i++){ n = 0; v = *s++; switch(b){ case 4: p[n++] = v, v>>=8; case 3: p[n++] = v, v>>=8; case 2: p[n++] = v, v>>=8; case 1: p[n] = v; } p += chans*b; } } n = b * chans * len; if(n > 0) write(ifd, buf, n); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void decerror(FLAC__StreamDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *client_data) { } static void decmeta(FLAC__StreamDecoder *dec, FLAC__StreamMetadata *metadata, void *client_data) { } int main(int argc, char *argv[]) { FLAC__bool ok = true; FLAC__StreamDecoder *dec = 0; dec = FLAC__stream_decoder_new(); FLAC__stream_decoder_set_read_callback(dec, decinput); FLAC__stream_decoder_set_write_callback(dec, decoutput); FLAC__stream_decoder_set_error_callback(dec, decerror); FLAC__stream_decoder_set_metadata_callback(dec, decmeta); FLAC__stream_decoder_init(dec); FLAC__stream_decoder_process_until_end_of_stream(dec); FLAC__stream_decoder_finish(dec); if(ifd >= 0){ close(ifd); wait(&sts); } return 0; }