Jelajahi Sumber

adding vorbis and alac

philippe44 5 tahun lalu
induk
melakukan
3aec88e87d

+ 2 - 1
components/codecs/component.mk

@@ -7,7 +7,8 @@ COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) 	\
 	$(COMPONENT_PATH)/lib/libesp-flac.a 	\
 	$(COMPONENT_PATH)/lib/libfaad.a 		\
 	$(COMPONENT_PATH)/lib/libvorbisidec.a	\
-	$(COMPONENT_PATH)/lib/libogg.a
+	$(COMPONENT_PATH)/lib/libogg.a			\
+	$(COMPONENT_PATH)/lib/libalac.a
 	
 	#$(COMPONENT_PATH)/lib/libvorbisidec.a
 	#$(COMPONENT_PATH)/lib/libogg.a

+ 40 - 0
components/codecs/inc/alac/alac_wrapper.h

@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * alac_wrapper.h: ALAC coder wrapper
+ *
+ * Copyright (C) 2016 Philippe <philippe44@outlook.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+#ifndef __ALAC_WRAPPER_H_
+#define __ALAC_WRAPPER_H_
+
+struct alac_codec_s;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
+								unsigned char *sample_size, unsigned *sample_rate,
+								unsigned char *channels);
+void alac_delete_decoder(struct alac_codec_s *codec);
+bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
+				 unsigned char *output, char channels, unsigned *out_frames);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 0 - 0
components/codecs/inc/vorbis/vorbisfile.h → components/codecs/inc/vorbis/ivorbisfile.h


TEMPAT SAMPAH
components/codecs/lib/libalac.a


+ 538 - 0
main/alac.c

