Beispiel #1
0
pcm_reader_t *limiter_open(pcm_reader_t *reader)
{
    limiter_t *self;
    int n = pcm_get_format(reader)->channels_per_frame;
    size_t size = sizeof(limiter_t) + offsetof(limiter_t, buffers[n + 1]);

    if ((self = calloc(1, size)) == 0)
        return 0;
    self->src = reader;
    self->vtbl = &my_vtable;
    self->format = *pcm_get_format(reader);
    self->format.bits_per_channel = 32;
    return (pcm_reader_t *)self;
}
Beispiel #2
0
static int process2(extrapolater_t *self, void *buffer, unsigned nframes)
{
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    buffer_t *bp = &self->buffer[self->nbuffer];
    buffer_t *bbp = &self->buffer[self->nbuffer ^ 1];

    if (bp->count < 2 * LPC_ORDER) {
        size_t total = bp->count + bbp->count;
        if (bbp->count &&
            realloc_buffer(bbp, total * sfmt->bytes_per_frame) == 0)
        {
            memcpy(bbp->data + bbp->count * sfmt->channels_per_frame,
                   bp->data, bp->count * sfmt->bytes_per_frame);
            bbp->count = total;
            bp->count = 0;
            bp = bbp;
            self->nbuffer ^= 1;
        }
    }
    self->process = process3;

    if (bp->count >= 2 * LPC_ORDER)
        extrapolate(self, bp, buffer, nframes);
    else
        memset(buffer, 0, nframes * sfmt->bytes_per_frame);
    return nframes;
}
Beispiel #3
0
static int process1(extrapolater_t *self, void *buffer, unsigned nframes)
{
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    buffer_t *bp = &self->buffer[self->nbuffer ^ 1];

    assert(bp->count <= nframes);
    memcpy(buffer, bp->data, bp->count * sfmt->bytes_per_frame); 
    if (!fetch(self, nframes))
        self->process = process2;
    return bp->count;
}
Beispiel #4
0
static int extrapolate(extrapolater_t *self, const buffer_t *bp,
                        void *dst, unsigned nframes)
{
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    unsigned i, n = sfmt->channels_per_frame;
    float lpc[LPC_ORDER];

    for (i = 0; i < n; ++i) {
        vorbis_lpc_from_data(bp->data + i, lpc, bp->count, LPC_ORDER, n);
        vorbis_lpc_predict(lpc, &bp->data[i + n * (bp->count - LPC_ORDER)],
                           LPC_ORDER, (sample_t*)dst + i, nframes, n);
    }
    return nframes;
}
Beispiel #5
0
static int fetch(extrapolater_t *self, unsigned nframes)
{
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    buffer_t *bp = &self->buffer[self->nbuffer];
    int rc = 0;

    if (realloc_buffer(bp, nframes * sfmt->bytes_per_frame) == 0) {
        rc = pcm_read_frames(self->src, bp->data, nframes);
        bp->count = rc > 0 ? rc : 0;
    }
    if (rc > 0)
        self->nbuffer ^= 1;
    return bp->count;
}
Beispiel #6
0
static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes)
{
    pcm_float_converter_t *self = (pcm_float_converter_t *)reader;
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    nframes = pcm_read_frames(self->src, buffer, nframes);
    if (!(sfmt->sample_type & PCM_TYPE_FLOAT)) {
        int32_t *ip = buffer;
        float   *op = buffer;
        unsigned i, count = nframes * sfmt->channels_per_frame;
        for (i = 0; i < count; ++i)
            op[i] = ip[i] / 2147483648.0f;
    }
    return nframes;
}
Beispiel #7
0
int pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes)
{
    int n;
    unsigned count = 0;
    uint8_t *bp = data;
    unsigned bpf = pcm_get_format(r)->bytes_per_frame;

    do {
        n = r->vtbl->read_frames(r, bp, nframes - count);
        if (n > 0) {
            count += n;
            bp += n * bpf;
        }
    } while (n > 0 && count < nframes);
    return count;
}
Beispiel #8
0
pcm_reader_t *pcm_open_float_converter(pcm_reader_t *reader)
{
    pcm_float_converter_t *self = 0;
    pcm_sample_description_t *fmt;

    if ((self = calloc(1, sizeof(pcm_float_converter_t))) == 0)
        return 0;
    self->src = reader;
    self->vtbl = &my_vtable;
    memcpy(&self->format, pcm_get_format(reader), sizeof(self->format));
    fmt = &self->format;
    fmt->bits_per_channel = 32;
    fmt->sample_type = PCM_TYPE_FLOAT;
    fmt->bytes_per_frame = 4 * fmt->channels_per_frame;
    return (pcm_reader_t *)self;
}
Beispiel #9
0
static int process0(extrapolater_t *self, void *buffer, unsigned nframes)
{
    const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
    unsigned nchannels = sfmt->channels_per_frame;
    buffer_t *bp = &self->buffer[self->nbuffer];

    if (fetch(self, nframes) < 2 * LPC_ORDER)
        memset(buffer, 0, nframes * sfmt->bytes_per_frame);
    else {
        reverse_buffer(bp->data, bp->count, nchannels);
        extrapolate(self, bp, buffer, nframes);
        reverse_buffer(buffer, nframes, nchannels);
        reverse_buffer(bp->data, bp->count, nchannels);
    }
    self->process = bp->count ? process1 : process2;
    return nframes;
}
Beispiel #10
0
int main(int argc, char **argv)
{
    static m4af_io_callbacks_t m4af_io = {
        read_callback, write_callback, seek_callback, tell_callback
    };
    aacenc_param_ex_t params = { 0 };

    int result = 2;
    char *output_filename = 0;
    pcm_reader_t *reader = 0;
    HANDLE_AACENCODER encoder = 0;
    AACENC_InfoStruct aacinfo = { 0 };
    m4af_ctx_t *m4af = 0;
    const pcm_sample_description_t *sample_format;
    int frame_count = 0;
    int sbr_mode = 0;
    unsigned scale_shift = 0;

    setlocale(LC_CTYPE, "");
    setbuf(stderr, 0);

    if (parse_options(argc, argv, &params) < 0)
        return 1;

    if ((reader = open_input(&params)) == 0)
        goto END;

    sample_format = pcm_get_format(reader);

    sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
    if (sbr_mode && !aacenc_is_sbr_ratio_available()) {
        fprintf(stderr, "WARNING: Only dual-rate SBR is available "
                        "for this version\n");
        params.sbr_ratio = 2;
    }
    scale_shift = aacenc_is_dual_rate_sbr((aacenc_param_t*)&params);
    params.sbr_signaling =
        (params.transport_format == TT_MP4_LOAS) ? 2 :
        (params.transport_format == TT_MP4_RAW)  ? 1 : 0;
    if (sbr_mode && !scale_shift)
        params.sbr_signaling = 2;

    if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
                    &aacinfo) < 0)
        goto END;

    if (!params.output_filename) {
        const char *ext = params.transport_format ? ".aac" : ".m4a";
        output_filename = generate_output_filename(params.input_filename, ext);
        params.output_filename = output_filename;
    }

    if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
        aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
                       strerror(errno));
        goto END;
    }
    handle_signals();

    if (!params.transport_format) {
        uint32_t scale;
        unsigned framelen = aacinfo.frameLength;
        scale = sample_format->sample_rate >> scale_shift;
        if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
                                params.output_fp)) < 0)
            goto END;
        m4af_set_decoder_specific_info(m4af, 0,
                                       aacinfo.confBuf, aacinfo.confSize);
        m4af_set_fixed_frame_duration(m4af, 0,
                                      framelen >> scale_shift);
        m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
        m4af_set_priming_mode(m4af, params.gapless_mode + 1);
        m4af_begin_write(m4af);
    }
