/* libmpg123: MPEG Audio Decoder library copyright 1995-2009 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.org */ #include "mpg123lib_intern.h" #include "icy2utf8.h" #include "debug.h" #ifdef GAPLESS #define SAMPLE_ADJUST(x) ((x) - ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) #define SAMPLE_UNADJUST(x) ((x) + ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) #else #define SAMPLE_ADJUST(x) (x) #define SAMPLE_UNADJUST(x) (x) #endif #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe) static int initialized = 0; #define ALIGNCHECK(mh) #define ALIGNCHECKK /* On compilers that support data alignment but not the automatic stack realignment. We check for properly aligned stack before risking a crash because of badly compiled client program. */ #if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) /* Common building block. */ #define ALIGNMAINPART \ /* minimum size of 16 bytes, not all compilers would align a smaller piece of data */ \ double ALIGNED(16) altest[2]; \ debug2("testing alignment, with %lu %% 16 = %lu", \ (unsigned long)altest, (unsigned long)((size_t)altest % 16)); \ if((size_t)altest % 16 != 0) #undef ALIGNCHECK #define ALIGNCHECK(mh) \ ALIGNMAINPART \ { \ error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ if(mh != NULL) mh->err = MPG123_BAD_ALIGN; \ \ return MPG123_ERR; \ } #undef ALIGNCHECKK #define ALIGNCHECKK \ ALIGNMAINPART \ { \ error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ return MPG123_BAD_ALIGN; \ } #endif #ifdef GAPLESS /* Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out. fr->buffer.fill may then be smaller than before... */ static void frame_buffercheck(mpg123_handle *fr) { /* When we have no accurate position, gapless code does not make sense. */ if(!fr->accurate) return; /* The first interesting frame: Skip some leading samples. */ if(fr->firstoff && fr->num == fr->firstframe) { off_t byteoff = samples_to_bytes(fr, fr->firstoff); if((off_t)fr->buffer.fill > byteoff) { fr->buffer.fill -= byteoff; /* buffer.p != buffer.data only for own buffer */ debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i", (long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff; else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill); debug3("done cutting, buffer at %p =? %p, buf[1]=%i", (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); } else fr->buffer.fill = 0; fr->firstoff = 0; /* Only enter here once... when you seek, firstoff should be reset. */ } /* The last interesting (planned) frame: Only use some leading samples. */ if(fr->lastoff && fr->num == fr->lastframe) { off_t byteoff = samples_to_bytes(fr, fr->lastoff); if((off_t)fr->buffer.fill > byteoff) { fr->buffer.fill = byteoff; } fr->lastoff = 0; /* Only enter here once... when you seek, lastoff should be reset. */ } } #endif int attribute_align_arg mpg123_init(void) { ALIGNCHECKK if((sizeof(short) != 2) || (sizeof(long) < 4)) return MPG123_BAD_TYPES; if(initialized) return MPG123_OK; /* no need to initialize twice */ #ifndef NO_LAYER12 init_layer12(); /* inits also shared tables with layer1 */ #endif #ifndef NO_LAYER3 init_layer3(); #endif prepare_decode_tables(); check_decoders(); initialized = 1; return MPG123_OK; } void attribute_align_arg mpg123_exit(void) { /* nothing yet, but something later perhaps */ } /* create a new handle with specified decoder, decoder can be "", "auto" or NULL for auto-detection */ mpg123_handle attribute_align_arg *mpg123_new(const char* decoder, int *error) { return mpg123_parnew(NULL, decoder, error); } /* ...the full routine with optional initial parameters to override defaults. */ mpg123_handle attribute_align_arg *mpg123_parnew(mpg123_pars *mp, const char* decoder, int *error) { mpg123_handle *fr = NULL; int err = MPG123_OK; #if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) #ifdef CCALIGN double ALIGNED(16) altest[4]; if(((size_t)altest) % 16 != 0) { error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); *error = MPG123_BAD_ALIGN; return NULL; } #endif #endif if(initialized) fr = (mpg123_handle*) malloc(sizeof(mpg123_handle)); else err = MPG123_NOT_INITIALIZED; if(fr != NULL) { frame_init_par(fr, mp); debug("cpu opt setting"); if(frame_cpu_opt(fr, decoder) != 1) { err = MPG123_BAD_DECODER; frame_exit(fr); free(fr); fr = NULL; } } if(fr != NULL) { /* Cleanup that mess! ... use mpg123_decoder / decode_update! */ if(frame_outbuffer(fr) != 0) { err = MPG123_NO_BUFFERS; frame_exit(fr); free(fr); fr = NULL; } else { /* I smell cleanup here... with get_next_frame() */ /* if(decode_update(fr) != 0) { err = fr->err != MPG123_OK ? fr->err : MPG123_BAD_DECODER; frame_exit(fr); free(fr); fr = NULL; } else */ fr->decoder_change = 1; } } else if(err == MPG123_OK) err = MPG123_OUT_OF_MEM; if(error != NULL) *error = err; return fr; } int attribute_align_arg mpg123_decoder(mpg123_handle *mh, const char* decoder) { enum optdec dt = dectype(decoder); ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; if(dt == nodec) { mh->err = MPG123_BAD_DECODER; return MPG123_ERR; } if(dt == mh->cpu_opts.type) return MPG123_OK; /* Now really change. */ /* frame_exit(mh); frame_init(mh); */ debug("cpu opt setting"); if(frame_cpu_opt(mh, decoder) != 1) { mh->err = MPG123_BAD_DECODER; frame_exit(mh); return MPG123_ERR; } /* New buffers for decoder are created in frame_buffers() */ if((frame_outbuffer(mh) != 0)) { mh->err = MPG123_NO_BUFFERS; frame_exit(mh); return MPG123_ERR; } /* I smell cleanup here... with get_next_frame() */ decode_update(mh); mh->decoder_change = 1; return MPG123_OK; } int attribute_align_arg mpg123_param(mpg123_handle *mh, enum mpg123_parms key, long val, double fval) { int r; ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; r = mpg123_par(&mh->p, key, val, fval); if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } else { /* Special treatment for some settings. */ #ifdef FRAME_INDEX if(key == MPG123_INDEX_SIZE) { /* Apply frame index size and grow property on the fly. */ r = frame_index_setup(mh); if(r != MPG123_OK) mh->err = MPG123_INDEX_FAIL; } #endif } return r; } int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long val, double fval) { int ret = MPG123_OK; ALIGNCHECKK if(mp == NULL) return MPG123_BAD_PARS; switch(key) { case MPG123_VERBOSE: mp->verbose = val; break; case MPG123_FLAGS: #ifndef GAPLESS if(val & MPG123_GAPLESS) ret = MPG123_NO_GAPLESS; #endif if(ret == MPG123_OK) mp->flags = val; debug1("set flags to 0x%lx", (unsigned long) mp->flags); break; case MPG123_ADD_FLAGS: #ifndef GAPLESS /* Enabling of gapless mode doesn't work when it's not there, but disabling (below) is no problem. */ if(val & MPG123_GAPLESS) ret = MPG123_NO_GAPLESS; else #endif mp->flags |= val; debug1("set flags to 0x%lx", (unsigned long) mp->flags); break; case MPG123_REMOVE_FLAGS: mp->flags &= ~val; debug1("set flags to 0x%lx", (unsigned long) mp->flags); break; case MPG123_FORCE_RATE: /* should this trigger something? */ #ifdef NO_NTOM if(val > 0) ret = MPG123_BAD_RATE; #else if(val > 96000) ret = MPG123_BAD_RATE; else mp->force_rate = val < 0 ? 0 : val; /* >0 means enable, 0 disable */ #endif break; case MPG123_DOWN_SAMPLE: #ifdef NO_DOWNSAMPLE if(val != 0) ret = MPG123_BAD_RATE; #else if(val < 0 || val > 2) ret = MPG123_BAD_RATE; else mp->down_sample = (int)val; #endif break; case MPG123_RVA: if(val < 0 || val > MPG123_RVA_MAX) ret = MPG123_BAD_RVA; else mp->rva = (int)val; break; case MPG123_DOWNSPEED: mp->halfspeed = val < 0 ? 0 : val; break; case MPG123_UPSPEED: mp->doublespeed = val < 0 ? 0 : val; break; case MPG123_ICY_INTERVAL: #ifndef NO_ICY mp->icy_interval = val > 0 ? val : 0; #else if(val > 0) ret = MPG123_BAD_PARAM; #endif break; case MPG123_OUTSCALE: /* Choose the value that is non-zero, if any. Downscaling integers to 1.0 . */ mp->outscale = val == 0 ? fval : (double)val/SHORT_SCALE; break; case MPG123_TIMEOUT: #ifndef WIN32 mp->timeout = val >= 0 ? val : 0; #else ret = MPG123_NO_TIMEOUT; #endif break; case MPG123_RESYNC_LIMIT: mp->resync_limit = val; break; case MPG123_INDEX_SIZE: #ifdef FRAME_INDEX mp->index_size = val; #else ret = MPG123_NO_INDEX; #endif break; case MPG123_PREFRAMES: if(val >= 0) mp->preframes = val; else ret = MPG123_BAD_VALUE; break; default: ret = MPG123_BAD_PARAM; } return ret; } int attribute_align_arg mpg123_getparam(mpg123_handle *mh, enum mpg123_parms key, long *val, double *fval) { int r; ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; r = mpg123_getpar(&mh->p, key, val, fval); if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } return r; } int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, long *val, double *fval) { int ret = 0; ALIGNCHECKK if(mp == NULL) return MPG123_BAD_PARS; switch(key) { case MPG123_VERBOSE: if(val) *val = mp->verbose; break; case MPG123_FLAGS: case MPG123_ADD_FLAGS: if(val) *val = mp->flags; break; case MPG123_FORCE_RATE: if(val) #ifdef NO_NTOM *val = 0; #else *val = mp->force_rate; #endif break; case MPG123_DOWN_SAMPLE: if(val) *val = mp->down_sample; break; case MPG123_RVA: if(val) *val = mp->rva; break; case MPG123_DOWNSPEED: if(val) *val = mp->halfspeed; break; case MPG123_UPSPEED: if(val) *val = mp->doublespeed; break; case MPG123_ICY_INTERVAL: #ifndef NO_ICY if(val) *val = (long)mp->icy_interval; #else if(val) *val = 0; #endif break; case MPG123_OUTSCALE: if(fval) *fval = mp->outscale; if(val) *val = (long)(mp->outscale*SHORT_SCALE); break; case MPG123_RESYNC_LIMIT: if(val) *val = mp->resync_limit; break; case MPG123_INDEX_SIZE: if(val) #ifdef FRAME_INDEX *val = mp->index_size; #else *val = 0; /* graceful fallback: no index is index of zero size */ #endif break; case MPG123_PREFRAMES: *val = mp->preframes; break; default: ret = MPG123_BAD_PARAM; } return ret; } int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key, long *val, double *fval) { int ret = MPG123_OK; long theval = 0; double thefval = 0.; ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; switch(key) { case MPG123_ACCURATE: theval = mh->accurate; break; default: mh->err = MPG123_BAD_KEY; ret = MPG123_ERR; } if(val != NULL) *val = theval; if(fval != NULL) *fval = thefval; return ret; } int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val) { ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; } switch(channel) { case MPG123_LEFT|MPG123_RIGHT: mh->equalizer[0][band] = mh->equalizer[1][band] = DOUBLE_TO_REAL(val); break; case MPG123_LEFT: mh->equalizer[0][band] = DOUBLE_TO_REAL(val); break; case MPG123_RIGHT: mh->equalizer[1][band] = DOUBLE_TO_REAL(val); break; default: mh->err=MPG123_BAD_CHANNEL; return MPG123_ERR; } mh->have_eq_settings = TRUE; return MPG123_OK; } double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band) { double ret = 0.; ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; /* Handle this gracefully. When there is no band, it has no volume. */ if(band > -1 && band < 32) switch(channel) { case MPG123_LEFT|MPG123_RIGHT: ret = 0.5*(REAL_TO_DOUBLE(mh->equalizer[0][band])+REAL_TO_DOUBLE(mh->equalizer[1][band])); break; case MPG123_LEFT: ret = REAL_TO_DOUBLE(mh->equalizer[0][band]); break; case MPG123_RIGHT: ret = REAL_TO_DOUBLE(mh->equalizer[1][band]); break; /* Default case is already handled: ret = 0 */ } return ret; } /* plain file access, no http! */ int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) { ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; mpg123_close(mh); frame_reset(mh); return open_stream(mh, path, -1); } int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd) { ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; mpg123_close(mh); frame_reset(mh); return open_stream(mh, NULL, fd); } int attribute_align_arg mpg123_open_feed(mpg123_handle *mh) { ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; mpg123_close(mh); frame_reset(mh); return open_feed(mh); } int attribute_align_arg mpg123_replace_reader( mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int) ) { ALIGNCHECK(mh); if(mh == NULL) return MPG123_ERR; mh->rdat.r_read = r_read; mh->rdat.r_lseek = r_lseek; return MPG123_OK; } int decode_update(mpg123_handle *mh) { long native_rate; int b; ALIGNCHECK(mh); native_rate = frame_freq(mh); b = frame_output_format(mh); /* Select the new output format based on given constraints. */ if(b < 0) return MPG123_ERR; if(b == 1) mh->new_format = 1; /* Store for later... */ debug3("updating decoder structure with native rate %li and af.rate %li (new format: %i)", native_rate, mh->af.rate, mh->new_format); if(mh->af.rate == native_rate) mh->down_sample = 0; else if(mh->af.rate == native_rate>>1) mh->down_sample = 1; else if(mh->af.rate == native_rate>>2) mh->down_sample = 2; else mh->down_sample = 3; /* flexible (fixed) rate */ switch(mh->down_sample) { case 0: case 1: case 2: mh->down_sample_sblimit = SBLIMIT>>(mh->down_sample); /* With downsampling I get less samples per frame */ mh->outblock = samples_to_bytes(mh, (spf(mh)>>mh->down_sample)); break; #ifndef NO_NTOM case 3: { if(synth_ntom_set_step(mh) != 0) return -1; if(frame_freq(mh) > mh->af.rate) { mh->down_sample_sblimit = SBLIMIT * mh->af.rate; mh->down_sample_sblimit /= frame_freq(mh); } else mh->down_sample_sblimit = SBLIMIT; mh->outblock = mh->af.encsize * mh->af.channels * ( ( NTOM_MUL-1+spf(mh) * (((size_t)NTOM_MUL*mh->af.rate)/frame_freq(mh)) )/NTOM_MUL ); } break; #endif } if(!(mh->p.flags & MPG123_FORCE_MONO)) { if(mh->af.channels == 1) mh->single = SINGLE_MIX; else mh->single = SINGLE_STEREO; } else mh->single = (mh->p.flags & MPG123_FORCE_MONO)-1; if(set_synth_functions(mh) != 0) return -1;; do_rva(mh); debug3("done updating decoder structure with native rate %li and af.rate %li and down_sample %i", frame_freq(mh), mh->af.rate, mh->down_sample); return 0; } size_t attribute_align_arg mpg123_safe_buffer() { /* real is the largest possible output (it's 32bit float, 32bit int or 64bit double). */ return sizeof(real)*2*1152*NTOM_MAX; } size_t attribute_align_arg mpg123_outblock(mpg123_handle *mh) { if(mh != NULL) return mh->outblock; else return mpg123_safe_buffer(); } static int get_next_frame(mpg123_handle *mh) { int change = mh->decoder_change; do { int b; /* Decode & discard some frame(s) before beginning. */ if(mh->to_ignore && mh->num < mh->firstframe && mh->num >= mh->ignoreframe) { debug1("ignoring frame %li", (long)mh->num); /* Decoder structure must be current! decode_update has been called before... */ (mh->do_layer)(mh); mh->buffer.fill = 0; #ifndef NO_NTOM /* The ignored decoding may have failed. Make sure ntom stays consistent. */ if(mh->down_sample == 3) ntom_set_ntom(mh, mh->num+1); #endif mh->to_ignore = mh->to_decode = FALSE; } /* Read new frame data; possibly breaking out here for MPG123_NEED_MORE. */ debug("read frame"); mh->to_decode = FALSE; b = read_frame(mh); /* That sets to_decode only if a full frame was read. */ debug4("read of frame %li returned %i (to_decode=%i) at sample %li", (long)mh->num, b, mh->to_decode, (long)mpg123_tell(mh)); if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */ else if(b <= 0) { /* More sophisticated error control? */ if(b==0 || mh->rdat.filepos == mh->rdat.filelen) { /* We simply reached the end. */ mh->track_frames = mh->num + 1; debug("What about updating/checking gapless sample count here?"); return MPG123_DONE; } else return MPG123_ERR; /* Some real error. */ } /* Now, there should be new data to decode ... and also possibly new stream properties */ if(mh->header_change > 1) { debug("big header change"); change = 1; } /* Now some accounting: Look at the numbers and decide if we want this frame. */ ++mh->playnum; /* Plain skipping without decoding, only when frame is not ignored on next cycle. */ if(mh->num < mh->firstframe || (mh->p.doublespeed && (mh->playnum % mh->p.doublespeed))) { if(!(mh->to_ignore && mh->num < mh->firstframe && mh->num >= mh->ignoreframe)) { frame_skip(mh); /* Should one fix NtoM here or not? It is not work the trouble for doublespeed, but what with leading frames? */ } } /* Or, we are finally done and have a new frame. */ else break; } while(1); /* When we start actually using the CRC, this could move into the loop... */ /* A question of semantics ... should I fold start_frame and frame_number into firstframe/lastframe? */ if(mh->lastframe >= 0 && mh->num > mh->lastframe) { mh->to_decode = mh->to_ignore = FALSE; return MPG123_DONE; } if(change) { if(decode_update(mh) < 0) /* dito... */ return MPG123_ERR; debug1("new format: %i", mh->new_format); mh->decoder_change = 0; #ifdef GAPLESS if(mh->fresh) { int b=0; /* Prepare offsets for gapless decoding. */ debug1("preparing gapless stuff with native rate %li", frame_freq(mh)); frame_gapless_realinit(mh); frame_set_frameseek(mh, mh->num); mh->fresh = 0; /* Could this possibly happen? With a real big gapless offset... */ if(mh->num < mh->firstframe) b = get_next_frame(mh); if(b < 0) return b; /* Could be error, need for more, new format... */ } #endif } return MPG123_OK; } /* Assumption: A buffer full of zero samples can be constructed by repetition of this byte. Only to be used by decode_the_frame() ... */ static int zero_byte(mpg123_handle *fr) { #ifndef NO_8BIT return fr->af.encoding & MPG123_ENC_8 ? fr->conv16to8[0] : 0; #else return 0; /* All normal signed formats have the zero here (even in byte form -- that may be an assumption for your funny machine...). */ #endif } /* Not part of the api. This just decodes the frame and fills missing bits with zeroes. There can be frames that are broken and thus make do_layer() fail. */ void decode_the_frame(mpg123_handle *fr) { size_t needed_bytes = samples_to_bytes(fr, frame_outs(fr, fr->num+1)-frame_outs(fr, fr->num)); fr->clip += (fr->do_layer)(fr); /*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/ /* There could be less data than promised. Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */ #ifdef DEBUG if(fr->buffer.fill != needed_bytes) { #endif if(fr->buffer.fill < needed_bytes) { if(VERBOSE2) fprintf(stderr, "Note: broken frame %li, filling up with %"SIZE_P" zeroes, from %"SIZE_P"\n", (long)fr->num, (size_p)(needed_bytes-fr->buffer.fill), (size_p)fr->buffer.fill); /* One could do a loop with individual samples instead... but zero is zero Actually, that is wrong: zero is mostly a series of null bytes, but we have funny 8bit formats that have a different opinion on zero... Unsigned 16 or 32 bit formats are handled later. */ memset( fr->buffer.data + fr->buffer.fill, zero_byte(fr), needed_bytes - fr->buffer.fill ); fr->buffer.fill = needed_bytes; #ifndef NO_NTOM /* ntom_val will be wrong when the decoding wasn't carried out completely */ ntom_set_ntom(fr, fr->num+1); #endif } #ifdef DEBUG else { if(NOQUIET) error2("I got _more_ bytes than expected (%"SIZE_P" / %"SIZE_P"), that should not be possible!", (size_p)fr->buffer.fill, (size_p)needed_bytes); } } #endif /* Handle unsigned output formats via reshifting after decode here. */ #ifndef NO_32BIT if(fr->af.encoding == MPG123_ENC_UNSIGNED_32) { /* 32bit signed -> unsigned */ size_t i; int32_t *ssamples; uint32_t *usamples; ssamples = (int32_t*)fr->buffer.data; usamples = (uint32_t*)fr->buffer.data; debug("converting output to unsigned 32 bit integer"); for(i=0; ibuffer.fill/sizeof(int32_t); ++i) { /* Different strategy since we don't have a larger type at hand. Also watch out for silly +-1 fun because integer constants are signed in C90! */ if(ssamples[i] >= 0) usamples[i] = (uint32_t)ssamples[i] + 2147483647+1; /* The smalles value goes zero. */ else if(ssamples[i] == ((int32_t)-2147483647-1)) usamples[i] = 0; /* Now -value is in the positive range of signed int ... so it's a possible value at all. */ else usamples[i] = (uint32_t)2147483647+1 - (uint32_t)(-ssamples[i]); } } #endif #ifndef NO_16BIT if(fr->af.encoding == MPG123_ENC_UNSIGNED_16) { size_t i; short *ssamples; unsigned short *usamples; ssamples = (short*)fr->buffer.data; usamples = (unsigned short*)fr->buffer.data; debug("converting output to unsigned 16 bit integer"); for(i=0; ibuffer.fill/sizeof(short); ++i) { long tmp = (long)ssamples[i]+32768; usamples[i] = (unsigned short)tmp; } } #endif } /* Put _one_ decoded frame into the frame structure's buffer, accessible at the location stored in