@@ -0,0 +1,538 @@
+/*
+ *  Squeezelite - lightweight headless squeezebox emulator
+ *
+ *  (c) Adrian Smith 2012-2015, triode1@btinternet.com
+ *  (c) Philippe, philippe_44@outlook.com 
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "squeezelite.h"
+
+#include <alac_wrapper.h>
+
+#define BLOCK_SIZE (4096 * BYTES_PER_FRAME)
+#define MIN_READ    BLOCK_SIZE
+#define MIN_SPACE  (MIN_READ * 4)
+
+struct chunk_table {
+	u32_t sample, offset;
+};
+
+struct alac {
+	void *decoder;
+	u8_t *writebuf;
+	// following used for mp4 only
+	u32_t consume;
+	u32_t pos;
+	u32_t sample;
+	u32_t nextchunk;
+	void *stsc;
+	u32_t skip;
+	u64_t samples;
+	u64_t sttssamples;
+	bool  empty;
+	struct chunk_table *chunkinfo;
+	u32_t  *block_size, default_block_size, block_index;
+	unsigned sample_rate;
+	unsigned char channels, sample_size;
+	unsigned trak, play;
+};
+
+static struct alac *l;
+
+extern log_level loglevel;
+
+extern struct buffer *streambuf;
+extern struct buffer *outputbuf;
+extern struct streamstate stream;
+extern struct outputstate output;
+extern struct decodestate decode;
+extern struct processstate process;
+
+#define LOCK_S   mutex_lock(streambuf->mutex)
+#define UNLOCK_S mutex_unlock(streambuf->mutex)
+#define LOCK_O   mutex_lock(outputbuf->mutex)
+#define UNLOCK_O mutex_unlock(outputbuf->mutex)
+#if PROCESS
+#define LOCK_O_direct   if (decode.direct) mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
+#define LOCK_O_not_direct   if (!decode.direct) mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex)
+#define IF_DIRECT(x)    if (decode.direct) { x }
+#define IF_PROCESS(x)   if (!decode.direct) { x }
+#else
+#define LOCK_O_direct   mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
+#define LOCK_O_not_direct
+#define UNLOCK_O_not_direct
+#define IF_DIRECT(x)    { x }
+#define IF_PROCESS(x)
+#endif
+
+// read mp4 header to extract config data
+static int read_mp4_header(void) {
+	size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
+	char type[5];
+	u32_t len;
+
+	while (bytes >= 8) {
+		// count trak to find the first playable one
+		u32_t consume;
+
+		len = unpackN((u32_t *)streambuf->readp);
+		memcpy(type, streambuf->readp + 4, 4);
+		type[4] = '\0';
+
+		if (!strcmp(type, "moov")) {
+			l->trak = 0;
+			l->play = 0;
+		}
+		if (!strcmp(type, "trak")) {
+			l->trak++;
+		}
+
+		// extract audio config from within alac
+		if (!strcmp(type, "alac") && bytes > len) {
+			u8_t *ptr = streambuf->readp + 36;
+			l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels);
+			l->play = l->trak;
+		}
+
+		// extract the total number of samples from stts
+		if (!strcmp(type, "stsz") && bytes > len) {
+			u32_t i;
+			u8_t *ptr = streambuf->readp + 12;
+			l->default_block_size = unpackN((u32_t *) ptr); ptr += 4;
+			if (!l->default_block_size) {
+				u32_t entries = unpackN((u32_t *)ptr); ptr += 4;
+				l->block_size = malloc((entries + 1)* 4);
+				for (i = 0; i < entries; i++) {
+					l->block_size[i] = unpackN((u32_t *)ptr); ptr += 4;
+				}
+				l->block_size[entries] = 0;
+				LOG_DEBUG("total blocksize contained in stsz %u", entries);
+			} else {
+				LOG_DEBUG("fixed blocksize in stsz %u", l->default_block_size);
+            }
+		}
+
+		// extract the total number of samples from stts
+		if (!strcmp(type, "stts") && bytes > len) {
+			u32_t i;
+			u8_t *ptr = streambuf->readp + 12;
+			u32_t entries = unpackN((u32_t *)ptr);
+			ptr += 4;
+			for (i = 0; i < entries; ++i) {
+				u32_t count = unpackN((u32_t *)ptr);
+				u32_t size = unpackN((u32_t *)(ptr + 4));
+				l->sttssamples += count * size;
+				ptr += 8;
+			}
+			LOG_DEBUG("total number of samples contained in stts: " FMT_u64, l->sttssamples);
+		}
+
+		// stash sample to chunk info, assume it comes before stco
+		if (!strcmp(type, "stsc") && bytes > len && !l->chunkinfo) {
+			l->stsc = malloc(len - 12);
+			if (l->stsc == NULL) {
+				LOG_WARN("malloc fail");
+				return -1;
+			}
+			memcpy(l->stsc, streambuf->readp + 12, len - 12);
+		}
+
+		// build offsets table from stco and stored stsc
+		if (!strcmp(type, "stco") && bytes > len && l->play == l->trak) {
+			u32_t i;
+			// extract chunk offsets
+			u8_t *ptr = streambuf->readp + 12;
+			u32_t entries = unpackN((u32_t *)ptr);
+			ptr += 4;
+			l->chunkinfo = malloc(sizeof(struct chunk_table) * (entries + 1));
+			if (l->chunkinfo == NULL) {
+				LOG_WARN("malloc fail");
+				return -1;
+			}
+			for (i = 0; i < entries; ++i) {
+				l->chunkinfo[i].offset = unpackN((u32_t *)ptr);
+				l->chunkinfo[i].sample = 0;
+				ptr += 4;
+			}
+			l->chunkinfo[i].sample = 0;
+			l->chunkinfo[i].offset = 0;
+			// fill in first sample id for each chunk from stored stsc
+			if (l->stsc) {
+				u32_t stsc_entries = unpackN((u32_t *)l->stsc);
+				u32_t sample = 0;
+				u32_t last = 0, last_samples = 0;
+				u8_t *ptr = (u8_t *)l->stsc + 4;
+				while (stsc_entries--) {
+					u32_t first = unpackN((u32_t *)ptr);
+					u32_t samples = unpackN((u32_t *)(ptr + 4));
+					if (last) {
+						for (i = last - 1; i < first - 1; ++i) {
+							l->chunkinfo[i].sample = sample;
+							sample += last_samples;
+						}
+					}
+					if (stsc_entries == 0) {
+						for (i = first - 1; i < entries; ++i) {
+							l->chunkinfo[i].sample = sample;
+							sample += samples;
+						}
+					}
+					last = first;
+					last_samples = samples;
+					ptr += 12;
+				}
+				free(l->stsc);
+				l->stsc = NULL;
+			}
+		}
+
+		// found media data, advance to start of first chunk and return
+		if (!strcmp(type, "mdat")) {
+			_buf_inc_readp(streambuf, 8);
+			l->pos += 8;
+			bytes  -= 8;
+			if (l->play) {
+				LOG_DEBUG("type: mdat len: %u pos: %u", len, l->pos);
+				if (l->chunkinfo && l->chunkinfo[0].offset > l->pos) {
+					u32_t skip = l->chunkinfo[0].offset - l->pos;
+					LOG_DEBUG("skipping: %u", skip);
+					if (skip <= bytes) {
+						_buf_inc_readp(streambuf, skip);
+						l->pos += skip;
+					} else {
+						l->consume = skip;
+					}
+				}
+				l->sample = l->nextchunk = 1;
+				l->block_index = 0;
+				return 1;
+			} else {
+				LOG_DEBUG("type: mdat len: %u, no playable track found", len);
+				return -1;
+			}
+		}
+
+		// parse key-value atoms within ilst ---- entries to get encoder padding within iTunSMPB entry for gapless
+		if (!strcmp(type, "----") && bytes > len) {
+			u8_t *ptr = streambuf->readp + 8;
+			u32_t remain = len - 8, size;
+			if (!memcmp(ptr + 4, "mean", 4) && (size = unpackN((u32_t *)ptr)) < remain) {
+				ptr += size; remain -= size;
+			}
+			if (!memcmp(ptr + 4, "name", 4) && (size = unpackN((u32_t *)ptr)) < remain && !memcmp(ptr + 12, "iTunSMPB", 8)) {
+				ptr += size; remain -= size;
+			}
+			if (!memcmp(ptr + 4, "data", 4) && remain > 16 + 48) {
+				// data is stored as hex strings: 0 start end samples
+				u32_t b, c; u64_t d;
+				if (sscanf((const char *)(ptr + 16), "%x %x %x " FMT_x64, &b, &b, &c, &d) == 4) {
+					LOG_DEBUG("iTunSMPB start: %u end: %u samples: " FMT_u64, b, c, d);
+					if (l->sttssamples && l->sttssamples < b + c + d) {
+						LOG_DEBUG("reducing samples as stts count is less");
+						d = l->sttssamples - (b + c);
+					}
+					l->skip = b;
+					l->samples = d;
+				}
+			}
+		}
+
+		// default to consuming entire box
+		consume = len;
+
+		// read into these boxes so reduce consume
+		if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl") ||
+			!strcmp(type, "udta") || !strcmp(type, "ilst")) {
+			consume = 8;
+		}
+		// special cases which mix mix data in the enclosing box which we want to read into
+		if (!strcmp(type, "stsd")) consume = 16;
+		if (!strcmp(type, "mp4a")) consume = 36;
+		if (!strcmp(type, "meta")) consume = 12;
+
+		// consume rest of box if it has been parsed (all in the buffer) or is not one we want to parse
+		if (bytes >= consume) {
+			LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume);
+			_buf_inc_readp(streambuf, consume);
+			l->pos += consume;
+			bytes -= consume;
+		} else if ( !(!strcmp(type, "esds") || !strcmp(type, "stts") || !strcmp(type, "stsc") ||
+					  !strcmp(type, "stsz") || !strcmp(type, "stco") || !strcmp(type, "----")) ) {
+			LOG_DEBUG("type: %s len: %u consume: %u - partial consume: %u", type, len, consume, bytes);
+			_buf_inc_readp(streambuf, bytes);
+			l->pos += bytes;
+			l->consume = consume - bytes;
+			break;
+		} else {
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static decode_state alac_decode(void) {
+	size_t bytes;
+	bool endstream;
+	u8_t *iptr;
+	u32_t frames, block_size;
+
+	LOCK_S;
+
+		// data not reached yet
+	if (l->consume) {
+		u32_t consume = min(l->consume, _buf_used(streambuf));
+		LOG_DEBUG("consume: %u of %u", consume, l->consume);
+		_buf_inc_readp(streambuf, consume);
+		l->pos += consume;
+		l->consume -= consume;
+		UNLOCK_S;
+		return DECODE_RUNNING;
+	}
+
+	if (decode.new_stream) {
+		int found = 0;
+
+		// mp4 - read header
+		found = read_mp4_header();
+
+		if (found == 1) {
+			bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
+
+			LOG_INFO("setting track_start");
+			LOCK_O_not_direct;
+
+			output.next_sample_rate = decode_newstream(l->sample_rate, output.supported_rates);
+			output.track_start = outputbuf->writep;
+			if (output.fade_mode) _checkfade(true);
+			decode.new_stream = false;
+
+			UNLOCK_O_not_direct;
+		} else if (found == -1) {
+			LOG_WARN("[%p]: error reading stream header");
+			UNLOCK_S;
+			return DECODE_ERROR;
+		} else {
+			// not finished header parsing come back next time
+			UNLOCK_S;
+			return DECODE_RUNNING;
+		}
+	}
+
+	bytes = _buf_used(streambuf);
+	block_size = l->default_block_size ? l->default_block_size : l->block_size[l->block_index];
+
+	// stream terminated
+	if (stream.state <= DISCONNECT && (bytes == 0 || block_size == 0)) {
+		UNLOCK_S;
+		LOG_DEBUG("end of stream");
+		return DECODE_COMPLETE;
+	}
+
+	// enough data for coding
+	if (bytes < block_size) {
+		UNLOCK_S;
+		return DECODE_RUNNING;
+	} else if (block_size != l->default_block_size) l->block_index++;
+
+	bytes = min(bytes, _buf_cont_read(streambuf));
+
+	// need to create a buffer with contiguous data
+	if (bytes < block_size) {
+		u8_t *buffer = malloc(block_size);
+		memcpy(buffer, streambuf->readp, bytes);
+		memcpy(buffer + bytes, streambuf->buf, block_size - bytes);
+		iptr = buffer;
+	} else iptr = streambuf->readp;
+
+	if (!alac_to_pcm(l->decoder, iptr, l->writebuf, 2, &frames)) {
+		LOG_ERROR("decode error");
+		UNLOCK_S;
+		return DECODE_ERROR;
+	}
+
+	// and free it
+	if (bytes < block_size) free(iptr);
+
+	LOG_SDEBUG("block of %u bytes (%u frames)", block_size, frames);
+
+	endstream = false;
+	// mp4 end of chunk - skip to next offset
+	if (l->chunkinfo && l->chunkinfo[l->nextchunk].offset && l->sample++ == l->chunkinfo[l->nextchunk].sample) {
+		 if (l->chunkinfo[l->nextchunk].offset > l->pos) {
+			u32_t skip = l->chunkinfo[l->nextchunk].offset - l->pos;
+			if (_buf_used(streambuf) >= skip) {
+				_buf_inc_readp(streambuf, skip);
+				l->pos += skip;
+			} else {
+				l->consume = skip;
+			}
+			l->nextchunk++;
+		 } else {
+			LOG_ERROR("error: need to skip backwards!");
+			endstream = true;
+		 }
+	// mp4 when not at end of chunk
+	} else if (frames) {
+		_buf_inc_readp(streambuf, block_size);
+		l->pos += block_size;
+	} else {
+		endstream = true;
+	}
+
+	UNLOCK_S;
+
+	if (endstream) {
+		LOG_WARN("unable to decode further");
+		return DECODE_ERROR;
+	}
+
+	// now point at the beginning of decoded samples
+	iptr = l->writebuf;
+
+	if (l->skip) {
+		u32_t skip;
+		if (l->empty) {
+			l->empty = false;
+			l->skip -= frames;
+			LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames);
+		}
+		skip = min(frames, l->skip);
+		LOG_DEBUG("gapless: skipping %u frames at start", skip);
+		frames -= skip;
+		l->skip -= skip;
+		iptr += skip * l->channels * l->sample_size;
+	}
+
+	if (l->samples) {
+		if (l->samples < frames) {
+			LOG_DEBUG("gapless: trimming %u frames from end", frames - l->samples);
+			frames = (u32_t) l->samples;
+		}
+		l->samples -= frames;
+	}
+
+	LOCK_O_direct;
+
+	while (frames > 0) {
+		size_t f, count;
+		s32_t *optr;
+
+		IF_DIRECT(
+			f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
+			optr = (s32_t *)outputbuf->writep;
+		);
+		IF_PROCESS(
+			f = min(frames, process.max_in_frames - process.in_frames);
+			optr = (s32_t *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
+		);
+
+		f = min(f, frames);
+		count = f;
+
+		if (l->sample_size == 8) {
+			while (count--) {
+				*optr++ = (*(u32_t*) iptr) << 24;
+				*optr++ = (*(u32_t*) (iptr + 1)) << 24;
+				iptr += 2;
+			}
+		} else if (l->sample_size == 16) {
+			while (count--) {
+				*optr++ = (*(u32_t*) iptr) << 16;
+				*optr++ = (*(u32_t*) (iptr + 2)) << 16;
+				iptr += 4;
+			}
+		} else if (l->sample_size == 24) {
+			while (count--) {
+				*optr++ = (*(u32_t*) iptr) << 8;
+				*optr++ = (*(u32_t*) (iptr + 3)) << 8;
+				iptr += 6;
+			}
+		} else if (l->sample_size == 32) {
+			while (count--) {
+				*optr++ = (*(u32_t*) iptr);
+				*optr++ = (*(u32_t*) (iptr + 4));
+				iptr += 8;
+			}
+		} else {
+			LOG_ERROR("unsupported bits per sample: %u", l->sample_size);
+		}
+
+		frames -= f;
+
+		IF_DIRECT(
+			_buf_inc_writep(outputbuf, f * BYTES_PER_FRAME);
+		);
+		IF_PROCESS(
+			process.in_frames = f;
+			// called only if there is enough space in process buffer
+			if (frames) LOG_ERROR("unhandled case");
+		);
+	 }
+
+	UNLOCK_O_direct;
+
+	return DECODE_RUNNING;
+}
+
+static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
+	if (l->decoder)	alac_delete_decoder(l->decoder);
+	else l->writebuf = malloc(BLOCK_SIZE * 2);
+	
+	if (l->chunkinfo) free(l->chunkinfo);
+	if (l->block_size) free(l->block_size);
+	if (l->stsc) free(l->stsc);
+	l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
+	l->skip = 0;
+	l->samples = l->sttssamples = 0;
+	l->empty = false;
+	l->pos = l->consume = l->sample = l->nextchunk = 0;
+}
+
+static void alac_close(void) {
+	if (l->decoder) alac_delete_decoder(l->decoder);
+	if (l->chunkinfo) free(l->chunkinfo);
+	if (l->block_size) free(l->block_size);
+	if (l->stsc) free(l->stsc);
+	l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
+	free(l->writebuf);
+}
+
+struct codec *register_alac(void) {
+	static struct codec ret = {
+		'l',            // id
+		"alc",          // types
+		MIN_READ,	    // min read
+		MIN_SPACE,	 	// min space assuming a ratio of 2
+		alac_open,      // open
+		alac_close,     // close
+		alac_decode,    // decode
+	};
+	
+	l =  malloc(sizeof(struct alac));
+	if (!l) {
+		return NULL;
+	}	
+	
+	l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
+	
+	LOG_INFO("using alac to decode alc");
+	return &ret;
+}

+ 4 - 2
main/component.mk

@@ -2,10 +2,12 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
-CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO 		\
+CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY		\
 	-I$(COMPONENT_PATH)/../components/codecs/inc		\
 	-I$(COMPONENT_PATH)/../components/codecs/inc/mad 	\
-	-I$(COMPONENT_PATH)/../components/codecs/inc/faad2
+	-I$(COMPONENT_PATH)/../components/codecs/inc/faad2	\
+	-I$(COMPONENT_PATH)/../components/codecs/inc/alac	\
+	-I$(COMPONENT_PATH)/../components/codecs/inc/vorbis
 LDFLAGS += -s
 
 

+ 3 - 1
main/decode.c

@@ -54,7 +54,6 @@ static bool running = true;
 #endif
 
 static void *decode_thread() {
-	
 
 	while (running) {
 		size_t bytes, space, min_space;
@@ -168,6 +167,9 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud
 		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_ff("wma"));
 #endif
 */
