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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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, ¶ms) < 0) return 1; if ((reader = open_input(¶ms)) == 0) goto END; sample_format = pcm_get_format(reader); sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms); 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*)¶ms); 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*)¶ms, 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); }
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; }
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; }
static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return pcm_get_format(get_source(reader)); }
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 = ¶ms->source_tags; if ((reader = caf_open(&io, aacenc_translate_generic_text_tag, ¶ms->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; }
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, ¶ms); } 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); }