/* * Process options */ static int sox_trim_getopts(sox_effect_t * effp, int argc, char **argv) { char *end; priv_t * trim = (priv_t *) effp->priv; --argc, ++argv; /* Do not know sample rate yet so hold off on completely parsing * time related strings. */ switch (argc) { case 2: end = argv[1]; if (*end == '=') { trim->end_is_absolute = sox_true; end++; } else trim->end_is_absolute = sox_false; trim->end_str = lsx_malloc(strlen(end)+1); strcpy(trim->end_str, end); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., trim->end_str, &trim->length, 't') == NULL) return lsx_usage(effp); case 1: trim->start_str = lsx_malloc(strlen(argv[0])+1); strcpy(trim->start_str,argv[0]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., trim->start_str, &trim->start, 't') == NULL) return lsx_usage(effp); break; default: return lsx_usage(effp); } return (SOX_SUCCESS); }
/* * Process options */ static int sox_trim_getopts(sox_effect_t * effp, int n, char **argv) { priv_t * trim = (priv_t *) effp->priv; /* Do not know sample rate yet so hold off on completely parsing * time related strings. */ switch (n) { case 2: trim->length_str = lsx_malloc(strlen(argv[1])+1); strcpy(trim->length_str,argv[1]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., trim->length_str, &trim->length, 't') == NULL) return lsx_usage(effp); case 1: trim->start_str = lsx_malloc(strlen(argv[0])+1); strcpy(trim->start_str,argv[0]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., trim->start_str, &trim->start, 't') == NULL) return lsx_usage(effp); break; default: return lsx_usage(effp); } return (SOX_SUCCESS); }
/* * Process options * * Don't do initialization now. * The 'info' fields are not yet filled in. */ static int sox_mcompand_getopts_1(comp_band_t * l, size_t n, char **argv) { char *s; size_t rates, i, commas; /* Start by checking the attack and decay rates */ for (s = argv[0], commas = 0; *s; ++s) if (*s == ',') ++commas; if (commas % 2 == 0) /* There must be an even number of attack/decay parameters */ { lsx_fail("compander: Odd number of attack & decay rate parameters"); return (SOX_EOF); } rates = 1 + commas/2; l->attackRate = lsx_malloc(sizeof(double) * rates); l->decayRate = lsx_malloc(sizeof(double) * rates); l->volume = lsx_malloc(sizeof(double) * rates); l->expectedChannels = rates; l->delay_buf = NULL; /* Now tokenise the rates string and set up these arrays. Keep them in seconds at the moment: we don't know the sample rate yet. */ s = strtok(argv[0], ","); i = 0; do { l->attackRate[i] = atof(s); s = strtok(NULL, ","); l->decayRate[i] = atof(s); s = strtok(NULL, ","); ++i; } while (s != NULL); if (!lsx_compandt_parse(&l->transfer_fn, argv[1], n>2 ? argv[2] : 0)) return SOX_EOF; /* Set the initial "volume" to be attibuted to the input channels. Unless specified, choose 1.0 (maximum) otherwise clipping will result if the user has seleced a long attack time */ for (i = 0; i < l->expectedChannels; ++i) { double v = n>=4 ? pow(10.0, atof(argv[3])/20) : 1.0; l->volume[i] = v; /* If there is a delay, store it. */ if (n >= 5) l->delay = atof(argv[4]); else l->delay = 0.0; } return (SOX_SUCCESS); }
static int sox_silence_start(sox_effect_t * effp) { priv_t *silence = (priv_t *)effp->priv; uint64_t temp; /* When you want to remove silence, small window sizes are * better or else RMS will look like non-silence at * aburpt changes from load to silence. */ silence->window_size = (effp->in_signal.rate / 50) * effp->in_signal.channels; silence->window = lsx_malloc(silence->window_size * sizeof(double)); clear_rms(effp); /* Now that we know sample rate, reparse duration. */ if (silence->start) { if (lsx_parsesamples(effp->in_signal.rate, silence->start_duration_str, &temp, 's') == NULL) return lsx_usage(effp); silence->start_duration = temp * effp->in_signal.channels; } if (silence->stop) { if (lsx_parsesamples(effp->in_signal.rate,silence->stop_duration_str, &temp,'s') == NULL) return lsx_usage(effp); silence->stop_duration = temp * effp->in_signal.channels; } if (silence->start) silence->mode = SILENCE_TRIM; else silence->mode = SILENCE_COPY; silence->start_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->start_duration); silence->start_holdoff_offset = 0; silence->start_holdoff_end = 0; silence->start_found_periods = 0; silence->stop_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->stop_duration); silence->stop_holdoff_offset = 0; silence->stop_holdoff_end = 0; silence->stop_found_periods = 0; effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ return(SOX_SUCCESS); }
static FILE * xfopen(char const * identifier, char const * mode, lsx_io_type * io_type) { *io_type = lsx_io_file; if (*identifier == '|') { FILE * f = NULL; #ifdef HAVE_POPEN #ifndef POPEN_MODE #define POPEN_MODE "r" #endif f = popen(identifier + 1, POPEN_MODE); *io_type = lsx_io_pipe; #else lsx_fail("this build of SoX cannot open pipes"); #endif return f; } else if (is_url(identifier)) { FILE * f = NULL; #ifdef HAVE_POPEN char const * const command_format = "wget --no-check-certificate -q -O- \"%s\""; char * command = lsx_malloc(strlen(command_format) + strlen(identifier)); sprintf(command, command_format, identifier); f = popen(command, POPEN_MODE); free(command); *io_type = lsx_io_url; #else lsx_fail("this build of SoX cannot open URLs"); #endif return f; } return fopen(identifier, mode); }
static event_t event_new() { event_t ev = lsx_malloc(sizeof(struct event_tag)); if (!ev) return 0; pthread_mutex_init(&ev->mutex, 0); pthread_cond_init(&ev->cond, 0); ev->triggered = sox_false; return ev; }
static int setup(sox_format_t * ft) { priv_t * p = (priv_t *)ft->priv; snd_pcm_hw_params_t * params = NULL; snd_pcm_format_mask_t * mask = NULL; snd_pcm_uframes_t min, max; unsigned n; int err; _(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)); _(snd_pcm_hw_params_malloc, (¶ms)); _(snd_pcm_hw_params_any, (p->pcm, params)); #if SND_LIB_VERSION >= 0x010009 /* Disable alsa-lib resampling: */ _(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0)); #endif _(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); _(snd_pcm_format_mask_malloc, (&mask)); /* Set format: */ snd_pcm_hw_params_get_format_mask(params, mask); _(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format)); _(snd_pcm_hw_params_set_format, (p->pcm, params, p->format)); snd_pcm_format_mask_free(mask), mask = NULL; n = ft->signal.rate; /* Set rate: */ _(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0)); ft->signal.rate = n; n = ft->signal.channels; /* Set channels: */ _(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n)); ft->signal.channels = n; /* Set buf_len > > sox_globals.bufsiz for no underrun: */ p->buf_len = sox_globals.bufsiz * 8 / NBYTES / ft->signal.channels; _(snd_pcm_hw_params_get_buffer_size_min, (params, &min)); _(snd_pcm_hw_params_get_buffer_size_max, (params, &max)); p->period = range_limit(p->buf_len, min, max) / 8; p->buf_len = p->period * 8; _(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0)); _(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len)); if (p->period * 2 > p->buf_len) { lsx_fail_errno(ft, SOX_EPERM, "buffer too small"); goto error; } _(snd_pcm_hw_params, (p->pcm, params)); /* Configure ALSA */ snd_pcm_hw_params_free(params), params = NULL; _(snd_pcm_prepare, (p->pcm)); p->buf_len *= ft->signal.channels; /* No longer in `frames' */ p->buf = lsx_malloc(p->buf_len * NBYTES); return SOX_SUCCESS; error: if (mask) snd_pcm_format_mask_free(mask); if (params) snd_pcm_hw_params_free(params); return SOX_EOF; }
/* * Processed signed long samples from ibuf to obuf. * Return number of samples processed. */ static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t *isamp, size_t *osamp) { priv_t * c = (priv_t *) effp->priv; comp_band_t * l; size_t len = min(*isamp, *osamp); size_t band, i; sox_sample_t *abuf, *bbuf, *cbuf, *oldabuf, *ibuf_copy; double out; if (c->band_buf_len < len) { c->band_buf1 = lsx_realloc(c->band_buf1,len*sizeof(sox_sample_t)); c->band_buf2 = lsx_realloc(c->band_buf2,len*sizeof(sox_sample_t)); c->band_buf3 = lsx_realloc(c->band_buf3,len*sizeof(sox_sample_t)); c->band_buf_len = len; } len -= len % effp->out_signal.channels; ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t)); memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t)); /* split ibuf into bands using filters, pipe each band through sox_mcompand_flow_1, then add back together and write to obuf */ memset(obuf,0,len * sizeof *obuf); for (band=0,abuf=ibuf_copy,bbuf=c->band_buf2,cbuf=c->band_buf1;band<c->nBands;++band) { l = &c->bands[band]; if (l->topfreq) crossover_flow(effp, &l->filter, abuf, bbuf, cbuf, len); else { bbuf = abuf; abuf = cbuf; } if (abuf == ibuf_copy) abuf = c->band_buf3; (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len, (size_t)effp->out_signal.channels); for (i=0;i<len;++i) { out = obuf[i] + abuf[i]; SOX_SAMPLE_CLIP_COUNT(out, effp->clips); obuf[i] = out; } oldabuf = abuf; abuf = cbuf; cbuf = oldabuf; } *isamp = *osamp = len; free(ibuf_copy); return SOX_SUCCESS; }
static int start(sox_effect_t * effp) { priv_t * p = (priv_t *)effp->priv; size_t max_delay; if (!p->max_arg) return SOX_EFF_NULL; if (effp->flow < p->argc) lsx_parsesamples(effp->in_signal.rate, p->argv[effp->flow], &p->buffer_size, 't'); lsx_parsesamples(effp->in_signal.rate, p->max_arg, &max_delay, 't'); p->buffer_index = p->delay = 0; p->pad = max_delay - p->buffer_size; p->buffer = lsx_malloc(p->buffer_size * sizeof(*p->buffer)); return SOX_SUCCESS; }
void sox_append_comments(sox_comments_t * comments, char const * comment) { char * end; if (comment) { while ((end = strchr(comment, '\n'))) { size_t len = end - comment; char * c = lsx_malloc((len + 1) * sizeof(*c)); strncpy(c, comment, len); c[len] = '\0'; sox_append_comment(comments, c); comment += len + 1; free(c); } if (*comment) sox_append_comment(comments, comment); } }
int lsx_enum_option(int c, lsx_enum_item const * items) { lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, sox_false); if (p == NULL) { size_t len = 1; char * set = lsx_malloc(len); *set = 0; for (p = items; p->text; ++p) { set = lsx_realloc(set, len += 2 + strlen(p->text)); strcat(set, ", "); strcat(set, p->text); } lsx_fail("-%c: `%s' is not one of: %s.", c, lsx_optarg, set + 2); free(set); return INT_MAX; } return p->value; }
static void start(sox_format_t * ft) { priv_t * sf = (priv_t *)ft->priv; int subtype = ft_enc(ft->encoding.bits_per_sample? ft->encoding.bits_per_sample : ft->signal.precision, ft->encoding.encoding); sf->log_buffer_ptr = sf->log_buffer = lsx_malloc((size_t)LOG_MAX); sf->sf_info = lsx_calloc(1, sizeof(SF_INFO)); /* Copy format info */ if (subtype) { if (strcmp(ft->filetype, "sndfile") == 0) sf->sf_info->format = name_to_format(ft->filename) | subtype; else sf->sf_info->format = name_to_format(ft->filetype) | subtype; } sf->sf_info->samplerate = ft->signal.rate; sf->sf_info->channels = ft->signal.channels; if (ft->signal.channels) sf->sf_info->frames = ft->signal.length / ft->signal.channels; }
static int open_audio(priv_t * ffmpeg, AVStream *st) { AVCodecContext *c; AVCodec *codec; c = st->codec; /* find the audio encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { lsx_fail("ffmpeg CODEC not found"); return SOX_EOF; } /* open it */ if (avcodec_open(c, codec) < 0) { lsx_fail("ffmpeg could not open CODEC"); return SOX_EOF; } ffmpeg->audio_buf_raw = lsx_malloc((size_t)AVCODEC_MAX_AUDIO_FRAME_SIZE + 32); ffmpeg->audio_buf_aligned = ALIGN16(ffmpeg->audio_buf_raw); /* ugly hack for PCM codecs (will be removed ASAP with new PCM support to compute the input frame size in samples */ if (c->frame_size <= 1) { ffmpeg->audio_input_frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / c->channels; switch(st->codec->codec_id) { case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: case CODEC_ID_PCM_U16BE: ffmpeg->audio_input_frame_size >>= 1; break; default: break; } } else
static int startread(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; size_t ReadSize; sox_bool ignore_length = ft->signal.length == SOX_IGNORE_LENGTH; int open_library_result; LSX_DLLIBRARY_OPEN( p, mad_dl, MAD_FUNC_ENTRIES, "MAD decoder library", mad_library_names, open_library_result); if (open_library_result) return SOX_EOF; p->mp3_buffer_size = sox_globals.bufsiz; p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); ft->signal.length = SOX_UNSPEC; if (ft->seekable) { #ifdef USING_ID3TAG read_comments(ft); rewind((FILE*)ft->fp); if (!ft->signal.length) #endif if (!ignore_length) ft->signal.length = mp3_duration_ms(ft); } p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); ft->encoding.encoding = SOX_ENCODING_MP3; /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size); if (ReadSize != p->mp3_buffer_size && ferror((FILE*)ft->fp)) return SOX_EOF; p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = 0; while (p->mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (sox_mp3_input(ft) == SOX_EOF) return SOX_EOF; continue; } /* Consume any ID3 tags */ sox_mp3_inputtag(ft); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = 0; } if (p->Stream.error) { lsx_fail_errno(ft,SOX_EOF,"No valid MP3 frame found"); return SOX_EOF; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: ft->signal.channels = MAD_NCHANNELS(&p->Frame.header); break; default: lsx_fail_errno(ft, SOX_EFMT, "Cannot determine number of channels"); return SOX_EOF; } p->FrameCount=1; p->mad_timer_add(&p->Timer,p->Frame.header.duration); p->mad_synth_frame(&p->Synth,&p->Frame); ft->signal.precision = MP3_MAD_PRECISION; ft->signal.rate=p->Synth.pcm.samplerate; if (ignore_length) ft->signal.length = SOX_UNSPEC; else { ft->signal.length = (uint64_t)(ft->signal.length * .001 * ft->signal.rate + .5); ft->signal.length *= ft->signal.channels; /* Keep separate from line above! */ } p->cursamp = 0; return SOX_SUCCESS; }
static int sox_fade_getopts(sox_effect_t * effp, int argc, char **argv) { priv_t * fade = (priv_t *) effp->priv; char t_char[2]; int t_argno; --argc, ++argv; if (argc < 1 || argc > 4) return lsx_usage(effp); /* because sample rate is unavailable at this point we store the * string off for later computations. */ if (sscanf(argv[0], "%1[qhltp]", t_char)) { fade->in_fadetype = *t_char; fade->out_fadetype = *t_char; argv++; argc--; } else { /* No type given. */ fade->in_fadetype = 'l'; fade->out_fadetype = 'l'; } fade->in_stop_str = lsx_malloc(strlen(argv[0])+1); strcpy(fade->in_stop_str,argv[0]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., fade->in_stop_str, &fade->in_stop, 't') == NULL) return lsx_usage(effp); fade->out_start_str = fade->out_stop_str = 0; for (t_argno = 1; t_argno < argc && t_argno < 3; t_argno++) { /* See if there is fade-in/fade-out times/curves specified. */ if(t_argno == 1) { fade->out_stop_str = lsx_malloc(strlen(argv[t_argno])+1); strcpy(fade->out_stop_str,argv[t_argno]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., fade->out_stop_str, &fade->out_stop, 't') == NULL) return lsx_usage(effp); } else { fade->out_start_str = lsx_malloc(strlen(argv[t_argno])+1); strcpy(fade->out_start_str,argv[t_argno]); /* Do a dummy parse to see if it will fail */ if (lsx_parsesamples(0., fade->out_start_str, &fade->out_start, 't') == NULL) return lsx_usage(effp); } } /* End for(t_argno) */ return(SOX_SUCCESS); }
/* * Prepare for processing. */ static int sox_echo_start(sox_effect_t * effp) { priv_t * echo = (priv_t *) effp->priv; int i; float sum_in_volume; long j; echo->maxsamples = 0; if ( echo->in_gain < 0.0 ) { lsx_fail("echo: gain-in must be positive!"); return (SOX_EOF); } if ( echo->in_gain > 1.0 ) { lsx_fail("echo: gain-in must be less than 1.0!"); return (SOX_EOF); } if ( echo->out_gain < 0.0 ) { lsx_fail("echo: gain-in must be positive!"); return (SOX_EOF); } for ( i = 0; i < echo->num_delays; i++ ) { echo->samples[i] = echo->delay[i] * effp->in_signal.rate / 1000.0; if ( echo->samples[i] < 1 ) { lsx_fail("echo: delay must be positive!"); return (SOX_EOF); } if ( echo->samples[i] > (ptrdiff_t)DELAY_BUFSIZ ) { lsx_fail("echo: delay must be less than %g seconds!", DELAY_BUFSIZ / effp->in_signal.rate ); return (SOX_EOF); } if ( echo->decay[i] < 0.0 ) { lsx_fail("echo: decay must be positive!" ); return (SOX_EOF); } if ( echo->decay[i] > 1.0 ) { lsx_fail("echo: decay must be less than 1.0!" ); return (SOX_EOF); } if ( echo->samples[i] > echo->maxsamples ) echo->maxsamples = echo->samples[i]; } echo->delay_buf = lsx_malloc(sizeof (double) * echo->maxsamples); for ( j = 0; j < echo->maxsamples; ++j ) echo->delay_buf[j] = 0.0; /* Be nice and check the hint with warning, if... */ sum_in_volume = 1.0; for ( i = 0; i < echo->num_delays; i++ ) sum_in_volume += echo->decay[i]; if ( sum_in_volume * echo->in_gain > 1.0 / echo->out_gain ) lsx_warn("echo: warning >>> gain-out can cause saturation of output <<<"); echo->counter = 0; echo->fade_out = echo->maxsamples; effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ return (SOX_SUCCESS); }
/* * Prepare processing. * Do all initializations. */ static int start(sox_effect_t* effp) { priv_t* p = (priv_t*)effp->priv; int result = SOX_SUCCESS; spx_int32_t int_val; float float_val; if (p->samples_per_frame) { p->buffer_end = p->samples_per_frame; } else { p->buffer_end = effp->in_signal.rate / p->frames_per_second; if (!p->buffer_end) { lsx_fail("frames_per_second too large for the current sample rate."); return SOX_EOF; } } p->buffer_opos = p->buffer_end; effp->out_signal.precision = 16; p->buffer = lsx_malloc(p->buffer_end * sizeof(p->buffer[0])); if (!p->buffer) { result = SOX_ENOMEM; goto Done; } p->sps = speex_preprocess_state_init(p->buffer_end, effp->in_signal.rate); if (!p->sps) { lsx_fail("Failed to initialize preprocessor DSP."); result = SOX_EOF; goto Done; } int_val = p->agc ? 1 : 2; speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC, &int_val); if (p->agc) { float_val = p->agc * 327.68f; speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC_LEVEL, &float_val); } int_val = p->denoise ? 1 : 2; speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DENOISE, &int_val); if (p->denoise) { int_val = -(spx_int32_t)p->denoise; speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &int_val); } int_val = p->dereverb ? 1 : 2; speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DEREVERB, &int_val); Done: if (result != SOX_SUCCESS) stop(effp); return result; }
static int start_read(sox_format_t * ft) { unsigned long header_size_ul = 0, num_samples_ul = 0; sox_encoding_t encoding = SOX_ENCODING_SIGN2; size_t header_size, bytes_read; size_t num_samples = 0; unsigned bytes_per_sample = 0; unsigned channels = 1; unsigned rate = 16000; char fldname[64], fldtype[16], fldsval[128]; char * buf; /* Magic header */ if (lsx_reads(ft, fldname, (size_t)8) || strncmp(fldname, "NIST_1A", (size_t)7) != 0) { lsx_fail_errno(ft, SOX_EHDR, "Sphere header does not begin with magic word `NIST_1A'"); return (SOX_EOF); } if (lsx_reads(ft, fldsval, (size_t)8)) { lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); return (SOX_EOF); } /* Determine header size, and allocate a buffer large enough to hold it. */ sscanf(fldsval, "%lu", &header_size_ul); buf = lsx_malloc(header_size = header_size_ul); /* Skip what we have read so far */ header_size -= 16; if (lsx_reads(ft, buf, header_size) == SOX_EOF) { lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); free(buf); return (SOX_EOF); } header_size -= (strlen(buf) + 1); while (strncmp(buf, "end_head", (size_t)8) != 0) { if (strncmp(buf, "sample_n_bytes", (size_t)14) == 0) sscanf(buf, "%63s %15s %u", fldname, fldtype, &bytes_per_sample); else if (strncmp(buf, "channel_count", (size_t)13) == 0) sscanf(buf, "%63s %15s %u", fldname, fldtype, &channels); else if (strncmp(buf, "sample_count ", (size_t)13) == 0) sscanf(buf, "%53s %15s %lu", fldname, fldtype, &num_samples_ul); else if (strncmp(buf, "sample_rate ", (size_t)12) == 0) sscanf(buf, "%53s %15s %u", fldname, fldtype, &rate); else if (strncmp(buf, "sample_coding", (size_t)13) == 0) { sscanf(buf, "%63s %15s %127s", fldname, fldtype, fldsval); if (!strcasecmp(fldsval, "ulaw") || !strcasecmp(fldsval, "mu-law")) encoding = SOX_ENCODING_ULAW; else if (!strcasecmp(fldsval, "pcm")) encoding = SOX_ENCODING_SIGN2; else { lsx_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval); free(buf); return SOX_EOF; } } else if (strncmp(buf, "sample_byte_format", (size_t)18) == 0) { sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval); if (strcmp(fldsval, "01") == 0) /* Data is little endian. */ ft->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; else if (strcmp(fldsval, "10") == 0) /* Data is big endian. */ ft->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; else if (strcmp(fldsval, "1")) { lsx_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval); free(buf); return SOX_EOF; } } if (lsx_reads(ft, buf, header_size) == SOX_EOF) { lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); free(buf); return (SOX_EOF); } header_size -= (strlen(buf) + 1); } if (!bytes_per_sample) bytes_per_sample = encoding == SOX_ENCODING_ULAW? 1 : 2; while (header_size) { bytes_read = lsx_readbuf(ft, buf, header_size); if (bytes_read == 0) { free(buf); return (SOX_EOF); } header_size -= bytes_read; } free(buf); if (ft->seekable) { /* Check first four bytes of data to see if it's shorten compressed. */ char shorten_check[4]; if (lsx_readchars(ft, shorten_check, sizeof(shorten_check))) return SOX_EOF; lsx_seeki(ft, -(off_t)sizeof(shorten_check), SEEK_CUR); if (!memcmp(shorten_check, "ajkg", sizeof(shorten_check))) { lsx_fail_errno(ft, SOX_EFMT, "File uses shorten compression, cannot handle this."); return (SOX_EOF); } } num_samples = num_samples_ul; return lsx_check_read_params(ft, channels, (sox_rate_t)rate, encoding, bytes_per_sample << 3, (uint64_t)num_samples * channels, sox_true); }
static int start_write(sox_format_t * const ft) { priv_t * p = (priv_t *)ft->priv; FLAC__StreamEncoderState status; unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */ if (ft->encoding.compression != HUGE_VAL) { compression_level = ft->encoding.compression; if (compression_level != ft->encoding.compression || compression_level > MAX_COMPRESSION) { lsx_fail_errno(ft, SOX_EINVAL, "FLAC compression level must be a whole number from 0 to %i", MAX_COMPRESSION); return SOX_EOF; } } p->encoder = FLAC__stream_encoder_new(); if (p->encoder == NULL) { lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder instance"); return SOX_EOF; } p->decoded_samples = lsx_malloc(sox_globals.bufsiz * sizeof(FLAC__int32)); p->bits_per_sample = ft->encoding.bits_per_sample; lsx_report("encoding at %i bits per sample", p->bits_per_sample); FLAC__stream_encoder_set_channels(p->encoder, ft->signal.channels); FLAC__stream_encoder_set_bits_per_sample(p->encoder, p->bits_per_sample); FLAC__stream_encoder_set_sample_rate(p->encoder, (unsigned)(ft->signal.rate + .5)); { /* Check if rate is streamable: */ static const unsigned streamable_rates[] = {8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; size_t i; sox_bool streamable = sox_false; for (i = 0; !streamable && i < array_length(streamable_rates); ++i) streamable = (streamable_rates[i] == ft->signal.rate); if (!streamable) { lsx_report("non-standard rate; output may not be streamable"); FLAC__stream_encoder_set_streamable_subset(p->encoder, sox_false); } } #if FLAC_API_VERSION_CURRENT >= 10 FLAC__stream_encoder_set_compression_level(p->encoder, compression_level); #else { static struct { unsigned blocksize; FLAC__bool do_exhaustive_model_search; FLAC__bool do_mid_side_stereo; FLAC__bool loose_mid_side_stereo; unsigned max_lpc_order; unsigned max_residual_partition_order; unsigned min_residual_partition_order; } const options[MAX_COMPRESSION + 1] = { {1152, sox_false, sox_false, sox_false, 0, 2, 2}, {1152, sox_false, sox_true, sox_true, 0, 2, 2}, {1152, sox_false, sox_true, sox_false, 0, 3, 0}, {4608, sox_false, sox_false, sox_false, 6, 3, 3}, {4608, sox_false, sox_true, sox_true, 8, 3, 3}, {4608, sox_false, sox_true, sox_false, 8, 3, 3}, {4608, sox_false, sox_true, sox_false, 8, 4, 0}, {4608, sox_true, sox_true, sox_false, 8, 6, 0}, {4608, sox_true, sox_true, sox_false, 12, 6, 0}, }; #define SET_OPTION(x) do {\ lsx_report(#x" = %i", options[compression_level].x); \ FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\ } while (0) SET_OPTION(blocksize); SET_OPTION(do_exhaustive_model_search); SET_OPTION(max_lpc_order); SET_OPTION(max_residual_partition_order); SET_OPTION(min_residual_partition_order); if (ft->signal.channels == 2) { SET_OPTION(do_mid_side_stereo); SET_OPTION(loose_mid_side_stereo); } #undef SET_OPTION } #endif if (ft->signal.length != 0) { FLAC__stream_encoder_set_total_samples_estimate(p->encoder, (FLAC__uint64)(ft->signal.length / ft->signal.channels)); p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); if (p->metadata[p->num_metadata] == NULL) { lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table template"); return SOX_EOF; } { #if FLAC_API_VERSION_CURRENT >= 8 if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p->metadata[p->num_metadata], (unsigned)(10 * ft->signal.rate + .5), (FLAC__uint64)(ft->signal.length/ft->signal.channels))) { #else size_t samples = 10 * ft->signal.rate; size_t total_samples = ft->signal.length/ft->signal.channels; if (!FLAC__metadata_object_seektable_template_append_spaced_points(p->metadata[p->num_metadata], total_samples / samples + (total_samples % samples != 0), (FLAC__uint64)total_samples)) { #endif lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table points"); return SOX_EOF; } } p->metadata[p->num_metadata]->is_last = sox_false; /* the encoder will set this for us */ ++p->num_metadata; } if (ft->oob.comments) { /* Make the comment structure */ FLAC__StreamMetadata_VorbisComment_Entry entry; int i; p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); for (i = 0; ft->oob.comments[i]; ++i) { static const char prepend[] = "Comment="; char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text)); /* Prepend `Comment=' if no field-name already in the comment */ if (!strchr(ft->oob.comments[i], '=')) strcpy(text, prepend); entry.entry = (FLAC__byte *) strcat(text, ft->oob.comments[i]); entry.length = strlen(text); FLAC__metadata_object_vorbiscomment_append_comment(p->metadata[p->num_metadata], entry, /*copy= */ sox_true); free(text); } ++p->num_metadata; } if (p->num_metadata) FLAC__stream_encoder_set_metadata(p->encoder, p->metadata, p->num_metadata); #if FLAC_API_VERSION_CURRENT <= 7 FLAC__stream_encoder_set_write_callback(p->encoder, flac_stream_encoder_write_callback); FLAC__stream_encoder_set_metadata_callback(p->encoder, flac_stream_encoder_metadata_callback); FLAC__stream_encoder_set_client_data(p->encoder, ft); status = FLAC__stream_encoder_init(p->encoder); #else status = FLAC__stream_encoder_init_stream(p->encoder, flac_stream_encoder_write_callback, flac_stream_encoder_seek_callback, flac_stream_encoder_tell_callback, flac_stream_encoder_metadata_callback, ft); #endif if (status != FLAC__STREAM_ENCODER_OK) { lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamEncoderStateString[status]); return SOX_EOF; } return SOX_SUCCESS; } static size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, size_t const len) { priv_t * p = (priv_t *)ft->priv; unsigned i; for (i = 0; i < len; ++i) { long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips); p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample); switch (p->bits_per_sample) { case 8: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips); break; case 16: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips); break; case 24: p->decoded_samples[i] = /* sign extension: */ SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8; p->decoded_samples[i] >>= 8; break; case 32: p->decoded_samples[i] = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips); break; } } FLAC__stream_encoder_process_interleaved(p->encoder, p->decoded_samples, (unsigned) len / ft->signal.channels); return FLAC__stream_encoder_get_state(p->encoder) == FLAC__STREAM_ENCODER_OK ? len : 0; }
/* * Process either isamp or osamp samples, whichever is smaller. */ static int sox_pan_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t *isamp, size_t *osamp) { priv_t * pan = (priv_t *) effp->priv; size_t len, done; sox_sample_t *ibuf_copy; char ich, och; double left, right, direction, hdir; ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t)); memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t)); direction = pan->direction; /* -1 <= direction <= 1 */ hdir = 0.5 * direction; /* -0.5 <= hdir <= 0.5 */ left = 0.5 - hdir; /* 0 <= left <= 1 */ right = 0.5 + hdir; /* 0 <= right <= 1 */ ich = effp->in_signal.channels; och = effp->out_signal.channels; len = min(*osamp/och,*isamp/ich); /* report back how much is processed. */ *isamp = len*ich; *osamp = len*och; /* 9 different cases to handle: (1,2,4) X (1,2,4) */ switch (och) { case 1: /* pan on mono channel... not much sense. just avg. */ switch (ich) { case 1: /* simple copy */ for (done=0; done<len; done++) *obuf++ = *ibuf_copy++; break; case 2: /* average 2 */ for (done=0; done<len; done++) { double f; f = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); *obuf++ = f; ibuf_copy += 2; } break; case 4: /* average 4 */ for (done=0; done<len; done++) { double f; f = 0.25*ibuf_copy[0] + 0.25*ibuf_copy[1] + 0.25*ibuf_copy[2] + 0.25*ibuf_copy[3]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); *obuf++ = f; ibuf_copy += 4; } break; default: UNEXPECTED_CHANNELS; break; } /* end first switch in channel */ break; case 2: switch (ich) { case 1: /* linear */ for (done=0; done<len; done++) { double f; f = left * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = right * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; obuf += 2; ibuf_copy++; } break; case 2: /* linear panorama. * I'm not sure this is the right way to do it. */ if (direction <= 0.0) /* to the left */ { register double volume, cll, clr, cr; volume = 1.0 - 0.5*direction; cll = volume*(1.5-left); clr = volume*(left-0.5); cr = volume*(1.0+direction); for (done=0; done<len; done++) { double f; f = cll * ibuf_copy[0] + clr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = cr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; obuf += 2; ibuf_copy += 2; } } else /* to the right */ { register double volume, cl, crl, crr; volume = 1.0 + 0.5*direction; cl = volume*(1.0-direction); crl = volume*(right-0.5); crr = volume*(1.5-right); for (done=0; done<len; done++) { double f; f = cl * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = crl * ibuf_copy[0] + crr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; obuf += 2; ibuf_copy += 2; } } break; case 4: if (direction <= 0.0) /* to the left */ { register double volume, cll, clr, cr; volume = 1.0 - 0.5*direction; cll = volume*(1.5-left); clr = volume*(left-0.5); cr = volume*(1.0+direction); for (done=0; done<len; done++) { register double ibuf0, ibuf1, f; /* build stereo signal */ ibuf0 = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[2]; ibuf1 = 0.5*ibuf_copy[1] + 0.5*ibuf_copy[3]; /* pan it */ f = cll * ibuf0 + clr * ibuf1; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = cr * ibuf1; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; obuf += 2; ibuf_copy += 4; } } else /* to the right */ { register double volume, cl, crl, crr; volume = 1.0 + 0.5*direction; cl = volume*(1.0-direction); crl = volume*(right-0.5); crr = volume*(1.5-right); for (done=0; done<len; done++) { register double ibuf0, ibuf1, f; ibuf0 = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[2]; ibuf1 = 0.5*ibuf_copy[1] + 0.5*ibuf_copy[3]; f = cl * ibuf0; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = crl * ibuf0 + crr * ibuf1; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; obuf += 2; ibuf_copy += 4; } } break; default: UNEXPECTED_CHANNELS; break; } /* end second switch in channel */ break; case 4: switch (ich) { case 1: /* linear */ { register double cr, cl; cl = 0.5*left; cr = 0.5*right; for (done=0; done<len; done++) { double f; f = cl * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[2] = obuf[0] = f; f = cr * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); ibuf_copy[3] = obuf[1] = f; obuf += 4; ibuf_copy++; } } break; case 2: /* simple linear panorama */ if (direction <= 0.0) /* to the left */ { register double volume, cll, clr, cr; volume = 0.5 - 0.25*direction; cll = volume * (1.5-left); clr = volume * (left-0.5); cr = volume * (1.0+direction); for (done=0; done<len; done++) { double f; f = cll * ibuf_copy[0] + clr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[2] = obuf[0] = f; f = cr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); ibuf_copy[3] = obuf[1] = f; obuf += 4; ibuf_copy += 2; } } else /* to the right */ { register double volume, cl, crl, crr; volume = 0.5 + 0.25*direction; cl = volume * (1.0-direction); crl = volume * (right-0.5); crr = volume * (1.5-right); for (done=0; done<len; done++) { double f; f = cl * ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[2] = obuf[0] =f ; f = crl * ibuf_copy[0] + crr * ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); ibuf_copy[3] = obuf[1] = f; obuf += 4; ibuf_copy += 2; } } break; case 4: /* maybe I could improve the formula to reverse... also, turn only by quarters. */ if (direction <= 0.0) /* to the left */ { register double cown, cright; cright = -direction; cown = 1.0 + direction; for (done=0; done<len; done++) { double f; f = cown*ibuf_copy[0] + cright*ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = cown*ibuf_copy[1] + cright*ibuf_copy[3]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; f = cown*ibuf_copy[2] + cright*ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[2] = f; f = cown*ibuf_copy[3] + cright*ibuf_copy[2]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[3] = f; obuf += 4; ibuf_copy += 4; } } else /* to the right */ { register double cleft, cown; cleft = direction; cown = 1.0 - direction; for (done=0; done<len; done++) { double f; f = cleft*ibuf_copy[2] + cown*ibuf_copy[0]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[0] = f; f = cleft*ibuf_copy[0] + cown*ibuf_copy[1]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[1] = f; f = cleft*ibuf_copy[3] + cown*ibuf_copy[2]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[2] = f; f = cleft*ibuf_copy[1] + cown*ibuf_copy[3]; SOX_SAMPLE_CLIP_COUNT(f, effp->clips); obuf[3] = f; obuf += 4; ibuf_copy += 4; } } break; default: UNEXPECTED_CHANNELS; break; } /* end third switch in channel */ break; default: UNEXPECTED_CHANNELS; break; } /* end switch out channel */ free(ibuf_copy - len * ich); return SOX_SUCCESS; }
/* common r/w initialization code */ static int ossinit(sox_format_t * ft) { int sampletype, samplesize, dsp_stereo; int tmp, rc; priv_t *file = (priv_t *)ft->priv; if (ft->encoding.bits_per_sample == 8) { sampletype = AFMT_U8; samplesize = 8; if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_UNSIGNED; if (ft->encoding.encoding != SOX_ENCODING_UNSIGNED) { lsx_report("OSS driver only supports unsigned with bytes"); lsx_report("Forcing to unsigned"); ft->encoding.encoding = SOX_ENCODING_UNSIGNED; } } else if (ft->encoding.bits_per_sample == 16) { /* Attempt to use endian that user specified */ if (ft->encoding.reverse_bytes) sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; else sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; samplesize = 16; if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_SIGN2; if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { lsx_report("OSS driver only supports signed with words"); lsx_report("Forcing to signed linear"); ft->encoding.encoding = SOX_ENCODING_SIGN2; } } else { /* Attempt to use endian that user specified */ if (ft->encoding.reverse_bytes) sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; else sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; samplesize = 16; ft->encoding.bits_per_sample = 16; ft->encoding.encoding = SOX_ENCODING_SIGN2; lsx_report("OSS driver only supports bytes and words"); lsx_report("Forcing to signed linear word"); } if (ft->signal.channels > 2) ft->signal.channels = 2; if (ioctl(fileno(ft->fp), (size_t) SNDCTL_DSP_RESET, 0) < 0) { lsx_fail_errno(ft,SOX_EOF,"Unable to reset OSS driver. Possibly accessing an invalid file/device"); return(SOX_EOF); } /* Query the supported formats and find the best match */ rc = ioctl(fileno(ft->fp), SNDCTL_DSP_GETFMTS, &tmp); if (rc == 0) { if ((tmp & sampletype) == 0) { /* is 16-bit supported? */ if (samplesize == 16 && (tmp & (AFMT_S16_LE|AFMT_S16_BE)) == 0) { /* Must not like 16-bits, try 8-bits */ ft->encoding.bits_per_sample = 8; ft->encoding.encoding = SOX_ENCODING_UNSIGNED; lsx_report("OSS driver doesn't like signed words"); lsx_report("Forcing to unsigned bytes"); tmp = sampletype = AFMT_U8; samplesize = 8; } /* is 8-bit supported */ else if (samplesize == 8 && (tmp & AFMT_U8) == 0) { ft->encoding.bits_per_sample = 16; ft->encoding.encoding = SOX_ENCODING_SIGN2; lsx_report("OSS driver doesn't like unsigned bytes"); lsx_report("Forcing to signed words"); sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; samplesize = 16; } /* determine which 16-bit format to use */ if (samplesize == 16 && (tmp & sampletype) == 0) { /* Either user requested something not supported * or hardware doesn't support machine endian. * Force to opposite as the above test showed * it supports at least one of the two endians. */ sampletype = (sampletype == AFMT_S16_BE) ? AFMT_S16_LE : AFMT_S16_BE; ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; } } tmp = sampletype; rc = ioctl(fileno(ft->fp), SNDCTL_DSP_SETFMT, &tmp); } /* Give up and exit */ if (rc < 0 || tmp != sampletype) { lsx_fail_errno(ft,SOX_EOF,"Unable to set the sample size to %d", samplesize); return (SOX_EOF); } if (ft->signal.channels == 2) dsp_stereo = 1; else dsp_stereo = 0; tmp = dsp_stereo; if (ioctl(fileno(ft->fp), SNDCTL_DSP_STEREO, &tmp) < 0) { lsx_warn("Couldn't set to %s", dsp_stereo? "stereo":"mono"); dsp_stereo = 0; } if (tmp != dsp_stereo) ft->signal.channels = tmp + 1; tmp = ft->signal.rate; if (ioctl (fileno(ft->fp), SNDCTL_DSP_SPEED, &tmp) < 0 || (int)ft->signal.rate != tmp) { /* If the rate the sound card is using is not within 1% of what * the user specified then override the user setting. * The only reason not to always override this is because of * clock-rounding problems. Sound cards will sometimes use * things like 44101 when you ask for 44100. No need overriding * this and having strange output file rates for something that * we can't hear anyways. */ if ((int)ft->signal.rate - tmp > (tmp * .01) || tmp - (int)ft->signal.rate > (tmp * .01)) ft->signal.rate = tmp; } /* Find out block size to use last because the driver could compute * its size based on specific rates/formats. */ file->size = 0; ioctl (fileno(ft->fp), SNDCTL_DSP_GETBLKSIZE, &file->size); if (file->size < 4 || file->size > 65536) { lsx_fail_errno(ft,SOX_EOF,"Invalid audio buffer size %lu", (unsigned long)file->size); return (SOX_EOF); } file->count = 0; file->pos = 0; file->buf = lsx_malloc(file->size); if (ioctl(fileno(ft->fp), (size_t) SNDCTL_DSP_SYNC, NULL) < 0) { lsx_fail_errno(ft,SOX_EOF,"Unable to sync dsp"); return (SOX_EOF); } /* Change to non-buffered I/O */ setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * file->size); return(SOX_SUCCESS); }