Beispiel #11
0
static
int encode(aacenc_param_ex_t *params, pcm_reader_t *reader,
           HANDLE_AACENCODER encoder, uint32_t frame_length, 
           m4af_ctx_t *m4af)
{
    int16_t *ibuf = 0, *ip;
    aacenc_frame_t obuf[2] = {{ 0 }}, *obp;
    unsigned flip = 0;
    int nread = 1;
    int rc = -1;
    int remaining, consumed;
    int frames_written = 0, encoded = 0;
    aacenc_progress_t progress = { 0 };
    const pcm_sample_description_t *fmt = pcm_get_format(reader);

    ibuf = malloc(frame_length * fmt->bytes_per_frame);
    aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);

    for (;;) {
        /*
         * Since we delay the write, we cannot just exit loop when interrupted.
         * Instead, we regard it as EOF.
         */
        if (g_interrupted)
            nread = 0;
        if (nread > 0) {
            if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
                fprintf(stderr, "ERROR: read failed\n");
                goto END;
            }
            if (!params->silent)
                aacenc_progress_update(&progress, pcm_get_position(reader),
                                       fmt->sample_rate * 2);
        }
        ip = ibuf;
        remaining = nread;
        do {
            obp = &obuf[flip];
            consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp);
            if (consumed < 0) goto END;
            if (consumed == 0 && obp->size == 0) goto DONE;
            if (obp->size == 0) break;

            remaining -= consumed;
            ip += consumed * fmt->channels_per_frame;
            flip ^= 1;
            /*
             * As we pad 1 frame at beginning and ending by our extrapolator,
             * we want to drop them.
             * We delay output by 1 frame by double buffering, and discard
             * second frame and final frame from the encoder.
             * Since sbr_header is included in the first frame (in case of
             * SBR), we cannot discard first frame. So we pick second instead.
             */
            ++encoded;
            if (encoded == 1 || encoded == 3)
                continue;
            obp = &obuf[flip];
            if (write_sample(params->output_fp, m4af, obp) < 0)
                goto END;
            ++frames_written;
        } while (remaining > 0);
    }