+	if (!strstr(exclude_codecs, "alac") && (!include_codecs || (order_codecs = strstr(include_codecs, "alac"))))
+		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_alac());
+
 #ifndef NO_FAAD
 	if (!strstr(exclude_codecs, "aac")	&& (!include_codecs || (order_codecs = strstr(include_codecs, "aac"))))
 		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_faad());

+ 1 - 0
main/squeezelite.h

@@ -755,6 +755,7 @@ struct codec *register_mpg(void);
 struct codec *register_vorbis(void);
 struct codec *register_faad(void);
 struct codec *register_dsd(void);
+struct codec *register_alac(void);
 struct codec *register_ff(const char *codec);
 
 //gpio.c

+ 9 - 4
main/vorbis.c

@@ -28,7 +28,11 @@
 // tremor's OggVorbis_File struct is normally smaller so this is ok, but padding added to malloc in case it is bigger
 #define OV_EXCLUDE_STATIC_CALLBACKS
 
+#ifdef TREMOR_ONLY
+#include <ivorbisfile.h>
+#else
 #include <vorbis/vorbisfile.h>
+#endif
 
 struct vorbis {
 	OggVorbis_File *vf;
@@ -183,7 +187,9 @@ static decode_state vorbis_decode(void) {
 	);
 
 	// write the decoded frames into outputbuf even though they are 16 bits per sample, then unpack them
-#if 0	
+#ifdef TREMOR_ONLY	
+	n = OV(v, read, v->vf, (char *)write_buf, bytes, &s);
+#else
 	if (!TREMOR(v)) {
 #if SL_LITTLE_ENDIAN
 		n = OV(v, read, v->vf, (char *)write_buf, bytes, 0, 2, 1, &s);
@@ -196,7 +202,6 @@ static decode_state vorbis_decode(void) {
 #endif
 	}
 #endif	
-	n = OV(v, read, v->vf, (char *)write_buf, bytes, &s);
 	
 	if (n > 0) {
 
@@ -315,8 +320,8 @@ struct codec *register_vorbis(void) {
 	static struct codec ret = {
 		'o',          // id
 		"ogg",        // types
-		4096,         // min read
-		40960,        // min space
+		2048,         // min read
+		20480,        // min space
 		vorbis_open,  // open
 		vorbis_close, // close
 		vorbis_decode,// decode