diff options
author | Sigrid <ftrvxmtrx@gmail.com> | 2021-01-11 15:45:12 +0100 |
---|---|---|
committer | Sigrid <ftrvxmtrx@gmail.com> | 2021-01-11 15:45:12 +0100 |
commit | ce82f6750c5d98968259b80614643ed63b972ea3 (patch) | |
tree | b3fe6d83bb1abf34129f1771810567ce2ac7b372 | |
parent | 10237a22f189d304668283fb82870b36144d4d1b (diff) | |
download | plan9front-ce82f6750c5d98968259b80614643ed63b972ea3.tar.xz |
audio/flacenc
-rw-r--r-- | sys/man/1/audio | 38 | ||||
-rw-r--r-- | sys/src/cmd/audio/flacenc/flacenc.c | 148 | ||||
-rw-r--r-- | sys/src/cmd/audio/flacenc/mkfile | 21 | ||||
-rw-r--r-- | sys/src/cmd/audio/mkfile | 2 |
4 files changed, 202 insertions, 7 deletions
diff --git a/sys/man/1/audio b/sys/man/1/audio index 414827362..39339cdea 100644 --- a/sys/man/1/audio +++ b/sys/man/1/audio @@ -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). diff --git a/sys/src/cmd/audio/flacenc/flacenc.c b/sys/src/cmd/audio/flacenc/flacenc.c new file mode 100644 index 000000000..f67830e0f --- /dev/null +++ b/sys/src/cmd/audio/flacenc/flacenc.c @@ -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; +} diff --git a/sys/src/cmd/audio/flacenc/mkfile b/sys/src/cmd/audio/flacenc/mkfile new file mode 100644 index 000000000..f8bc3a111 --- /dev/null +++ b/sys/src/cmd/audio/flacenc/mkfile @@ -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 diff --git a/sys/src/cmd/audio/mkfile b/sys/src/cmd/audio/mkfile index abc209502..0a9317aac 100644 --- a/sys/src/cmd/audio/mkfile +++ b/sys/src/cmd/audio/mkfile @@ -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 |