DONE:
    if (!params->silent)
        aacenc_progress_finish(&progress, pcm_get_position(reader));
    rc = frames_written;
END:
    if (ibuf) free(ibuf);
    if (obuf[0].data) free(obuf[0].data);
    if (obuf[1].data) free(obuf[1].data);
    return rc;
}
Beispiel #12
0
static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes)
{
    limiter_t *self = (limiter_t *)reader;
    unsigned i, n, res, nch = self->format.channels_per_frame;
    size_t bytes = nframes * pcm_get_format(self->src)->bytes_per_frame;
    buffer_t *ibp = &self->buffers[nch];
    float *obp = buffer;

    do {
        if (reserve_buffer(ibp, bytes, 1) < 0)
           return -1;
        res = pcm_read_frames(self->src, ibp->data, nframes);
        for (n = 0; n < nch; ++n) {
            float *ip = (float *)ibp->data, *x;
            buffer_t *bp = &self->buffers[n];
            unsigned end, limit;
            if (reserve_buffer(bp, bp->count + res, sizeof(float)) < 0)
                return -1;
            x = bp->data;
            for (i = 0; i < res; ++i)
                x[bp->count++] = pcm_clip(ip[i * nch + n], -3.0, 3.0);
            limit = bp->count;
            if (limit > 0 && res > 0) {
                float last = x[limit - 1];
                for (; limit > 0 && x[limit-1] * last > 0; --limit)
                    ;
            }
            end = bp->head;
            while (end < limit) {
                unsigned start, peak_pos;
                float peak;
                for (peak_pos = end; peak_pos < limit; ++peak_pos)
                    if (x[peak_pos] > 1.0f || x[peak_pos] < -1.0f)
                        break;
                if (peak_pos == limit)
                    break;
                start = peak_pos;
                peak = fabs(x[peak_pos]);
                while (start > bp->head && x[peak_pos] * x[start] >= 0.0f)
                    --start;
                ++start;
                for (end = peak_pos + 1; end < limit; ++end) {
                    float y;
                    if (x[peak_pos] * x[end] < 0.0f)
                        break;
                    y = fabs(x[end]);
                    if (y > peak) {
                        peak = y;
                        peak_pos = end;
                    }
                }
                if (peak < 2.0f) {
                    float a = (peak - 1.0f) / (peak * peak);
                    if (x[peak_pos] > 0.0f) a = -a;
                    for (i = start; i < end; ++i)
                        x[i] = x[i] + a * x[i] * x[i];
                } else {
                    float u = peak, v = 1.0f;
                    float a = (u - 2.0f * v) / (u * u * u);
                    float b = (3.0f * v - 2.0f * u) / (u * u);
                    if (x[peak_pos] < 0.0f) b = -b;
                    for (i = start; i < end; ++i)
                        x[i] = x[i] + b * x[i] * x[i] + a * x[i] * x[i] * x[i];
                }
            }
            bp->head = limit;
        }
        res = nframes;
        for (n = 0; n < nch; ++n)
            if (self->buffers[n].head < res)
                res = self->buffers[n].head;
        for (i = 0; i < res; ++i)
            for (n = 0; n < nch; ++n)
                *obp++ = ((float *)self->buffers[n].data)[i];
        if (res) {
            for (n = 0; n < nch; ++n) {
                buffer_t *bp = &self->buffers[n];
                float *p = bp->data;
                memmove(p, p + res, (bp->count - res) * sizeof(float));
                bp->count -= res;
                bp->head  -= res;
            }
        }
    } while (res == 0 && self->buffers[0].count);
    self->position += res;
    return res;
}
Beispiel #13
0
static const
pcm_sample_description_t *get_format(pcm_reader_t *reader)
{
    return pcm_get_format(get_source(reader));
}
Beispiel #14
0
static
pcm_reader_t *open_input(aacenc_param_ex_t *params)
{
    pcm_io_context_t io = { 0 };
    pcm_reader_t *reader = 0;
    struct stat stb = { 0 };

    if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) {
        aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename,
                       strerror(errno));
        goto FAIL;
    }
    io.cookie = params->input_fp;
    if (fstat(fileno(params->input_fp), &stb) == 0
            && (stb.st_mode & S_IFMT) == S_IFREG)
        io.vtbl = &pcm_io_vtbl;
    else
        io.vtbl = &pcm_io_vtbl_noseek;

    if (params->is_raw) {
        int bytes_per_channel;
        pcm_sample_description_t desc = { 0 };
        if (parse_raw_spec(params->raw_format, &desc) < 0) {
            fprintf(stderr, "ERROR: invalid raw-format spec\n");
            goto FAIL;
        }
        desc.sample_rate = params->raw_rate;
        desc.channels_per_frame = params->raw_channels;
        bytes_per_channel = (desc.bits_per_channel + 7) / 8;
        desc.bytes_per_frame = params->raw_channels * bytes_per_channel;
        if ((reader = raw_open(&io, &desc)) == 0) {
            fprintf(stderr, "ERROR: failed to open raw input\n");
            goto FAIL;
        }
    } else {
        int c;
        ungetc(c = getc(params->input_fp), params->input_fp);

        switch (c) {
        case 'R':
            if ((reader = wav_open(&io, params->ignore_length)) == 0) {
                fprintf(stderr, "ERROR: broken / unsupported input file\n");
                goto FAIL;
            }
            break;
        case 'c':
            params->source_tag_ctx.add = aacenc_add_tag_entry_to_store;
            params->source_tag_ctx.add_ctx = &params->source_tags;
            if ((reader = caf_open(&io,
                                   aacenc_translate_generic_text_tag,
                                   &params->source_tag_ctx)) == 0) {
                fprintf(stderr, "ERROR: broken / unsupported input file\n");
                goto FAIL;
            }
            break;
        default:
            fprintf(stderr, "ERROR: unsupported input file\n");
            goto FAIL;
        }
    }
    reader = pcm_open_native_converter(reader);
    if (reader && PCM_IS_FLOAT(pcm_get_format(reader)))
        reader = limiter_open(reader);
    if (reader && (reader = pcm_open_sint16_converter(reader)) != 0)
        reader = extrapolater_open(reader);
    return reader;
