audio/flacenc

This commit is contained in:
Sigrid 2021-01-11 15:45:12 +01:00
parent 10237a22f1
commit ce82f6750c
4 changed files with 202 additions and 7 deletions

View file

@ -1,6 +1,6 @@
.TH AUDIO 1
.SH NAME
mp3dec, mp3enc, oggdec, oggenc, flacdec, sundec, wavdec, pcmconv, mixfs \- decode and encode audio files
mp3dec, mp3enc, oggdec, oggenc, flacdec, flacenc, sundec, wavdec, pcmconv, mixfs \- decode and encode audio files
.SH SYNOPSIS
.B audio/mp3dec
[
@ -55,6 +55,27 @@ q ] [
] [
.I "long or silly options"
]
.br
.B audio/flacenc
[
.B -b
.I bitspersample
] [
.B -c
.I channels
] [
.B -l
.I compresslevel
] [
.B -s
.I sfreq
] [
.B -P
.I padding
] [
.B -T
.I field=value
]
.PP
.B audio/pcmconv
[
@ -107,10 +128,11 @@ seek to a specific position in seconds before decoding.
The encoders read PCM on standard input and produce compressed audio
on standard output.
.PP
.I Oggenc
.I Flacenc,
.I oggenc
and
.I mp3enc
produce OGG Vorbis and MP3 audio. For
produce FLAC, OGG Vorbis and MP3 audio. For
.I mp3enc,
the MP3 file will use `constant bit-rate' (CBR) encoding by default,
but that can be changed via
@ -120,11 +142,13 @@ or
.BR -v
(variable bitrate, VBR).
.PP
.I Oggenc
accepts raw PCM in the same byte order as
.I Flacenc
and
.I oggenc
accept raw PCM in the same byte order as
.B /dev/audio
(little-endian),
t
while
.I mp3enc -r
expects big-endian.
.SS Encoding options
@ -380,3 +404,5 @@ dd -conv swab | audio/mp3enc -a -r -m m --resample 16 -b 24
first appeared in 9front (December, 2012).
.I Mixfs
first appeared in 9front (December, 2013).
.I Flacenc
first appeared in 9front (January, 2020).

View file

@ -0,0 +1,148 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _PLAN9_SOURCE
#include <utf.h>
#include <lib9.h>
#include "FLAC/stream_encoder.h"
#include "FLAC/metadata.h"
static FLAC__StreamEncoderReadStatus
encwrite(FLAC__StreamEncoder *enc, FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
{
return fwrite(buffer, 1, bytes, stdout) != bytes ?
FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR :
FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
static FLAC__StreamEncoderSeekStatus
encseek(FLAC__StreamEncoder *enc, FLAC__uint64 absolute_byte_offset, void *client_data)
{
return fseeko(stdout, absolute_byte_offset, SEEK_SET) != absolute_byte_offset ?
FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED :
FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
}
static FLAC__StreamEncoderTellStatus
enctell(FLAC__StreamEncoder *enc, FLAC__uint64 *absolute_byte_offset, void *client_data)
{
off_t off;
if((off = ftello(stdout)) < 0)
return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
*absolute_byte_offset = off;
return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-b bitspersample] [-c channels] [-l compresslevel] [-r sfreq] [-P padding] [-T field=value]\n", argv0);
exit(1);
}
int
main(int argc, char *argv[])
{
int i, n, nm, r, be, bits, chan, level, sfreq;
FLAC__StreamMetadata_VorbisComment_Entry vc;
FLAC__StreamMetadata *m[2];
uint32_t beef = 0xdeadbeef;
FLAC__StreamEncoder *enc;
FLAC__int32 *buf;
int16_t *x;
be = *((uint8_t*)&beef) == 0xde;
m[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
nm = 1;
bits = 16;
chan = 2;
sfreq = 44100;
level = -1;
ARGBEGIN{
case 'b':
bits = atoi(EARGF(usage()));
if(bits <= 8 || bits > 32){
fprintf(stderr, "bits per sample = %d not supported\n");
exit(1);
}
break;
case 'c':
chan = atoi(EARGF(usage()));
break;
case 'l':
level = atoi(EARGF(usage()));
break;
case 's':
sfreq = atoi(EARGF(usage()));
break;
case 'P':
m[nm] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
m[nm++]->length = atoi(EARGF(usage()));
break;
case 'T':
vc.entry = (FLAC__byte*)EARGF(usage());
vc.length = strlen((char*)vc.entry);
FLAC__metadata_object_vorbiscomment_append_comment(m[0], vc, true);
break;
default:
usage();
}ARGEND
if(argc != 0)
usage();
n = chan * 4096;
if((buf = malloc(n*4)) == NULL){
fprintf(stderr, "no memory\n");
exit(1);
}
x = (int16_t*)buf + (bits > 16 ? 0 : n);
if((enc = FLAC__stream_encoder_new()) == NULL){
fprintf(stderr, "failed to create encoder\n");
exit(1);
}
FLAC__stream_encoder_set_bits_per_sample(enc, bits);
FLAC__stream_encoder_set_channels(enc, chan);
FLAC__stream_encoder_set_sample_rate(enc, sfreq);
if(level >= 0)
FLAC__stream_encoder_set_compression_level(enc, level);
if(!FLAC__stream_encoder_set_metadata(enc, m, nm)){
fprintf(stderr, "failed to set metadata\n");
exit(1);
}
if(FLAC__stream_encoder_init_stream(enc, encwrite, encseek, enctell, NULL, NULL) != FLAC__STREAM_ENCODER_INIT_STATUS_OK){
fprintf(stderr, "failed to init the stream\n");
exit(1);
}
for(;;){
r = fread(x, bits > 16 ? 4 : 2, n, stdin);
if(r < 1)
break;
if(bits <= 16){
for(i = 0; i < r; i++)
buf[i] = be ? x[i]<<8 | x[i]>>8 : x[i];
}else if(be){
for(i = 0; i < r; i++)
buf[i] = buf[i]<<24 | (buf[i]<<8)&0xff0000 | (buf[i]>>8)&0xff00 | buf[i]>>24;
}
if(!FLAC__stream_encoder_process_interleaved(enc, buf, r/chan)){
fprintf(stderr, "encoding failed\n");
exit(1);
}
}
if(!FLAC__stream_encoder_finish(enc)){
fprintf(stderr, "encoding failed\n");
exit(1);
}
FLAC__stream_encoder_delete(enc);
return 0;
}

View file

@ -0,0 +1,21 @@
</$objtype/mkfile
<../config
TARGET=flacenc
CC=pcc
CFLAGS=-I. -I../libFLAC -I../libFLAC/FLAC -D_POSIX_SOURCE -D_BSD_EXTENSION -DPlan9 -c
%.$O: %.c
$CC $CFLAGS -c $stem.c
$O.%: %.$O ../libFLAC/libFLAC.a$O
$CC -o $target $prereq
all:V: $O.$TARGET
clean:V:
rm -f *.[$OS] [$OS].$TARGET
install:V: $O.$TARGET
cp $O.$TARGET $BIN/$TARGET

View file

@ -1,7 +1,7 @@
</$objtype/mkfile
LIBS=libogg libvorbis libFLAC
PROGS=pcmconv oggdec oggenc mp3dec mp3enc flacdec wavdec sundec mixfs
PROGS=pcmconv oggdec oggenc mp3dec mp3enc flacdec flacenc wavdec sundec mixfs
#libs must be made first
DIRS=$LIBS $PROGS