aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-02-15 04:32:00 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-02-15 04:32:00 +0100
commitba346d2469facf500cbcaa9cf9117ce04ea0b6da (patch)
treefa1e026da22296f8b044c8960c5860377c4fd6e2
parente65ff4adee3a806881e3c1ebe1b273b9b664eb26 (diff)
downloadODR-AudioEnc-ba346d2469facf500cbcaa9cf9117ce04ea0b6da.tar.gz
ODR-AudioEnc-ba346d2469facf500cbcaa9cf9117ce04ea0b6da.tar.bz2
ODR-AudioEnc-ba346d2469facf500cbcaa9cf9117ce04ea0b6da.zip
Use libtoolame-dab in dabplus-enc
-rw-r--r--libtoolame-dab.sym7
-rw-r--r--libtoolame-dab/bitstream.c16
-rw-r--r--libtoolame-dab/bitstream.h2
-rw-r--r--libtoolame-dab/toolame.c1155
-rw-r--r--libtoolame-dab/toolame.h38
-rw-r--r--src/dabplus-enc.cpp287
-rw-r--r--src/utils.h1
7 files changed, 337 insertions, 1169 deletions
diff --git a/libtoolame-dab.sym b/libtoolame-dab.sym
index 9fa2b97..2e8a1f1 100644
--- a/libtoolame-dab.sym
+++ b/libtoolame-dab.sym
@@ -1 +1,8 @@
+toolame_init
+toolame_enable_downmix_stereo
+toolame_enable_byteswap
+toolame_set_channel_mode
+toolame_set_psy_model
+toolame_set_bitrate
+toolame_set_pad
toolame_encode_frame
diff --git a/libtoolame-dab/bitstream.c b/libtoolame-dab/bitstream.c
index 3417c89..4346d60 100644
--- a/libtoolame-dab/bitstream.c
+++ b/libtoolame-dab/bitstream.c
@@ -127,23 +127,11 @@ void empty_buffer (Bit_stream_struc * bs, int minimum)
/* open the device to write the bit stream into it */
-void open_bit_stream_w (Bit_stream_struc * bs, char *bs_filenam, int size)
+void open_bit_stream_w (Bit_stream_struc * bs, int size)
{
bs->zmq_sock = NULL;
- if (bs_filenam[0] == '-')
- bs->pt = stdout;
- else if (strncmp(bs_filenam, "tcp://", 4) == 0) {
- if (zmqoutput_open(bs, bs_filenam) != 0) {
- fprintf(stderr, "Could not initialise ZMQ\n");
- exit(1);
- }
- bs->pt = NULL; // we're not using file output
- }
- else if ((bs->pt = fopen (bs_filenam, "wb")) == NULL) {
- fprintf (stderr, "Could not create \"%s\".\n", bs_filenam);
- exit (1);
- }
+ bs->pt = NULL; // we're not using file output
alloc_buffer (bs, size);
bs->buf_byte_idx = size - 1;
bs->buf_bit_idx = 8;
diff --git a/libtoolame-dab/bitstream.h b/libtoolame-dab/bitstream.h
index f7759d8..017a12d 100644
--- a/libtoolame-dab/bitstream.h
+++ b/libtoolame-dab/bitstream.h
@@ -1,6 +1,6 @@
int refill_buffer (Bit_stream_struc *);
void empty_buffer (Bit_stream_struc *, int);
-void open_bit_stream_w (Bit_stream_struc *, char *, int);
+void open_bit_stream_w (Bit_stream_struc *, int);
void close_bit_stream_w (Bit_stream_struc *);
void alloc_buffer (Bit_stream_struc *, int);
void desalloc_buffer (Bit_stream_struc *);
diff --git a/libtoolame-dab/toolame.c b/libtoolame-dab/toolame.c
index 09eb69e..a626552 100644
--- a/libtoolame-dab/toolame.c
+++ b/libtoolame-dab/toolame.c
@@ -1,15 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#if defined(JACK_INPUT)
-# include <jack/jack.h>
-# include <jack/ringbuffer.h>
-#endif
#include "common.h"
#include "encoder.h"
-#include "musicin.h"
#include "options.h"
-#include "audio_read.h"
#include "bitstream.h"
#include "mem.h"
#include "crc.h"
@@ -24,20 +18,15 @@
#include "subband.h"
#include "encode_new.h"
#include "toolame.h"
-#include "xpad.h"
#include "utils.h"
-#include "vlc_input.h"
-#include "zmqoutput.h"
-
#include <assert.h>
-music_in_t musicin;
Bit_stream_struc bs;
-char *programName;
-char toolameversion[] = "0.2l-ODR";
const int FPAD_LENGTH=2;
+void smr_dump(double smr[2][SBLIMIT], int nch);
+
void global_init (void)
{
glopts.usepsy = TRUE;
@@ -127,18 +116,17 @@ static FLOAT smrdef[2][32];
static unsigned int scfsi[2][SBLIMIT];
static unsigned int bit_alloc[2][SBLIMIT];
-static uint8_t* xpad_data;
+static char* mot_file = NULL;
+static char* icy_file = NULL;
int toolame_init(void)
{
frameNum = 0;
psycount = 0;
- header.extension = 0;
frame.header = &header;
frame.tab_num = -1; /* no table loaded */
frame.alloc = NULL;
- header.version = MPEG_AUDIO_ID; /* Default: MPEG-1 */
sb_sample = (SBS *) mem_alloc (sizeof (SBS), "sb_sample");
j_sample = (JSBS *) mem_alloc (sizeof (JSBS), "j_sample");
@@ -151,12 +139,115 @@ int toolame_init(void)
memset ((char *) scfsi, 0, sizeof (scfsi));
memset ((char *) bit_alloc, 0, sizeof (bit_alloc));
- xpad_data = NULL;
+ global_init();
+
+ header.extension = 0;
+ header.version = MPEG_AUDIO_ID; /* Default: MPEG-1 */
+ header.copyright = 0;
+ header.original = 0;
+ header.error_protection = FALSE;
+ header.dab_extension = 1;
+ header.lay = DFLT_LAY;
+
+ model = DFLT_PSY;
return 0;
}
-int toolame_encode_frame(short buffer[2][1152])
+int toolame_enable_downmix_stereo(void)
+{
+ glopts.downmix = TRUE;
+ header.mode = MPG_MD_MONO;
+ header.mode_ext = 0;
+ return 0;
+}
+
+int toolame_enable_byteswap(void)
+{
+ glopts.byteswap = TRUE;
+ return 0;
+}
+
+int toolame_set_channel_mode(const char mode)
+{
+ switch (mode) {
+ case 's':
+ header.mode = MPG_MD_STEREO;
+ header.mode_ext = 0;
+ break;
+ case 'd':
+ header.mode = MPG_MD_DUAL_CHANNEL;
+ header.mode_ext = 0;
+ break;
+ /* in j-stereo mode, no default header.mode_ext was defined, gave error..
+ now default = 2 added by MFC 14 Dec 1999. */
+ case 'j':
+ header.mode = MPG_MD_JOINT_STEREO;
+ header.mode_ext = 2;
+ break;
+ case 'm':
+ header.mode = MPG_MD_MONO;
+ header.mode_ext = 0;
+ break;
+ default:
+ fprintf (stderr, "libtoolame-dab: Bad mode %c\n", mode);
+ return 1;
+ }
+ return 0;
+}
+
+int toolame_set_psy_model(int new_model)
+{
+ if (new_model < 0 || new_model > 3) {
+ fprintf(stderr, "libtoolame-dab: Invalid PSY model %d\n", new_model);
+ return 1;
+ }
+ model = new_model;
+ return 0;
+}
+
+int toolame_set_bitrate(int brate)
+{
+ int err = 0;
+
+ /* check for a valid bitrate */
+ if (brate == 0)
+ brate = bitrate[header.version][10];
+
+ /* Check to see we have a sane value for the bitrate for this version */
+ if ((header.bitrate_index = BitrateIndex (brate, header.version)) < 0) {
+ err = 1;
+ }
+
+ if (header.dab_extension) {
+ /* in 48 kHz (= MPEG-1) */
+ /* if the bit rate per channel is less then 56 kbit/s, we have 2 scf-crc */
+ /* else we have 4 scf-crc */
+ /* in 24 kHz (= MPEG-2), we have 4 scf-crc */
+ if (header.version == MPEG_AUDIO_ID && (brate / (header.mode == MPG_MD_MONO ? 1 : 2) < 56))
+ header.dab_extension = 2;
+ }
+
+ open_bit_stream_w(&bs, BUFFER_SIZE);
+
+ return err;
+}
+
+int toolame_set_pad(int pad_len)
+{
+ header.dab_length = pad_len;
+ if (header.dab_length <= 0) {
+ fprintf(stderr, "Invalid XPAD length specified\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int toolame_encode_frame(
+ short buffer[2][1152],
+ unsigned char *xpad_data,
+ unsigned char *output_buffer)
{
extern int minimum;
const int nch = frame.nch;
@@ -414,1034 +505,6 @@ int toolame_encode_frame(short buffer[2][1152])
}
}
-int oldmain (int argc, char **argv)
-{
- SBS *sb_sample;
- JSBS *j_sample;
-#ifdef REFERENCECODE
- typedef double IN[2][HAN_SIZE];
- IN *win_que;
-#endif
- typedef unsigned int SUB[2][3][SCALE_BLOCK][SBLIMIT];
- SUB *subband;
-
- frame_info frame;
- frame_header header;
- char original_file_name[MAX_NAME_SIZE];
- char encoded_file_name[MAX_NAME_SIZE];
- short **win_buf;
- static short buffer[2][1152];
- static unsigned int bit_alloc[2][SBLIMIT], scfsi[2][SBLIMIT];
- static unsigned int scalar[2][3][SBLIMIT], j_scale[3][SBLIMIT];
- static double smr[2][SBLIMIT], lgmin[2][SBLIMIT], max_sc[2][SBLIMIT];
- // FLOAT snr32[32];
- short sam[2][1344]; /* was [1056]; */
- int model, nch, error_protection;
- static unsigned int crc;
- int sb, ch, adb;
- unsigned long frameBits, sentBits = 0;
- unsigned long num_samples;
- int lg_frame;
- int i;
-
- /* Keep track of peaks */
- int peak_left = 0;
- int peak_right = 0;
-
- char* mot_file = NULL;
- char* icy_file = NULL;
-
- /* Used to keep the SNR values for the fast/quick psy models */
- static FLOAT smrdef[2][32];
-
- static int psycount = 0;
- extern int minimum;
-
- sb_sample = (SBS *) mem_alloc (sizeof (SBS), "sb_sample");
- j_sample = (JSBS *) mem_alloc (sizeof (JSBS), "j_sample");
-#ifdef REFERENCECODE
- win_que = (IN *) mem_alloc (sizeof (IN), "Win_que");
-#endif
- subband = (SUB *) mem_alloc (sizeof (SUB), "subband");
- win_buf = (short **) mem_alloc (sizeof (short *) * 2, "win_buf");
-
- /* clear buffers */
- memset ((char *) buffer, 0, sizeof (buffer));
- memset ((char *) bit_alloc, 0, sizeof (bit_alloc));
- memset ((char *) scalar, 0, sizeof (scalar));
- memset ((char *) j_scale, 0, sizeof (j_scale));
- memset ((char *) scfsi, 0, sizeof (scfsi));
- memset ((char *) smr, 0, sizeof (smr));
- memset ((char *) lgmin, 0, sizeof (lgmin));
- memset ((char *) max_sc, 0, sizeof (max_sc));
- //memset ((char *) snr32, 0, sizeof (snr32));
- memset ((char *) sam, 0, sizeof (sam));
-
- global_init ();
-
- header.extension = 0;
- frame.header = &header;
- frame.tab_num = -1; /* no table loaded */
- frame.alloc = NULL;
- header.version = MPEG_AUDIO_ID; /* Default: MPEG-1 */
-
- programName = argv[0];
- if (argc == 1) /* no command-line args */
- short_usage ();
- else
- parse_args (argc, argv, &frame, &model, &num_samples, original_file_name,
- encoded_file_name, &mot_file, &icy_file);
- print_config (&frame, &model, original_file_name, encoded_file_name);
-
- uint8_t* xpad_data = NULL;
- if (mot_file) {
- if (header.dab_length <= 0) {
- fprintf(stderr, "Invalid XPAD length specified\n");
- return 1;
- }
-
- int err = xpad_init(mot_file, header.dab_length + 1);
- if (err == -1) {
- fprintf(stderr, "XPAD reader initialisation failed\n");
- return 1;
- }
-
- xpad_data = malloc(header.dab_length + 1);
- }
-
- /* this will load the alloc tables and do some other stuff */
- hdr_to_frps (&frame);
- nch = frame.nch;
- error_protection = header.error_protection;
-
- unsigned long samps_read;
- while ((samps_read = get_audio(&musicin, buffer, num_samples, nch, &header)) > 0) {
- /* Check if we have new PAD data
- */
- int xpad_len = 0;
- if (mot_file) {
- xpad_len = xpad_read_len(xpad_data, header.dab_length + 1);
-
- if (xpad_len == -1) {
- fprintf(stderr, "Error reading XPAD data\n");
- xpad_len = 0;
- }
- else if (xpad_len == 0) {
- // no PAD available
- }
- else if (xpad_len == header.dab_length + 1) {
-//#define XPAD_DEBUG
-#ifdef XPAD_DEBUG
- fprintf(stderr, "XPAD:");
- for (i = 0; i < xpad_len; i++)
- fprintf(stderr, " %02X", xpad_data[i]);
- fprintf(stderr, "\n");
-#endif
- // everything OK
- xpad_len = xpad_data[header.dab_length];
- assert(xpad_len > 2);
- }
- else {
- fprintf(stderr, "xpad length=%d\n", xpad_len);
- abort();
- }
- }
-
- unsigned long j;
- for (j = 0; j < 1152; j++) {
- peak_left = MAX(peak_left, buffer[0][j]);
- }
- for (j = 0; j < 1152; j++) {
- peak_right = MAX(peak_right, buffer[1][j]);
- }
-
- // We can always set the zmq peaks, even if the output is not
- // used, it just writes some variables
- zmqoutput_set_peaks(peak_left, peak_right);
-
- if (glopts.verbosity > 1)
- if (++frameNum % 10 == 0) {
-
- fprintf(stderr, "[%4u", frameNum);
-
- if (mot_file) {
- fprintf(stderr, " %s",
- xpad_len > 0 ? "p" : " ");
- }
-
- if (glopts.show_level) {
- fprintf(stderr, " (%6d|%-6d) ",
- peak_left, peak_right);
-
- fprintf(stderr, "] [%6s|%-6s]\r",
- level(0, &peak_left),
- level(1, &peak_right) );
- }
- else {
- fprintf(stderr, "]\r");
- }
- }
-
- fflush(stderr);
- win_buf[0] = &buffer[0][0];
- win_buf[1] = &buffer[1][0];
-
- adb = available_bits (&header, &glopts);
- lg_frame = adb / 8;
- if (header.dab_extension) {
- /* You must have one frame in memory if you are in DAB mode */
- /* in conformity of the norme ETS 300 401 http://www.etsi.org */
- /* see bitstream.c */
- if (frameNum == 1)
- minimum = lg_frame + MINIMUM;
- adb -= header.dab_extension * 8 + (xpad_len ? xpad_len : FPAD_LENGTH) * 8;
- }
-
- {
- int gr, bl, ch;
- /* New polyphase filter
- Combines windowing and filtering. Ricardo Feb'03 */
- for( gr = 0; gr < 3; gr++ )
- for ( bl = 0; bl < 12; bl++ )
- for ( ch = 0; ch < nch; ch++ )
- WindowFilterSubband( &buffer[ch][gr * 12 * 32 + 32 * bl], ch,
- &(*sb_sample)[ch][gr][bl][0] );
- }
-
-#ifdef REFERENCECODE
- {
- /* Old code. left here for reference */
- int gr, bl, ch;
- for (gr = 0; gr < 3; gr++)
- for (bl = 0; bl < SCALE_BLOCK; bl++)
- for (ch = 0; ch < nch; ch++) {
- window_subband (&win_buf[ch], &(*win_que)[ch][0], ch);
- filter_subband (&(*win_que)[ch][0], &(*sb_sample)[ch][gr][bl][0]);
- }
- }
-#endif
-
-
-#ifdef NEWENCODE
- scalefactor_calc_new(*sb_sample, scalar, nch, frame.sblimit);
- find_sf_max (scalar, &frame, max_sc);
- if (frame.actual_mode == MPG_MD_JOINT_STEREO) {
- /* this way we calculate more mono than we need */
- /* but it is cheap */
- combine_LR_new (*sb_sample, *j_sample, frame.sblimit);
- scalefactor_calc_new (j_sample, &j_scale, 1, frame.sblimit);
- }
-#else
- scale_factor_calc (*sb_sample, scalar, nch, frame.sblimit);
- pick_scale (scalar, &frame, max_sc);
- if (frame.actual_mode == MPG_MD_JOINT_STEREO) {
- /* this way we calculate more mono than we need */
- /* but it is cheap */
- combine_LR (*sb_sample, *j_sample, frame.sblimit);
- scale_factor_calc (j_sample, &j_scale, 1, frame.sblimit);
- }
-#endif
-
-
-
- if ((glopts.quickmode == TRUE) && (++psycount % glopts.quickcount != 0)) {
- /* We're using quick mode, so we're only calculating the model every
- 'quickcount' frames. Otherwise, just copy the old ones across */
- for (ch = 0; ch < nch; ch++) {
- for (sb = 0; sb < SBLIMIT; sb++)
- smr[ch][sb] = smrdef[ch][sb];
- }
- } else {
- /* calculate the psymodel */
- switch (model) {
- case -1:
- psycho_n1 (smr, nch);
- break;
- case 0: /* Psy Model A */
- psycho_0 (smr, nch, scalar, (FLOAT) s_freq[header.version][header.sampling_frequency] * 1000);
- break;
- case 1:
- psycho_1 (buffer, max_sc, smr, &frame);
- break;
- case 2:
- for (ch = 0; ch < nch; ch++) {
- psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- }
- break;
- case 3:
- /* Modified psy model 1 */
- psycho_3 (buffer, max_sc, smr, &frame, &glopts);
- break;
- case 4:
- /* Modified Psycho Model 2 */
- for (ch = 0; ch < nch; ch++) {
- psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- }
- break;
- case 5:
- /* Model 5 comparse model 1 and 3 */
- psycho_1 (buffer, max_sc, smr, &frame);
- fprintf(stdout,"1 ");
- smr_dump(smr,nch);
- psycho_3 (buffer, max_sc, smr, &frame, &glopts);
- fprintf(stdout,"3 ");
- smr_dump(smr,nch);
- break;
- case 6:
- /* Model 6 compares model 2 and 4 */
- for (ch = 0; ch < nch; ch++)
- psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- fprintf(stdout,"2 ");
- smr_dump(smr,nch);
- for (ch = 0; ch < nch; ch++)
- psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- fprintf(stdout,"4 ");
- smr_dump(smr,nch);
- break;
- case 7:
- fprintf(stdout,"Frame: %i\n",frameNum);
- /* Dump the SMRs for all models */
- psycho_1 (buffer, max_sc, smr, &frame);
- fprintf(stdout,"1");
- smr_dump(smr, nch);
- psycho_3 (buffer, max_sc, smr, &frame, &glopts);
- fprintf(stdout,"3");
- smr_dump(smr,nch);
- for (ch = 0; ch < nch; ch++)
- psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- fprintf(stdout,"2");
- smr_dump(smr,nch);
- for (ch = 0; ch < nch; ch++)
- psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- fprintf(stdout,"4");
- smr_dump(smr,nch);
- break;
- case 8:
- /* Compare 0 and 4 */
- psycho_n1 (smr, nch);
- fprintf(stdout,"0");
- smr_dump(smr,nch);
-
- for (ch = 0; ch < nch; ch++)
- psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
- (FLOAT) s_freq[header.version][header.sampling_frequency] *
- 1000, &glopts);
- fprintf(stdout,"4");
- smr_dump(smr,nch);
- break;
- default:
- fprintf (stderr, "Invalid psy model specification: %i\n", model);
- exit (0);
- }
-
- if (glopts.quickmode == TRUE)
- /* copy the smr values and reuse them later */
- for (ch = 0; ch < nch; ch++) {
- for (sb = 0; sb < SBLIMIT; sb++)
- smrdef[ch][sb] = smr[ch][sb];
- }
-
- if (glopts.verbosity > 4)
- smr_dump(smr, nch);
-
-
-
-
- }
-
-#ifdef NEWENCODE
- sf_transmission_pattern (scalar, scfsi, &frame);
- main_bit_allocation_new (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
- //main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
-
- if (error_protection)
- CRC_calc (&frame, bit_alloc, scfsi, &crc);
-
- write_header (&frame, &bs);
- //encode_info (&frame, &bs);
- if (error_protection)
- putbits (&bs, crc, 16);
- write_bit_alloc (bit_alloc, &frame, &bs);
- //encode_bit_alloc (bit_alloc, &frame, &bs);
- write_scalefactors(bit_alloc, scfsi, scalar, &frame, &bs);
- //encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);
- subband_quantization_new (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
- *subband, &frame);
- //subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
- // *subband, &frame);
- write_samples_new(*subband, bit_alloc, &frame, &bs);
- //sample_encoding (*subband, bit_alloc, &frame, &bs);
-#else
- transmission_pattern (scalar, scfsi, &frame);
- main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
- if (error_protection)
- CRC_calc (&frame, bit_alloc, scfsi, &crc);
- encode_info (&frame, &bs);
- if (error_protection)
- encode_CRC (crc, &bs);
- encode_bit_alloc (bit_alloc, &frame, &bs);
- encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);
- subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
- *subband, &frame);
- sample_encoding (*subband, bit_alloc, &frame, &bs);
-#endif
-
-
- /* If not all the bits were used, write out a stack of zeros */
- for (i = 0; i < adb; i++)
- put1bit (&bs, 0);
-
-
- if (xpad_len) {
- assert(xpad_len > 2);
-
- // insert available X-PAD
- for (i = header.dab_length - xpad_len; i < header.dab_length - FPAD_LENGTH; i++)
- putbits (&bs, xpad_data[i], 8);
- }
-
-
- for (i = header.dab_extension - 1; i >= 0; i--) {
- CRC_calcDAB (&frame, bit_alloc, scfsi, scalar, &crc, i);
- /* this crc is for the previous frame in DAB mode */
- if (bs.buf_byte_idx + lg_frame < bs.buf_size)
- bs.buf[bs.buf_byte_idx + lg_frame] = crc;
- /* reserved 2 bytes for F-PAD in DAB mode */
- putbits (&bs, crc, 8);
- }
-
- if (xpad_len) {
- /* The F-PAD is also given us by mot-encoder */
- putbits (&bs, xpad_data[header.dab_length - 2], 8);
- putbits (&bs, xpad_data[header.dab_length - 1], 8);
- }
- else {
- putbits (&bs, 0, 16); // FPAD is all-zero
- }
-
-#if defined(VLC_INPUT)
- if (glopts.input_select == INPUT_SELECT_VLC) {
- vlc_in_write_icy();
- }
-#endif
-
-
- frameBits = sstell (&bs) - sentBits;
-
- if (frameBits % 8) { /* a program failure */
- fprintf (stderr, "Sent %ld bits = %ld slots plus %ld\n", frameBits,
- frameBits / 8, frameBits % 8);
- fprintf (stderr, "If you are reading this, the program is broken\n");
- fprintf (stderr, "Please report a bug.\n");
- exit(1);
- }
-
- sentBits += frameBits;
-
- // Reset peak measurement
- peak_left = 0;
- peak_right = 0;
- }
-
- fprintf(stdout, "Main loop has quit with samps_read = %zu\n", samps_read);
-
- close_bit_stream_w (&bs);
-
- if ((glopts.verbosity > 1) && (glopts.vbr == TRUE)) {
- int i;
-#ifdef NEWENCODE
- extern int vbrstats_new[15];
-#else
- extern int vbrstats[15];
-#endif
- fprintf (stdout, "VBR stats:\n");
- for (i = 1; i < 15; i++)
- fprintf (stdout, "%4i ", bitrate[header.version][i]);
- fprintf (stdout, "\n");
- for (i = 1; i < 15; i++)
-#ifdef NEWENCODE
- fprintf (stdout,"%4i ",vbrstats_new[i]);
-#else
- fprintf (stdout, "%4i ", vbrstats[i]);
-#endif
- fprintf (stdout, "\n");
- }
-
- fprintf (stderr,
- "Avg slots/frame = %.3f; b/smp = %.2f; bitrate = %.3f kbps\n",
- (FLOAT) sentBits / (frameNum * 8),
- (FLOAT) sentBits / (frameNum * 1152),
- (FLOAT) sentBits / (frameNum * 1152) *
- s_freq[header.version][header.sampling_frequency]);
-
- if (glopts.input_select == INPUT_SELECT_WAV) {
- if ( fclose (musicin.wav_input) != 0) {
- fprintf (stderr, "Could not close \"%s\".\n", original_file_name);
- exit (2);
- }
- }
-
- fprintf (stderr, "\nDone\n");
- exit (0);
-}
-
-/************************************************************************
- *
- * print_config
- *
- * PURPOSE: Prints the encoding parameters used
- *
- ************************************************************************/
-
-void print_config (frame_info * frame, int *psy, char *inPath,
- char *outPath)
-{
- frame_header *header = frame->header;
-
- if (glopts.verbosity == 0)
- return;
-
- fprintf (stderr, "--------------------------------------------\n");
- if (glopts.input_select == INPUT_SELECT_JACK) {
- fprintf (stderr, "Input JACK\n");
- fprintf (stderr, " name %s\n", musicin.jack_name);
- }
- else if (glopts.input_select == INPUT_SELECT_WAV) {
- fprintf (stderr, "Input File : '%s' %.1f kHz\n",
- (strcmp (inPath, "-") ? inPath : "stdin"),
- s_freq[header->version][header->sampling_frequency]);
- }
- else if (glopts.input_select == INPUT_SELECT_VLC) {
- fprintf (stderr, "Input VLC\n");
- fprintf (stderr, " URI %s\n", inPath);
- }
-
- fprintf (stderr, "Output File: '%s'\n",
- (strcmp (outPath, "-") ? outPath : "stdout"));
- fprintf (stderr, "%d kbps ", bitrate[header->version][header->bitrate_index]);
- fprintf (stderr, "%s ", version_names[header->version]);
- if (header->mode != MPG_MD_JOINT_STEREO)
- fprintf (stderr, "Layer II %s Psycho model=%d (Mode_Extension=%d)\n",
- mode_names[header->mode], *psy, header->mode_ext);
- else
- fprintf (stderr, "Layer II %s Psy model %d \n", mode_names[header->mode],
- *psy);
-
- fprintf (stderr, "[De-emph:%s\tCopyright:%s\tOriginal:%s\tCRC:%s]\n",
- ((header->emphasis) ? "On" : "Off"),
- ((header->copyright) ? "Yes" : "No"),
- ((header->original) ? "Yes" : "No"),
- ((header->error_protection) ? "On" : "Off"));
-
- fprintf (stderr, "[Padding:%s\tByte-swap:%s\tChanswap:%s\tDAB:%s]\n",
- ((glopts.usepadbit) ? "Normal" : "Off"),
- ((glopts.byteswap) ? "On" : "Off"),
- ((glopts.channelswap) ? "On" : "Off"),
- ((glopts.dab) ? "On" : "Off"));
-
- if (glopts.vbr == TRUE)
- fprintf (stderr, "VBR Enabled. Using MNR boost of %f\n", glopts.vbrlevel);
- fprintf(stderr,"ATH adjustment %f\n",glopts.athlevel);
-
- fprintf (stderr, "--------------------------------------------\n");
-}
-
-
-/************************************************************************
- *
- * usage
- *
- * PURPOSE: Writes command line syntax to the file specified by #stderr#
- *
- ************************************************************************/
-
-void usage (void)
-{ /* print syntax & exit */
- /* FIXME: maybe have an option to display better definitions of help codes, and
- long equivalents of the flags */
- fprintf (stdout, "\nToolame-DAB version %s\n (http://opendigitalradio.org)\n",
- toolameversion);
- fprintf (stdout, "MPEG Audio Layer II encoder for DAB\n\n");
- fprintf (stdout, "usage: \n");
- fprintf (stdout, "\t%s [options] (<infile>|-j <jackname>|-V <libvlc url>) <output>\n\n", programName);
-
- fprintf (stdout, "Options:\n");
- fprintf (stdout, "Input\n");
- fprintf (stdout, "\t-s sfrq input smpl rate in kHz (dflt %4.1f)\n",
- DFLT_SFQ);
- fprintf (stdout, "\t-a downmix from stereo to mono\n");
- fprintf (stdout, "\t-x force byte-swapping of input\n");
- fprintf (stdout, "\t-g swap channels of input file\n");
-
-#if defined(JACK_INPUT)
- fprintf (stdout, "\t-j use jack input\n");
-#else
- fprintf (stdout, "\t-j DISABLED: JACK input not compiled in\n");
-#endif
-
-#if defined(VLC_INPUT)
- fprintf (stdout, "\t-V use libvlc input\n");
-#else
- fprintf (stdout, "\t-V DISABLED: libvlc input not compiled in\n");
-#endif
-
- fprintf (stdout, "\t-W file when using libvlc input, write the ICY-Text to file\n");
- fprintf (stdout, "\t-L enable audio level display\n");
- fprintf (stdout, "Output\n");
- fprintf (stdout, "\t-m mode channel mode : s/d/j/m (dflt %4c)\n",
- DFLT_MOD);
- fprintf (stdout, "\t-y psy psychoacoustic model 0/1/2/3 (dflt %4u)\n",
- DFLT_PSY);
- fprintf (stdout, "\t-b br total bitrate in kbps (dflt 192)\n");
- fprintf (stdout, "\t-v lev vbr mode\n");
- fprintf (stdout, "\t-l lev ATH level (dflt 0)\n");
- fprintf (stdout, "Operation\n");
- // fprintf (stdout, "\t-f fast mode (turns off psy model)\n");
- // deprecate the -f switch. use "-y 0" instead.
- fprintf (stdout,
- "\t-q num quick mode. only calculate psy model every num frames\n");
- fprintf (stdout, "Misc\n");
- fprintf (stdout, "\t-d emp de-emphasis n/5/c (dflt %4c)\n",
- DFLT_EMP);
- fprintf (stdout, "\t-c mark as copyright\n");
- fprintf (stdout, "\t-o mark as original\n");
- fprintf (stdout, "\t-e add error protection\n");
- fprintf (stdout, "\t-r force padding bit/frame off\n");
- fprintf (stdout, "\t-p len "
- "enable PAD, and read len bytes of X-PAD data per frame\n");
- fprintf (stdout, "\t-P file "
- "read X-PAD data from mot-encoder from the specified file\n");
- fprintf (stdout, "\t-t talkativity 0=no messages (dflt 2)\n");
- fprintf (stdout, "Files\n");
- fprintf (stdout,
- "\tinput input sound file. (WAV,AIFF,PCM or use '/dev/stdin')\n");
- fprintf (stdout, "\toutput output bit stream of encoded audio\n");
- fprintf (stdout, "\t prefix with tcp:// to use a ZMQ output\n");
- fprintf (stdout, "\t Several ZMQ destinations can be given,\n");
- fprintf (stdout, "\t separated by semicolons.\n");
- fprintf (stdout,
- "\n\tAllowable bitrates for 16, 22.05 and 24kHz sample input\n");
- fprintf (stdout,
- "\t8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160\n");
- fprintf (stdout,
- "\n\tAllowable bitrates for 32, 44.1 and 48kHz sample input\n");
- fprintf (stdout,
- "\t32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384\n");
- exit (1);
-}
-
-/*********************************************
- * void short_usage(void)
- ********************************************/
-void short_usage (void)
-{
- /* print a bit of info about the program */
- fprintf (stderr, "Toolame-DAB version %s\n (http://opendigitalradio.org)\n",
- toolameversion);
- fprintf (stderr, "MPEG Audio Layer II encoder for DAB\n\n");
-#if defined(JACK_INPUT) && defined(VLC_INPUT)
- fprintf (stderr, "USAGE: %s [options] (<infile>|-j <jackname>|-V <libvlc url>) [output]\n\n", programName);
-#elif defined(JACK_INPUT)
- fprintf (stderr, "USAGE: %s [options] (<infile>|-j <jackname>) [output]\n\n", programName);
- fprintf (stderr, "VLC input not compiled in\n");
-#elif defined(VLC_INPUT)
- fprintf (stderr, "USAGE: %s [options] (<infile>|-V <libvlc url>) [output]\n\n", programName);
- fprintf (stderr, "JACK input not compiled in\n");
-#else
- fprintf (stderr, "USAGE: %s [options] <infile> [output]\n\n", programName);
- fprintf (stderr, "Neither JACK nor libVLC input compiled in\n");
-#endif
- fprintf (stderr, "Try \"%s -h\" for more information.\n", programName);
- exit (0);
-}
-
-/************************************************************************
- *
- * parse_args
- *
- * PURPOSE: Sets encoding parameters to the specifications of the
- * command line. Default settings are used for parameters
- * not specified in the command line.
- *
- * SEMANTICS: The command line is parsed according to the following
- * syntax:
- *
- * -j turns on JACK input
- * -V turns on libVLC input
- * -L turns on audio level display
- * -m is followed by the mode
- * -y is followed by the psychoacoustic model number
- * -s is followed by the sampling rate
- * -b is followed by the total bitrate, irrespective of the mode
- * -d is followed by the emphasis flag
- * -c is followed by the copyright/no_copyright flag
- * -o is followed by the original/not_original flag
- * -e is followed by the error_protection on/off flag
- * -f turns off psy model (fast mode)
- * -q <i> only calculate psy model every ith frame
- * -a downmix from stereo to mono
- * -r turn off padding bits in frames.
- * -x force byte swapping of input
- * -g swap the channels on an input file
- * -t talkativity. how verbose should the program be. 0 = no messages.
- *
- * If the input file is in AIFF format, the sampling frequency is read
- * from the AIFF header.
- *
- * The input and output filenames are read into #inpath# and #outpath#.
- *
- ************************************************************************/
-
-void parse_args (int argc, char **argv, frame_info * frame, int *psy,
- unsigned long *num_samples, char inPath[MAX_NAME_SIZE],
- char outPath[MAX_NAME_SIZE], char **mot_file, char **icy_file)
-{
- FLOAT srate;
- int brate;
- frame_header *header = frame->header;
- int err = 0, i = 0;
- long samplerate = 0;
-
- /* preset defaults */
- inPath[0] = '\0';
- outPath[0] = '\0';
- header->lay = DFLT_LAY;
- switch (DFLT_MOD) {
- case 's':
- header->mode = MPG_MD_STEREO;
- header->mode_ext = 0;
- break;
- case 'd':
- header->mode = MPG_MD_DUAL_CHANNEL;
- header->mode_ext = 0;
- break;
- /* in j-stereo mode, no default header->mode_ext was defined, gave error..
- now default = 2 added by MFC 14 Dec 1999. */
- case 'j':
- header->mode = MPG_MD_JOINT_STEREO;
- header->mode_ext = 2;
- break;
- case 'm':
- header->mode = MPG_MD_MONO;
- header->mode_ext = 0;
- break;
- default:
- fprintf (stderr, "%s: Bad mode dflt %c\n", programName, DFLT_MOD);
- abort ();
- }
- *psy = DFLT_PSY;
- if ((header->sampling_frequency =
- SmpFrqIndex ((long) (1000 * DFLT_SFQ), &header->version)) < 0) {
- fprintf (stderr, "%s: bad sfrq default %.2f\n", programName, DFLT_SFQ);
- abort ();
- }
- header->bitrate_index = 14;
- brate = 0;
- switch (DFLT_EMP) {
- case 'n':
- header->emphasis = 0;
- break;
- case '5':
- header->emphasis = 1;
- break;
- case 'c':
- header->emphasis = 3;
- break;
- default:
- fprintf (stderr, "%s: Bad emph dflt %c\n", programName, DFLT_EMP);
- abort ();
- }
- header->copyright = 0;
- header->original = 0;
- header->error_protection = FALSE;
- header->dab_extension = 0;
-
- glopts.input_select = INPUT_SELECT_WAV;
-
- /* process args */
- while (++i < argc && err == 0) {
- char c, *token, *arg, *nextArg;
- int argUsed;
-
- token = argv[i];
- if (*token++ == '-') {
- if (i + 1 < argc)
- nextArg = argv[i + 1];
- else
- nextArg = "";
- argUsed = 0;
- if (!*token) {
- /* The user wants to use stdin and/or stdout. */
- if (inPath[0] == '\0')
- strncpy (inPath, argv[i], MAX_NAME_SIZE);
- else if (outPath[0] == '\0')
- strncpy (outPath, argv[i], MAX_NAME_SIZE);
- }
- while ((c = *token++)) {
- if (*token /* NumericQ(token) */ )
- arg = token;
- else
- arg = nextArg;
- switch (c) {
- case 'm':
- argUsed = 1;
- if (*arg == 's') {
- header->mode = MPG_MD_STEREO;
- header->mode_ext = 0;
- } else if (*arg == 'd') {
- header->mode = MPG_MD_DUAL_CHANNEL;
- header->mode_ext = 0;
- } else if (*arg == 'j') {
- header->mode = MPG_MD_JOINT_STEREO;
- } else if (*arg == 'm') {
- header->mode = MPG_MD_MONO;
- header->mode_ext = 0;
- } else {
- fprintf (stderr, "%s: -m mode must be s/d/j/m not %s\n",
- programName, arg);
- err = 1;
- }
- break;
- case 'y':
- *psy = atoi (arg);
- argUsed = 1;
- break;
-
- case 'L':
- glopts.show_level = 1;
- break;
-
- case 's':
- argUsed = 1;
- srate = atof (arg);
- /* samplerate = rint( 1000.0 * srate ); $A */
- samplerate = (long) ((1000.0 * srate) + 0.5);
- if ((header->sampling_frequency =
- SmpFrqIndex ((long) samplerate, &header->version)) < 0)
- err = 1;
- break;
-
- case 'j':
- glopts.input_select = INPUT_SELECT_JACK;
- break;
-
- case 'b':
- argUsed = 1;
- brate = atoi (arg);
- break;
- case 'd':
- argUsed = 1;
- if (*arg == 'n')
- header->emphasis = 0;
- else if (*arg == '5')
- header->emphasis = 1;
- else if (*arg == 'c')
- header->emphasis = 3;
- else {
- fprintf (stderr, "%s: -d emp must be n/5/c not %s\n", programName,
- arg);
- err = 1;
- }
- break;
- case 'P':
- argUsed = 1;
- *mot_file = arg;
- break;
- case 'p':
- argUsed = 1;
- header->dab_length = atoi(arg);
- break;
- case 'c':
- header->copyright = 1;
- break;
- case 'o':
- header->original = 1;
- break;
- case 'e':
- header->error_protection = TRUE;
- break;
- case 'r':
- glopts.usepadbit = FALSE;
- header->padding = 0;
- break;
- case 'q':
- argUsed = 1;
- glopts.quickmode = TRUE;
- glopts.usepsy = TRUE;
- glopts.quickcount = atoi (arg);
- if (glopts.quickcount == 0) {
- /* just don't use psy model */
- glopts.usepsy = FALSE;
- glopts.quickcount = FALSE;
- }
- break;
- case 'a':
- glopts.downmix = TRUE;
- header->mode = MPG_MD_MONO;
- header->mode_ext = 0;
- break;
- case 'x':
- glopts.byteswap = TRUE;
- break;
- case 'v':
- argUsed = 1;
- glopts.vbr = TRUE;
- glopts.vbrlevel = atof (arg);
- glopts.usepadbit = FALSE; /* don't use padding for VBR */
- header->padding = 0;
- /* MFC Feb 2003: in VBR mode, joint stereo doesn't make
- any sense at the moment, as there are no noisy subbands
- according to bits_for_nonoise in vbr mode */
- header->mode = MPG_MD_STEREO; /* force stereo mode */
- header->mode_ext = 0;
- break;
- case 'V':
- glopts.input_select = INPUT_SELECT_VLC;
- break;
- case 'W':
- argUsed = 1;
- *icy_file = arg;
- break;
- case 'l':
- argUsed = 1;
- glopts.athlevel = atof(arg);
- break;
- case 'h':
- usage ();
- break;
- case 'g':
- glopts.channelswap = TRUE;
- break;
- case 't':
- argUsed = 1;
- glopts.verbosity = atoi (arg);
- break;
- default:
- fprintf (stderr, "%s: unrec option %c\n", programName, c);
- err = 1;
- break;
- }
- if (argUsed) {
- if (arg == token)
- token = ""; /* no more from token */
- else
- ++i; /* skip arg we used */
- arg = "";
- argUsed = 0;
- }
- }
- } else {
- if (inPath[0] == '\0')
- strcpy (inPath, argv[i]);
- else if (outPath[0] == '\0')
- strcpy (outPath, argv[i]);
- else {
- fprintf (stderr, "%s: excess arg %s\n", programName, argv[i]);
- err = 1;
- }
- }
- }
-
- /* Always enable DAB mode */
- header->error_protection = TRUE;
- header->dab_extension = 4;
- header->padding = 0;
- glopts.dab = TRUE;
-
- if (err)
- usage (); /* If err has occured, then call usage() */
-
- if (glopts.input_select != INPUT_SELECT_JACK && inPath[0] == '\0')
- usage (); /* If not in jack-mode and no file specified, then call usage() */
-
- if (outPath[0] == '\0') {
- /* replace old extension with new one, 1992-08-19, 1995-06-12 shn */
- new_ext (inPath, DFLT_EXT, outPath);
- }
-
- if (glopts.input_select == INPUT_SELECT_JACK) {
-#if defined(JACK_INPUT)
- musicin.jack_name = inPath;
- *num_samples = MAX_U_32_NUM;
-
- setup_jack(header, musicin.jack_name);
-#else
- fprintf(stderr, "JACK input not compiled in\n");
- exit(1);
-#endif
- }
- else if (glopts.input_select == INPUT_SELECT_WAV) {
- if (!strcmp (inPath, "-")) {
- musicin.wav_input = stdin; /* read from stdin */
- *num_samples = MAX_U_32_NUM;
- } else {
- if ((musicin.wav_input = fopen (inPath, "rb")) == NULL) {
- fprintf (stderr, "Could not find \"%s\".\n", inPath);
- exit (1);
- }
- parse_input_file (musicin.wav_input, inPath, header, num_samples);
- }
- }
- else if (glopts.input_select == INPUT_SELECT_VLC) {
- if (samplerate == 0) {
- fprintf (stderr, "Samplerate not specified\n");
- exit (1);
- }
- *num_samples = MAX_U_32_NUM;
- int channels = (header->mode == MPG_MD_MONO) ? 1 : 2;
-#if defined(VLC_INPUT)
- if (vlc_in_prepare(glopts.verbosity, samplerate, inPath, channels, *icy_file) != 0) {
- fprintf(stderr, "VLC initialisation failed\n");
- exit(1);
- }
-#else
- fprintf(stderr, "VLC input not compiled in\n");
- exit(1);
-#endif
- }
- else {
- fprintf(stderr, "INVALID INPUT\n");
- exit(1);
- }
-
-
- /* check for a valid bitrate */
- if (brate == 0)
- brate = bitrate[header->version][10];
-
- /* Check to see we have a sane value for the bitrate for this version */
- if ((header->bitrate_index = BitrateIndex (brate, header->version)) < 0)
- err = 1;
-
- if (header->dab_extension) {
- /* in 48 kHz (= MPEG-1) */
- /* if the bit rate per channel is less then 56 kbit/s, we have 2 scf-crc */
- /* else we have 4 scf-crc */
- /* in 24 kHz (= MPEG-2), we have 4 scf-crc */
- if (header->version == MPEG_AUDIO_ID && (brate / (header->mode == MPG_MD_MONO ? 1 : 2) < 56))
- header->dab_extension = 2;
- }
-
- bs.zmq_framesize = 3 * brate;
-
- /* All options are hunky dory, open the input audio file and
- return to the main drag */
- open_bit_stream_w (&bs, outPath, BUFFER_SIZE);
-}
-
-
void smr_dump(double smr[2][SBLIMIT], int nch) {
int ch, sb;
diff --git a/libtoolame-dab/toolame.h b/libtoolame-dab/toolame.h
index 4289ab5..d7f8198 100644
--- a/libtoolame-dab/toolame.h
+++ b/libtoolame-dab/toolame.h
@@ -1,16 +1,32 @@
+#ifndef __TOOLAME_H_
+#define __TOOLAME_H_
-void global_init (void);
-void proginfo (void);
-void short_usage (void);
+/* All exported functions shown here return zero
+ * on success */
-void obtain_parameters (frame_info *, int *, unsigned long *,
- char[MAX_NAME_SIZE], char[MAX_NAME_SIZE]);
-void parse_args (int, char **, frame_info *, int *, unsigned long *,
- char[MAX_NAME_SIZE], char[MAX_NAME_SIZE], char**, char**);
-void print_config (frame_info *, int *,
- char[MAX_NAME_SIZE], char[MAX_NAME_SIZE]);
-void usage (void);
+/* Initialise toolame encoding library. */
+int toolame_init(void);
+int toolame_enable_downmix_stereo(void);
+int toolame_enable_byteswap(void);
-void smr_dump(double smr[2][SBLIMIT], int nch);
+/* Set channel mode. Allowed values:
+ * s, d, j , and m
+ */
+int toolame_set_channel_mode(const char mode);
+
+/* Valid PSY models: 0 to 3 */
+int toolame_set_psy_model(int new_model);
+
+int toolame_set_bitrate(int brate);
+
+/* Enable PAD insertion from the specified file with length */
+int toolame_set_pad(int pad_len);
+
+int toolame_encode_frame(
+ short buffer[2][1152],
+ unsigned char* xpad_data,
+ unsigned char *output_buffer);
+
+#endif // __TOOLAME_H_
diff --git a/src/dabplus-enc.cpp b/src/dabplus-enc.cpp
index d0130fd..8abc82a 100644
--- a/src/dabplus-enc.cpp
+++ b/src/dabplus-enc.cpp
@@ -46,16 +46,23 @@ extern "C" {
extern "C" {
#include <fec.h>
+#include "libtoolame-dab/toolame.h"
}
+// Enumerate which encoder we can use
+enum class encoder_selection_t {
+ fdk_dabplus,
+ toolame_dab
+};
+
using namespace std;
void usage(const char* name) {
fprintf(stderr,
"dabplus-enc %s is a HE-AACv2 encoder for DAB+\n"
- "based on fdk-aac-dabplus that can read from"
- "JACK, ALSA or a file source\n"
- "and encode to a ZeroMQ output for ODR-DabMux.\n"
+ "based on fdk-aac-dabplus and a Toolame-based MPEG\n"
+ "encoder for DAB that can read from JACK, ALSA or\n"
+ "a file source and encode to a ZeroMQ output for ODR-DabMux.\n"
"(Experimental!)It can also use libvlc as an input.\n"
"\n"
"The -D option enables experimental sound card clock drift compensation.\n"
@@ -110,6 +117,7 @@ void usage(const char* name) {
" Drift compensation\n"
" -D, --drift-comp Enable ALSA/VLC sound card drift compensation.\n"
" Encoder parameters:\n"
+ " -a, --dab Encode in DAB and not in DAB+.\n"
" -b, --bitrate={ 8, 16, ..., 192 } Output bitrate in kbps. Must be a multiple of 8.\n"
" -A, --no-afterburner Disable AAC encoder quality increaser.\n"
" -c, --channels={ 1, 2 } Nb of input channels (default: 2).\n"
@@ -240,9 +248,11 @@ int prepare_aac_encoder(
int main(int argc, char *argv[])
{
- int subchannel_index = 8; //64kbps subchannel
+ int bitrate = 64; //64kbps subchannel
int ch=0;
+ encoder_selection_t selected_encoder = encoder_selection_t::fdk_dabplus;
+
// For the ALSA input
const char *alsa_device = NULL;
@@ -314,7 +324,7 @@ int main(int argc, char *argv[])
{"vlc-uri", required_argument, 0, 'v'},
{"write-icy-text", required_argument, 0, 'w'},
{"aaclc", no_argument, 0, 0 },
- {"afterburner", no_argument, 0, 'a'},
+ {"dab", no_argument, 0, 'a'},
{"drift-comp", no_argument, 0, 'D'},
{"fifo-silence", no_argument, 0, 3 },
{"help", no_argument, 0, 'h'},
@@ -361,13 +371,13 @@ int main(int argc, char *argv[])
inFifoSilence = true;
break;
case 'a':
- fprintf(stderr, "Warning, -a option does not exist anymore!\n");
+ selected_encoder = encoder_selection_t::toolame_dab;
break;
case 'A':
afterburner = false;
break;
case 'b':
- subchannel_index = atoi(optarg) / 8;
+ bitrate = atoi(optarg);
break;
case 'c':
channels = atoi(optarg);
@@ -464,15 +474,25 @@ int main(int argc, char *argv[])
return 1;
}
- if (subchannel_index < 1 || subchannel_index > 24) {
- fprintf(stderr, "Bad subchannel index: %d, must be between 1 and 24. Try other bitrate.\n",
- subchannel_index);
- return 1;
- }
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ int subchannel_index = bitrate / 8;
- if ( ! (sample_rate == 32000 || sample_rate == 48000)) {
- fprintf(stderr, "Invalid sample rate. Possible values are: 32000, 48000.\n");
- return 1;
+ if (subchannel_index < 1 || subchannel_index > 24) {
+ fprintf(stderr, "Bad subchannel index: %d, must be between 1 and 24. Try other bitrate.\n",
+ subchannel_index);
+ return 1;
+ }
+
+ if ( ! (sample_rate == 32000 || sample_rate == 48000)) {
+ fprintf(stderr, "Invalid sample rate. Possible values are: 32000, 48000.\n");
+ return 1;
+ }
+ }
+ else if (selected_encoder == encoder_selection_t::toolame_dab) {
+ if ( ! (sample_rate == 24000 || sample_rate == 48000)) {
+ fprintf(stderr, "Invalid sample rate. Possible values are: 24000, 48000.\n");
+ return 1;
+ }
}
if (padlen < 0) {
@@ -554,12 +574,46 @@ int main(int argc, char *argv[])
}
+ std::vector<uint8_t> input_buf;
+
HANDLE_AACENCODER encoder;
- if (prepare_aac_encoder(&encoder, subchannel_index, channels,
- sample_rate, afterburner, &aot) != 0) {
- fprintf(stderr, "Encoder preparation failed\n");
- return 1;
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ int subchannel_index = bitrate / 8;
+ if (prepare_aac_encoder(&encoder, subchannel_index, channels,
+ sample_rate, afterburner, &aot) != 0) {
+ fprintf(stderr, "Encoder preparation failed\n");
+ return 1;
+ }
+
+ if (aacEncInfo(encoder, &info) != AACENC_OK) {
+ fprintf(stderr, "Unable to get the encoder info\n");
+ return 1;
+ }
+
+ // Each DAB+ frame will need input_size audio bytes
+ const int input_size = channels * BYTES_PER_SAMPLE * info.frameLength;
+ fprintf(stderr, "DAB+ Encoding: framelen=%d (%dB)\n",
+ info.frameLength,
+ input_size);
+
+ input_buf.resize(input_size);
+ }
+ else if (selected_encoder == encoder_selection_t::toolame_dab) {
+ int err = toolame_init();
+
+ if (err == 0) {
+ toolame_set_bitrate(bitrate);
+ }
+
+ if (err) {
+ fprintf(stderr, "libtoolame-dab init failed: %d\n", err);
+ return err;
+ }
+
+ // TODO int toolame_set_pad(int pad_len);
+
+ input_buf.resize(2 * 1152);
}
/* We assume that we need to call the encoder
@@ -567,24 +621,13 @@ int main(int argc, char *argv[])
* frame. This information is used when the alsa drift compensation
* is active
*/
- const int enc_calls_per_output =
- (aot == AOT_DABPLUS_AAC_LC) ? sample_rate / 8000 : sample_rate / 16000;
-
+ int enc_calls_per_output = 1; // Valid for libtoolame-dab
- if (aacEncInfo(encoder, &info) != AACENC_OK) {
- fprintf(stderr, "Unable to get the encoder info\n");
- return 1;
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ enc_calls_per_output = (aot == AOT_DABPLUS_AAC_LC) ? sample_rate / 8000 : sample_rate / 16000;
}
- // Each DAB+ frame will need input_size audio bytes
- const int input_size = channels * BYTES_PER_SAMPLE * info.frameLength;
- fprintf(stderr, "DAB+ Encoding: framelen=%d (%dB)\n",
- info.frameLength,
- input_size);
-
- uint8_t input_buf[input_size];
-
- int max_size = 8*input_size + NUM_SAMPLES_PER_CALL;
+ int max_size = 8*input_buf.size() + NUM_SAMPLES_PER_CALL;
SampleQueue<uint8_t> queue(BYTES_PER_SAMPLE, channels, max_size);
@@ -661,11 +704,22 @@ int main(int argc, char *argv[])
}
}
- int outbuf_size = subchannel_index*120;
- uint8_t zmqframebuf[ZMQ_HEADER_SIZE + 24*120];
- zmq_frame_header_t *zmq_frame_header = (zmq_frame_header_t*)zmqframebuf;
+ int outbuf_size;
+ std::vector<uint8_t> zmqframebuf;
+ std::vector<uint8_t> outbuf;
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ outbuf_size = bitrate/8*120;
+ outbuf.resize(24*120);
+ zmqframebuf.resize(ZMQ_HEADER_SIZE + 24*120);
+ }
+ else if (selected_encoder == encoder_selection_t::toolame_dab) {
+ outbuf_size = 3 * bitrate;
+ outbuf.resize(outbuf_size);
+ zmqframebuf.resize(ZMQ_HEADER_SIZE + outbuf_size);
+ }
+
+ zmq_frame_header_t *zmq_frame_header = (zmq_frame_header_t*)&zmqframebuf[0];
- uint8_t outbuf[24*120];
unsigned char pad_buf[padlen + 1];
@@ -686,8 +740,6 @@ int main(int argc, char *argv[])
int out_identifier = OUT_BITSTREAM_DATA;
AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 };
- AACENC_InArgs in_args = { 0 };
- AACENC_OutArgs out_args = { 0 };
void *in_ptr[2], *out_ptr;
int in_size[2], in_elem_size[2];
int out_size, out_elem_size;
@@ -750,20 +802,20 @@ int main(int argc, char *argv[])
}
// -------------- Read Data
- memset(outbuf, 0x00, outbuf_size);
- memset(input_buf, 0x00, input_size);
+ memset(&outbuf[0], 0x00, outbuf_size);
+ memset(&input_buf[0], 0x00, input_buf.size());
ssize_t read;
if (infile) {
- read = file_in.read(input_buf, input_size);
+ read = file_in.read(&input_buf[0], input_buf.size());
if (read < 0) {
break;
}
- else if (read != input_size) {
+ else if (read != input_buf.size()) {
if (inFifoSilence && file_in.eof()) {
- memset(input_buf, 0, input_size);
- read = input_size;
- usleep((long)input_size * 1000000 /
+ memset(&input_buf[0], 0, input_buf.size());
+ read = input_buf.size();
+ usleep((long)input_buf.size() * 1000000 /
(BYTES_PER_SAMPLE * channels * sample_rate));
}
else {
@@ -786,9 +838,9 @@ int main(int argc, char *argv[])
}
size_t overruns;
- read = queue.pop(input_buf, input_size, &overruns); // returns bytes
+ read = queue.pop(input_buf, input_buf.size(), &overruns); // returns bytes
- if (read != input_size) {
+ if (read != input_buf.size()) {
status |= STATUS_UNDERRUN;
}
@@ -799,12 +851,12 @@ int main(int argc, char *argv[])
else {
vlc_in = &vlc_in_direct;
- read = vlc_in_direct.read(input_buf, input_size);
+ read = vlc_in_direct.read(input_buf, input_buf.size());
if (read < 0) {
fprintf(stderr, "Detected fault in VLC input!\n");
break;
}
- else if (read != input_size) {
+ else if (read != input_buf.size()) {
fprintf(stderr, "Short VLC read !\n");
break;
}
@@ -823,9 +875,9 @@ int main(int argc, char *argv[])
}
size_t overruns;
- read = queue.pop(input_buf, input_size, &overruns); // returns bytes
+ read = queue.pop(&input_buf[0], input_buf.size(), &overruns); // returns bytes
- if (read != input_size) {
+ if (read != input_buf.size()) {
status |= STATUS_UNDERRUN;
}
@@ -834,11 +886,11 @@ int main(int argc, char *argv[])
}
}
else {
- read = alsa_in_direct.read(input_buf, input_size);
+ read = alsa_in_direct.read(&input_buf[0], input_buf.size());
if (read < 0) {
break;
}
- else if (read != input_size) {
+ else if (read != input_buf.size()) {
fprintf(stderr, "Short alsa read !\n");
}
}
@@ -869,50 +921,80 @@ int main(int argc, char *argv[])
measured_silence_ms = 0;
}
- // -------------- AAC Encoding
-
- int calculated_padlen = ret > 0 ? pad_buf[padlen] : 0;
-
-
- in_ptr[0] = input_buf;
- in_ptr[1] = pad_buf + (padlen - calculated_padlen); // offset due to unused PAD bytes
- in_size[0] = read;
- in_size[1] = calculated_padlen;
- in_elem_size[0] = BYTES_PER_SAMPLE;
- in_elem_size[1] = sizeof(uint8_t);
- in_args.numInSamples = input_size/BYTES_PER_SAMPLE;
- in_args.numAncBytes = calculated_padlen;
+ int numOutBytes = 0;
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ AACENC_InArgs in_args = { 0 };
+ AACENC_OutArgs out_args = { 0 };
+ // -------------- AAC Encoding
+
+ const int calculated_padlen = ret > 0 ? pad_buf[padlen] : 0;
+ const int subchannel_index = bitrate / 8;
+
+ in_ptr[0] = &input_buf[0];
+ in_ptr[1] = pad_buf + (padlen - calculated_padlen); // offset due to unused PAD bytes
+ in_size[0] = read;
+ in_size[1] = calculated_padlen;
+ in_elem_size[0] = BYTES_PER_SAMPLE;
+ in_elem_size[1] = sizeof(uint8_t);
+ in_args.numInSamples = input_buf.size()/BYTES_PER_SAMPLE;
+ in_args.numAncBytes = calculated_padlen;
+
+ in_buf.bufs = (void**)&in_ptr;
+ in_buf.bufferIdentifiers = in_identifier;
+ in_buf.bufSizes = in_size;
+ in_buf.bufElSizes = in_elem_size;
+
+ out_ptr = &outbuf[0];
+ out_size = outbuf.size();
+ out_elem_size = 1;
+ out_buf.numBufs = 1;
+ out_buf.bufs = &out_ptr;
+ out_buf.bufferIdentifiers = &out_identifier;
+ out_buf.bufSizes = &out_size;
+ out_buf.bufElSizes = &out_elem_size;
+
+ AACENC_ERROR err;
+ if ((err = aacEncEncode(encoder, &in_buf, &out_buf, &in_args, &out_args))
+ != AACENC_OK) {
+ if (err == AACENC_ENCODE_EOF) {
+ fprintf(stderr, "encoder error: EOF reached\n");
+ break;
+ }
+ fprintf(stderr, "Encoding failed (%d)\n", err);
+ retval = 3;
+ break;
+ }
+ calls++;
- in_buf.bufs = (void**)&in_ptr;
- in_buf.bufferIdentifiers = in_identifier;
- in_buf.bufSizes = in_size;
- in_buf.bufElSizes = in_elem_size;
+ numOutBytes = out_args.numOutBytes;
+ }
+ else if (selected_encoder == encoder_selection_t::toolame_dab) {
+ const int calculated_padlen = ret > 0 ? pad_buf[padlen] : 0;
+ uint8_t *xpad_data = pad_buf + (padlen - calculated_padlen); // offset due to unused PAD bytes
- out_ptr = outbuf;
- out_size = sizeof(outbuf);
- out_elem_size = 1;
- out_buf.numBufs = 1;
- out_buf.bufs = &out_ptr;
- out_buf.bufferIdentifiers = &out_identifier;
- out_buf.bufSizes = &out_size;
- out_buf.bufElSizes = &out_elem_size;
+ short input_buffers[2][1152];
- AACENC_ERROR err;
- if ((err = aacEncEncode(encoder, &in_buf, &out_buf, &in_args, &out_args))
- != AACENC_OK) {
- if (err == AACENC_ENCODE_EOF) {
- fprintf(stderr, "encoder error: EOF reached\n");
- break;
+ if (channels == 1) {
+ memcpy(input_buffers[0], &input_buf[0], 1152);
}
- fprintf(stderr, "Encoding failed (%d)\n", err);
- retval = 3;
- break;
+ else if (channels == 2) {
+ for (int ch = 0; ch < 2; ch++) {
+ for (int i = 0; i < 1152; i++) {
+ input_buffers[ch][i] = input_buf[2*i + ch];
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "INTERNAL ERROR! invalid number of channels\n");
+ }
+
+ toolame_encode_frame(input_buffers, xpad_data, &outbuf[0]);
}
- calls++;
/* Check if the encoder has generated output data */
- if (out_args.numOutBytes != 0)
- {
+ if (numOutBytes != 0 and
+ selected_encoder == encoder_selection_t::fdk_dabplus) {
+
// Our timing code depends on this
if (calls != enc_calls_per_output) {
fprintf(stderr, "INTERNAL ERROR! calls=%d"
@@ -925,6 +1007,7 @@ int main(int argc, char *argv[])
int row, col;
unsigned char buf_to_rs_enc[110];
unsigned char rs_enc[10];
+ const int subchannel_index = bitrate / 8;
for(row=0; row < subchannel_index; row++) {
for(col=0;col < 110; col++) {
buf_to_rs_enc[col] = outbuf[subchannel_index * col + row];
@@ -937,25 +1020,32 @@ int main(int argc, char *argv[])
assert(subchannel_index * col + row < outbuf_size);
}
}
+ }
+ if (numOutBytes != 0) {
if (out_fh) {
- fwrite(outbuf, 1, outbuf_size, out_fh);
+ fwrite(&outbuf[0], 1, outbuf_size, out_fh);
}
else {
// ------------ ZeroMQ transmit
try {
zmq_frame_header->version = 1;
- zmq_frame_header->encoder = ZMQ_ENCODER_FDK;
+ if (selected_encoder == encoder_selection_t::fdk_dabplus) {
+ zmq_frame_header->encoder = ZMQ_ENCODER_FDK;
+ }
+ else if (selected_encoder == encoder_selection_t::toolame_dab) {
+ zmq_frame_header->encoder = ZMQ_ENCODER_TOOLAME;
+ }
zmq_frame_header->datasize = outbuf_size;
zmq_frame_header->audiolevel_left = peak_left;
zmq_frame_header->audiolevel_right = peak_right;
- assert(ZMQ_FRAME_SIZE(zmq_frame_header) <= NUMOF(zmqframebuf));
+ assert(ZMQ_FRAME_SIZE(zmq_frame_header) <= zmqframebuf.size());
memcpy(ZMQ_FRAME_DATA(zmq_frame_header),
- outbuf, outbuf_size);
+ &outbuf[0], outbuf_size);
- zmq_sock.send(zmqframebuf, ZMQ_FRAME_SIZE(zmq_frame_header),
+ zmq_sock.send(&zmqframebuf[0], ZMQ_FRAME_SIZE(zmq_frame_header),
ZMQ_DONTWAIT);
}
catch (zmq::error_t& e) {
@@ -970,7 +1060,10 @@ int main(int argc, char *argv[])
break;
}
}
+ }
+ if (numOutBytes != 0)
+ {
if (show_level) {
if (channels == 1) {
fprintf(stderr, "\rIn: [%-6s] %1s %1s %1s",
diff --git a/src/utils.h b/src/utils.h
index c75935f..a0ab1ae 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -35,6 +35,7 @@ struct zmq_frame_header_t
} __attribute__ ((packed));
#define ZMQ_ENCODER_FDK 1
+#define ZMQ_ENCODER_TOOLAME 2
#define ZMQ_HEADER_SIZE sizeof(struct zmq_frame_header_t)