FAIL:
    return 0;
}
Beispiel #15
0
static void dspio_process_dma(struct dspio_state *state)
{
    int dma_cnt, nfr, in_fifo_cnt, out_fifo_cnt, i, j, tlocked;
    unsigned long long time_dst;
    double output_time_cur;
    sndbuf_t buf[PCM_MAX_BUF][SNDBUF_CHANS];
    static int warned;

    dma_cnt = in_fifo_cnt = out_fifo_cnt = 0;

    if (state->dma.running) {
	state->dma.stereo = sb_dma_samp_stereo();
	state->dma.rate = sb_get_dma_sampling_rate();
	state->dma.samp_signed = sb_dma_samp_signed();
	state->dma.dsp_fifo_enabled = sb_fifo_enabled();
	dma_cnt += state->dma.input ? dspio_drain_input(state) :
	    dspio_fill_output(state);
    }

    if (!state->output_running && !state->input_running)
	return;

    time_dst = GETusTIME(0);
    if (state->output_running) {
	output_time_cur = pcm_time_lock(state->dma_strm);
	tlocked = 1;
	nfr = calc_nframes(state, output_time_cur, time_dst);
    } else {
	nfr = 0;
	tlocked = 0;
    }
    for (i = 0; i < nfr; i++) {
	for (j = 0; j < state->dma.stereo + 1; j++) {
	    if (state->dma.running && !dspio_output_fifo_filled(state)) {
		if (!dspio_run_dma(state))
		    break;
		dma_cnt++;
	    }
	    if (!dspio_get_output_sample(state, &buf[i][j],
		    state->dma.is16bit))
		break;
#if 0
	    /* if speaker disabled, overwrite DMA data with silence */
	    /* on SB16 is not used */
	    if (!state->speaker)
		dma_get_silence(state->dma.samp_signed,
			state->dma.is16bit, &buf[i][j]);
#endif
	}
	if (j != state->dma.stereo + 1)
	    break;
	out_fifo_cnt++;
    }
    if (out_fifo_cnt && state->dma.rate) {
	pcm_write_interleaved(buf, out_fifo_cnt, state->dma.rate,
			  pcm_get_format(state->dma.is16bit,
					 state->dma.samp_signed),
			  state->dma.stereo + 1, state->dma_strm);
	output_time_cur = pcm_get_stream_time(state->dma_strm);
	if (state->dma.running && output_time_cur > time_dst - 1) {
	    pcm_clear_flag(state->dma_strm, PCM_FLAG_POST);
	    warned = 0;
	}
    }
    if (out_fifo_cnt < nfr) {
	/* not enough samples, see why */
	if (!sb_dma_active()) {
	    dspio_stop_output(state);
	} else {
	    if (nfr && !warned) {
		S_printf("SB: Output FIFO exhausted while DMA is still active (ol=%f)\n",
			 time_dst - output_time_cur);
		warned = 1;
	    }
	    if (state->dma.running)
		S_printf("SB: Output FIFO exhausted while DMA is running (no DACK?)\n");
	    /* DMA is active but currently not running and the FIFO is
	     * already exhausted. Normally we should flush the channel
	     * and stop the output timing.
	     * HACK: try to not flush the channel for as long as possible
	     * in a hope the PCM buffers are large enough to hold till
	     * the DMA is restarted. */
	    pcm_set_flag(state->dma_strm, PCM_FLAG_POST);
	    /* awake dosemu */
	    reset_idle(0);
	}
    }
    if (tlocked)
	pcm_time_unlock(state->dma_strm);

    /* TODO: sync also input time with PCM? */
    if (state->input_running)
	nfr = calc_nframes(state, state->input_time_cur, time_dst);
    else
	nfr = 0;
    if (nfr && state->i_started && sb_input_enabled()) {
	struct player_params params;
	params.rate = state->dma.rate;
	params.channels = state->dma.stereo + 1;
	params.format = pcm_get_format(state->dma.is16bit,
		state->dma.samp_signed);
	params.handle = state->i_handle;
	nfr = pcm_data_get_interleaved(buf, nfr, &params);
    }
    if (!state->i_started) {
	for (i = 0; i < nfr; i++) {
	    for (j = 0; j < state->dma.stereo + 1; j++)
		dma_get_silence(state->dma.samp_signed,
			state->dma.is16bit, &buf[i][j]);
	}
    }
    for (i = 0; i < nfr; i++) {
	for (j = 0; j < state->dma.stereo + 1; j++) {
	    if (sb_input_enabled()) {
		if (!dspio_put_input_sample(state, &buf[i][j],
			state->dma.is16bit))
		    break;
	    }
	}
	if (j == state->dma.stereo + 1)
	    in_fifo_cnt++;
	for (j = 0; j < state->dma.stereo + 1; j++) {
	    if (state->dma.running) {
		if (!dspio_run_dma(state))
		    break;
		dma_cnt++;
	    }
	}
	if (!state->input_running || (j != state->dma.stereo + 1))
	    break;
    }
    if (in_fifo_cnt) {
	if (state->dma.rate) {
	    state->input_time_cur += in_fifo_cnt *
		    pcm_frame_period_us(state->dma.rate);
	} else {
	    state->input_time_cur = time_dst;
	}
    }

    if (debug_level('S') >= 7 && (in_fifo_cnt || out_fifo_cnt || dma_cnt))
	S_printf("SB: Processed %i %i FIFO, %i DMA, or=%i dr=%i\n",
	     in_fifo_cnt, out_fifo_cnt, dma_cnt, state->output_running, state->dma.running);
}