Added new SHN decoder (Derek Scott)

CQTexperiment
vspader 2006-06-03 20:25:44 +00:00
parent 38ff1f798c
commit 4a4672a6b9
15 changed files with 2205 additions and 276 deletions

View File

@ -14,6 +14,7 @@
8E1296DA0A2BA9CE00443124 /* PlaylistHeaderView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */; };
8E1296DB0A2BA9CE00443124 /* PlaylistHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */; };
8E4C7F090A0509FC003BE25F /* DragScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C7F070A0509FC003BE25F /* DragScrollView.m */; };
8E4CAB5B0A32251B00214C1D /* ShnFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E4CAB5A0A32251B00214C1D /* ShnFile.mm */; };
8E6A8E2C0A0D8A68002ABE9C /* CoreAudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E6A8E280A0D8A68002ABE9C /* CoreAudioFile.m */; };
8E6A8E380A0D8AD8002ABE9C /* CoreAudioUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E6A8E360A0D8AD8002ABE9C /* CoreAudioUtils.m */; };
8E75756909F31D5A0080F1EE /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75751909F31D5A0080F1EE /* AppController.m */; };
@ -39,7 +40,6 @@
8E75757E09F31D5A0080F1EE /* FlacFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75754809F31D5A0080F1EE /* FlacFile.m */; };
8E75757F09F31D5A0080F1EE /* MonkeysFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E75754A09F31D5A0080F1EE /* MonkeysFile.mm */; };
8E75758109F31D5A0080F1EE /* MusepackFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75754E09F31D5A0080F1EE /* MusepackFile.m */; };
8E75758209F31D5A0080F1EE /* ShnFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75755009F31D5A0080F1EE /* ShnFile.m */; };
8E75758309F31D5A0080F1EE /* SoundFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E75755209F31D5A0080F1EE /* SoundFile.mm */; };
8E75758409F31D5A0080F1EE /* VorbisFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75755409F31D5A0080F1EE /* VorbisFile.m */; };
8E75758609F31D5A0080F1EE /* WavPackFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75755809F31D5A0080F1EE /* WavPackFile.m */; };
@ -84,14 +84,12 @@
8E75774009F31F2A0080F1EE /* MAC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75773F09F31F2A0080F1EE /* MAC.framework */; };
8E75774409F31F370080F1EE /* MPCDec.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75774309F31F370080F1EE /* MPCDec.framework */; };
8E75774709F31F450080F1EE /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75774609F31F450080F1EE /* Ogg.framework */; };
8E75774B09F31F500080F1EE /* Shorten.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75774A09F31F500080F1EE /* Shorten.framework */; };
8E75774E09F31F600080F1EE /* TagLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75774D09F31F600080F1EE /* TagLib.framework */; };
8E75775109F31F6B0080F1EE /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75775009F31F6B0080F1EE /* Vorbis.framework */; };
8E75775409F31F750080F1EE /* WavPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E75775309F31F750080F1EE /* WavPack.framework */; };
8E757B4F09F326710080F1EE /* WavPack.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75775309F31F750080F1EE /* WavPack.framework */; };
8E757B5009F326710080F1EE /* Vorbis.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75775009F31F6B0080F1EE /* Vorbis.framework */; };
8E757B5109F326710080F1EE /* TagLib.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75774D09F31F600080F1EE /* TagLib.framework */; };
8E757B5209F326710080F1EE /* Shorten.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75774A09F31F500080F1EE /* Shorten.framework */; };
8E757B5309F326710080F1EE /* Ogg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75774609F31F450080F1EE /* Ogg.framework */; };
8E757B5409F326710080F1EE /* MPCDec.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75774309F31F370080F1EE /* MPCDec.framework */; };
8E757B5509F326710080F1EE /* MAC.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E75773F09F31F2A0080F1EE /* MAC.framework */; };
@ -127,7 +125,6 @@
8E757B4F09F326710080F1EE /* WavPack.framework in CopyFiles */,
8E757B5009F326710080F1EE /* Vorbis.framework in CopyFiles */,
8E757B5109F326710080F1EE /* TagLib.framework in CopyFiles */,
8E757B5209F326710080F1EE /* Shorten.framework in CopyFiles */,
8E757B5309F326710080F1EE /* Ogg.framework in CopyFiles */,
8E757B5409F326710080F1EE /* MPCDec.framework in CopyFiles */,
8E757B5509F326710080F1EE /* MAC.framework in CopyFiles */,
@ -163,6 +160,7 @@
8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PlaylistHeaderView.m; sourceTree = "<group>"; };
8E4C7F060A0509FC003BE25F /* DragScrollView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DragScrollView.h; sourceTree = "<group>"; };
8E4C7F070A0509FC003BE25F /* DragScrollView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DragScrollView.m; sourceTree = "<group>"; };
8E4CAB5A0A32251B00214C1D /* ShnFile.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = ShnFile.mm; sourceTree = "<group>"; };
8E643DF20A2B585600844A28 /* GameFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameFile.h; sourceTree = "<group>"; };
8E643DF30A2B585600844A28 /* GameFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GameFile.mm; sourceTree = "<group>"; };
8E6A8E270A0D8A68002ABE9C /* CoreAudioFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CoreAudioFile.h; sourceTree = "<group>"; };
@ -221,7 +219,6 @@
8E75754D09F31D5A0080F1EE /* MusepackFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MusepackFile.h; sourceTree = "<group>"; };
8E75754E09F31D5A0080F1EE /* MusepackFile.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MusepackFile.m; sourceTree = "<group>"; };
8E75754F09F31D5A0080F1EE /* ShnFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ShnFile.h; sourceTree = "<group>"; };
8E75755009F31D5A0080F1EE /* ShnFile.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ShnFile.m; sourceTree = "<group>"; };
8E75755109F31D5A0080F1EE /* SoundFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SoundFile.h; sourceTree = "<group>"; };
8E75755209F31D5A0080F1EE /* SoundFile.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = SoundFile.mm; sourceTree = "<group>"; };
8E75755309F31D5A0080F1EE /* VorbisFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VorbisFile.h; sourceTree = "<group>"; };
@ -280,7 +277,6 @@
8E75773F09F31F2A0080F1EE /* MAC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MAC.framework; path = Libraries/MAC/build/Release/MAC.framework; sourceTree = "<group>"; };
8E75774309F31F370080F1EE /* MPCDec.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MPCDec.framework; path = Libraries/MPCDec/build/Release/MPCDec.framework; sourceTree = "<group>"; };
8E75774609F31F450080F1EE /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = Libraries/Ogg/build/Release/Ogg.framework; sourceTree = "<group>"; };
8E75774A09F31F500080F1EE /* Shorten.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Shorten.framework; path = Libraries/Shorten/build/Release/Shorten.framework; sourceTree = "<group>"; };
8E75774D09F31F600080F1EE /* TagLib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TagLib.framework; path = Libraries/TagLib/build/Release/TagLib.framework; sourceTree = "<group>"; };
8E75775009F31F6B0080F1EE /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = Libraries/Vorbis/build/Release/Vorbis.framework; sourceTree = "<group>"; };
8E75775309F31F750080F1EE /* WavPack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WavPack.framework; path = Libraries/WavPack/build/Release/WavPack.framework; sourceTree = "<group>"; };
@ -301,7 +297,6 @@
8E75774009F31F2A0080F1EE /* MAC.framework in Frameworks */,
8E75774409F31F370080F1EE /* MPCDec.framework in Frameworks */,
8E75774709F31F450080F1EE /* Ogg.framework in Frameworks */,
8E75774B09F31F500080F1EE /* Shorten.framework in Frameworks */,
8E75774E09F31F600080F1EE /* TagLib.framework in Frameworks */,
8E75775109F31F6B0080F1EE /* Vorbis.framework in Frameworks */,
8E75775409F31F750080F1EE /* WavPack.framework in Frameworks */,
@ -497,7 +492,7 @@
8E75754D09F31D5A0080F1EE /* MusepackFile.h */,
8E75754E09F31D5A0080F1EE /* MusepackFile.m */,
8E75754F09F31D5A0080F1EE /* ShnFile.h */,
8E75755009F31D5A0080F1EE /* ShnFile.m */,
8E4CAB5A0A32251B00214C1D /* ShnFile.mm */,
8E75755109F31D5A0080F1EE /* SoundFile.h */,
8E75755209F31D5A0080F1EE /* SoundFile.mm */,
8E75755309F31D5A0080F1EE /* VorbisFile.h */,
@ -573,7 +568,6 @@
8E75775309F31F750080F1EE /* WavPack.framework */,
8E75775009F31F6B0080F1EE /* Vorbis.framework */,
8E75774D09F31F600080F1EE /* TagLib.framework */,
8E75774A09F31F500080F1EE /* Shorten.framework */,
8E75774609F31F450080F1EE /* Ogg.framework */,
8E75774309F31F370080F1EE /* MPCDec.framework */,
8E75773F09F31F2A0080F1EE /* MAC.framework */,
@ -704,7 +698,6 @@
8E75757E09F31D5A0080F1EE /* FlacFile.m in Sources */,
8E75757F09F31D5A0080F1EE /* MonkeysFile.mm in Sources */,
8E75758109F31D5A0080F1EE /* MusepackFile.m in Sources */,
8E75758209F31D5A0080F1EE /* ShnFile.m in Sources */,
8E75758309F31D5A0080F1EE /* SoundFile.mm in Sources */,
8E75758409F31D5A0080F1EE /* VorbisFile.m in Sources */,
8E75758609F31D5A0080F1EE /* WavPackFile.m in Sources */,
@ -717,6 +710,7 @@
8E6A8E2C0A0D8A68002ABE9C /* CoreAudioFile.m in Sources */,
8E6A8E380A0D8AD8002ABE9C /* CoreAudioUtils.m in Sources */,
8E1296DB0A2BA9CE00443124 /* PlaylistHeaderView.m in Sources */,
8E4CAB5B0A32251B00214C1D /* ShnFile.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -0,0 +1,77 @@
/*
Millennium Sound System
©1999, Subband Software
Description: GP Ring Buffer
Released: 9/15/99
Version history:
Date Who Changes
--------+---------+------------------------------------------------------
09-15-99 DAB Initial release.
DAB = Dmitry Boldyrev
*/
/*
* 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-1307, USA.
*/
#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__
class RingBuffer
{
public:
RingBuffer();
~RingBuffer();
int Init(long inSize);
long WriteData(char *data, long len);
long ReadData(char *data, long len);
long FreeSpace(bool inTrueSpace = true);
long UsedSpace(bool inTrueSpace = true);
long BufSize()
{
return mBufSize;
}
void Empty();
void SaveRead();
void RestoreRead();
bool IsReadMode()
{
return mSaveFreeSpace == -1;
}
protected:
char* mBuffer;
long mBufSize;
long mBufWxIdx;
long mBufRdIdx;
long mFreeSpace;
long mSaveFreeSpace;
long mSaveReadPos;
};
#endif //__RINGBUFFER_H__

View File

@ -0,0 +1,204 @@
/*
* shn_reader.h
* shorten_decoder
*
* Created by Alex Lagutin on Sun Jul 07 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/* xmms-shn - a shorten (.shn) plugin for XMMS
* Copyright (C) 2000-2001 Jason Jordan (shnutils@freeshell.org)
*
* 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-1307, USA.
*/
/*
* $Id: shn.h,v 1.6 2001/12/30 05:12:04 jason Exp $
*/
#ifndef __SHN_READER_H__
#define __SHN_READER_H__
#include <stdio.h>
#include <pthread.h>
#include "shorten.h"
#include "ringbuffer.h"
/* Derek */
typedef unsigned int uint;
/* surely no headers will be this large. right? RIGHT? */
#define OUT_BUFFER_SIZE 16384
#define NUM_DEFAULT_BUFFER_BLOCKS 512L
#define SEEK_HEADER_SIZE 12
#define SEEK_TRAILER_SIZE 12
#define SEEK_ENTRY_SIZE 80
#define MASKTABSIZE 33
typedef struct _shn_decode_state
{
uchar *getbuf;
uchar *getbufp;
int nbitget;
int nbyteget;
ulong gbuffer;
char *writebuf;
char *writefub;
int nwritebuf;
} shn_decode_state;
typedef struct _shn_seek_header
{
uchar data[SEEK_HEADER_SIZE];
ulong version;
ulong shnFileSize;
} shn_seek_header;
typedef struct _shn_seek_trailer
{
uchar data[SEEK_TRAILER_SIZE];
ulong seekTableSize;
} shn_seek_trailer;
typedef struct _shn_seek_entry
{
uchar data[SEEK_ENTRY_SIZE];
} shn_seek_entry;
typedef struct _shn_wave_header
{
char *filename,
m_ss[16];
uint header_size;
ushort channels,
block_align,
bits_per_sample,
wave_format;
ulong samples_per_sec,
avg_bytes_per_sec,
rate,
length,
data_size,
total_size,
chunk_size,
actual_size;
ulong problems;
} shn_wave_header;
class shn_reader
{
private:
shn_decode_state mDecodeState;
shn_wave_header mWAVEHeader;
shn_seek_header mSeekHeader;
shn_seek_trailer mSeekTrailer;
shn_seek_entry *mSeekTable;
int mSeekTo;
bool mEOF;
bool mGoing;
long mSeekTableEntries;
int mBytesInBuf;
uchar mBuffer[OUT_BUFFER_SIZE];
int mBytesInHeader;
uchar mHeader[OUT_BUFFER_SIZE];
bool mFatalError;
FILE *mFP;
RingBuffer mRing;
pthread_mutex_t mRingLock;
pthread_cond_t mRunCond;
pthread_t mThread;
ulong masktab[MASKTABSIZE];
int sizeof_sample[TYPE_EOF];
public:
shn_reader();
~shn_reader();
int open(const char *fn, bool should_load_seek_table = true);
int go();
void exit();
bool file_info(long *size, int *nch, float *rate, float *time,
int *samplebits, bool *seekable);
long read(void *buf, long size);
float seek(float sec);
int shn_get_buffer_block_size(int blocks);//derek
unsigned int shn_get_song_length();//derek
private:
void init();
void Run();
int get_wave_header();
int verify_header();
void init_decode_state();
void write_and_wait(int block_size);
/* fixio.cpp */
void init_sizeof_sample();
void fwrite_type_init();
void fwrite_type_quit();
void fix_bitshift(slong *buffer, int nitem, int bitshift, int ftype);
void fwrite_type(slong **data,int ftype,int nchan,int nitem);
/* vario.cpp */
void var_get_init();
ulong word_get();
long uvar_get(int nbin);
ulong ulong_get();
long var_get(int nbin);
void var_get_quit();
/* seek.cpp */
void load_seek_table(const char *fn);
int load_separate_seek_table(const char *fn);
shn_seek_entry *seek_entry_search(ulong goal, ulong min, ulong max);
/* array.cpp */
void *pmalloc(ulong size);
slong **long2d(ulong n0, ulong n1);
friend void *thread_runner(shn_reader *reader)
{
reader->Run();
return NULL;
}
};
inline ulong uchar_to_ulong_le(uchar *buf)
/* converts 4 bytes stored in little-endian format to a ulong */
{
return (ulong)((buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]);
}
inline slong uchar_to_slong_le(uchar *buf)
/* converts 4 bytes stored in little-endian format to an slong */
{
return (long)uchar_to_ulong_le(buf);
}
inline ushort uchar_to_ushort_le(uchar *buf)
/* converts 4 bytes stored in little-endian format to a ushort */
{
return (ushort)((buf[1] << 8) + buf[0]);
}
#endif /*__SHN_READER_H__*/

View File

@ -1,3 +1,12 @@
/*
* shorten.h
* shorten_decoder
*
* Created by Alex Lagutin on Sun Jul 07 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/******************************************************************************
* *
* Copyright (C) 1992-1995 Tony Robinson *
@ -7,7 +16,7 @@
******************************************************************************/
/*
* $Id: shorten.h 19 2005-06-07 04:16:15Z vspader $
* $Id: shorten.h,v 1.4 2001/12/30 05:12:04 jason Exp $
*/
#ifndef _SHORTEN_H
@ -18,7 +27,6 @@
#endif
#include <stdlib.h>
#include <pthread.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
@ -49,8 +57,6 @@
#define sshort int16_t
#define schar int8_t
#include "shn.h"
#define MAGIC "ajkg"
#define FORMAT_VERSION 2
#define MIN_SUPPORTED_VERSION 1
@ -155,66 +161,7 @@
#define V2LPCQOFFSET (1 << LPCQUANT);
#define UINT_GET(nbit, file) \
((version == 0) ? uvar_get(nbit, file) : ulong_get(file))
#define putc_exit(val, stream)\
{ char rval;\
if((rval = putc((val), (stream))) != (char) (val))\
complain("FATALERROR: write failed: putc returns EOF");\
}
extern int getc_exit_val;
#define getc_exit(stream)\
(((getc_exit_val = getc(stream)) == EOF) ? \
complain("FATALERROR: read failed: getc returns EOF"), 0: getc_exit_val)
/************************/
/* defined in shorten.c */
extern void init_offset(slong**, int, int, int);
extern int shorten(FILE*, FILE*, int, char**);
/**************************/
/* defined in Sulawalaw.c */
extern int Sulaw2lineartab[];
#define Sulaw2linear(i) (Sulaw2lineartab[i])
#ifndef Sulaw2linear
extern int Sulaw2linear(uchar);
#endif
extern uchar Slinear2ulaw(int);
extern int Salaw2lineartab[];
#define Salaw2linear(i) (Salaw2lineartab[i])
#ifndef Salaw2linear
extern int Salaw2linear(uchar);
#endif
extern uchar Slinear2alaw(int);
/**********************/
/* defined in fixio.c */
extern void init_sizeof_sample(void);
extern void fwrite_type_init(shn_file*);
extern void fwrite_type(slong**,int,int,int,shn_file*);
extern void fwrite_type_quit(shn_file*);
extern void fix_bitshift(slong*, int, int, int);
/**********************/
/* defined in vario.c */
extern void var_get_init(shn_file*);
extern slong uvar_get(int, shn_file*);
extern slong var_get(int, shn_file*);
extern ulong ulong_get(shn_file*);
extern void var_get_quit(shn_file*);
extern int sizeof_uvar(ulong, int);
extern int sizeof_var(slong, int);
extern void mkmasktab(void);
extern ulong word_get(shn_file*);
/**********************/
/* defined in array.c */
extern void* pmalloc(ulong, shn_file*);
extern slong** long2d(ulong, ulong, shn_file*);
#define UINT_GET(nbit) \
((version == 0) ? uvar_get(nbit) : ulong_get())
#endif

View File

@ -0,0 +1,50 @@
/*
* array.cpp
* shorten_decoder
*
* Created by Alex Lagutin on Tue Jul 09 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/******************************************************************************
* *
* Copyright (C) 1992-1995 Tony Robinson *
* *
* See the file doc/LICENSE.shorten for conditions on distribution and usage *
* *
******************************************************************************/
/*
* $Id: array.c,v 1.6 2001/12/30 05:12:04 jason Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include "shn_reader.h"
void *shn_reader::pmalloc(ulong size) {
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
mFatalError = true;
return(ptr);
}
slong **shn_reader::long2d(ulong n0, ulong n1) {
slong **array0 = NULL;
if((array0 = (slong**) pmalloc((ulong) (n0 * sizeof(slong*) +
n0 * n1 * sizeof(slong)))) != NULL ) {
slong *array1 = (slong*) (array0 + n0);
ulong i;
for(i = 0; i < n0; i++)
array0[i] = array1 + i * n1;
}
return(array0);
}

View File

@ -13,6 +13,12 @@
#define FALSE 0
#endif
/* Derek start */
pthread_mutex_t mRingLock;
pthread_cond_t mRunCond;
pthread_t mThread;
/* Derek end */
int shn_seek(shn_file *this_shn, unsigned int time);
int shn_seekable(shn_file *this_shn);
shn_file *shn_load(char *filename, shn_config config);

View File

@ -0,0 +1,302 @@
/*
* fixio.cpp
* shorten_decoder
*
* Created by Alex Lagutin on Tue Jul 09 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/******************************************************************************
* *
* Copyright (C) 1992-1995 Tony Robinson *
* *
* See the file doc/LICENSE.shorten for conditions on distribution and usage *
* *
******************************************************************************/
/*
* $Id: fixio.c,v 1.6 2001/12/30 05:12:04 jason Exp $
*/
#include <string.h>
#include "shn_reader.h"
#include "bitshift.h"
#define CAPMAXSCHAR(x) ((x > 127) ? 127 : x)
#define CAPMAXUCHAR(x) ((x > 255) ? 255 : x)
#define CAPMAXSHORT(x) ((x > 32767) ? 32767 : x)
#define CAPMAXUSHORT(x) ((x > 65535) ? 65535 : x)
extern "C"
{
int Sulaw2linear(uchar);
uchar Slinear2ulaw(int);
uchar Slinear2alaw(int);
}
void shn_reader::init_sizeof_sample() {
sizeof_sample[TYPE_AU1] = sizeof(uchar);
sizeof_sample[TYPE_S8] = sizeof(schar);
sizeof_sample[TYPE_U8] = sizeof(uchar);
sizeof_sample[TYPE_S16HL] = sizeof(ushort);
sizeof_sample[TYPE_U16HL] = sizeof(ushort);
sizeof_sample[TYPE_S16LH] = sizeof(ushort);
sizeof_sample[TYPE_U16LH] = sizeof(ushort);
sizeof_sample[TYPE_ULAW] = sizeof(uchar);
sizeof_sample[TYPE_AU2] = sizeof(uchar);
sizeof_sample[TYPE_AU3] = sizeof(uchar);
sizeof_sample[TYPE_ALAW] = sizeof(uchar);
}
/***************/
/* fixed write */
/***************/
void shn_reader::fwrite_type_init()
{
init_sizeof_sample();
mDecodeState.writebuf = (char*) NULL;
mDecodeState.writefub = (char*) NULL;
mDecodeState.nwritebuf = 0;
}
void shn_reader::fwrite_type_quit() {
if(mDecodeState.writebuf != NULL) {
free(mDecodeState.writebuf);
mDecodeState.writebuf = NULL;
}
if(mDecodeState.writefub != NULL) {
free(mDecodeState.writefub);
mDecodeState.writefub = NULL;
}
}
/* convert from signed ints to a given type and write */
void shn_reader::fwrite_type(slong **data,int ftype,int nchan,int nitem)
{
int hiloint = 1, hilo = !(*((char*) &hiloint));
int i, nwrite = 0, datasize = sizeof_sample[ftype], chan;
slong *data0 = data[0];
int bufAvailable = OUT_BUFFER_SIZE - mBytesInBuf;
if(mDecodeState.nwritebuf < nchan * nitem * datasize) {
mDecodeState.nwritebuf = nchan * nitem * datasize;
if(mDecodeState.writebuf != NULL) free(mDecodeState.writebuf);
if(mDecodeState.writefub != NULL) free(mDecodeState.writefub);
mDecodeState.writebuf = (char*) pmalloc((ulong) mDecodeState.nwritebuf);
if (!mDecodeState.writebuf)
return;
mDecodeState.writefub = (char*) pmalloc((ulong) mDecodeState.nwritebuf);
if (!mDecodeState.writefub)
return;
}
switch(ftype) {
case TYPE_AU1: /* leave the conversion to fix_bitshift() */
case TYPE_AU2: {
uchar *writebufp = (uchar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = data0[i];
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = data[chan][i];
break;
}
case TYPE_U8: {
uchar *writebufp = (uchar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = CAPMAXUCHAR(data0[i]);
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = CAPMAXUCHAR(data[chan][i]);
break;
}
case TYPE_S8: {
schar *writebufp = (schar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = CAPMAXSCHAR(data0[i]);
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = CAPMAXSCHAR(data[chan][i]);
break;
}
case TYPE_S16HL:
case TYPE_S16LH: {
short *writebufp = (short*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = CAPMAXSHORT(data0[i]);
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = CAPMAXSHORT(data[chan][i]);
break;
}
case TYPE_U16HL:
case TYPE_U16LH: {
ushort *writebufp = (ushort*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = CAPMAXUSHORT(data0[i]);
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = CAPMAXUSHORT(data[chan][i]);
break;
}
case TYPE_ULAW: {
uchar *writebufp = (uchar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = Slinear2ulaw(CAPMAXSHORT((data0[i] << 3)));
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = Slinear2ulaw(CAPMAXSHORT((data[chan][i] << 3)));
break;
}
case TYPE_AU3: {
uchar *writebufp = (uchar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
if(data0[i] < 0)
*writebufp++ = (127 - data0[i]) ^ 0xd5;
else
*writebufp++ = (data0[i] + 128) ^ 0x55;
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
if(data[chan][i] < 0)
*writebufp++ = (127 - data[chan][i]) ^ 0xd5;
else
*writebufp++ = (data[chan][i] + 128) ^ 0x55;
break;
}
case TYPE_ALAW: {
uchar *writebufp = (uchar*) mDecodeState.writebuf;
if(nchan == 1)
for(i = 0; i < nitem; i++)
*writebufp++ = Slinear2alaw(CAPMAXSHORT((data0[i] << 3)));
else
for(i = 0; i < nitem; i++)
for(chan = 0; chan < nchan; chan++)
*writebufp++ = Slinear2alaw(CAPMAXSHORT((data[chan][i] << 3)));
break;
}
}
switch(ftype) {
case TYPE_AU1:
case TYPE_S8:
case TYPE_U8:
case TYPE_ULAW:
case TYPE_AU2:
case TYPE_AU3:
case TYPE_ALAW:
if (datasize*nchan*nitem <= bufAvailable) {
memcpy((void *)&mBuffer[mBytesInBuf],(const void *)mDecodeState.writebuf,datasize*nchan*nitem);
mBytesInBuf += datasize*nchan*nitem;
nwrite = nitem;
}
else
{
// fprintf(stderr, "Buffer overrun in fwrite_type() [case 1]: %d bytes to read, but only %d bytes are available\n",datasize*nchan*nitem,bufAvailable);
}
break;
case TYPE_S16HL:
case TYPE_U16HL:
if(hilo)
{
if (datasize*nchan*nitem <= bufAvailable) {
memcpy((void *)&mBuffer[mBytesInBuf],(const void *)mDecodeState.writebuf,datasize*nchan*nitem);
mBytesInBuf += datasize*nchan*nitem;
nwrite = nitem;
}
else
{
//fprintf(stderr, "Buffer overrun in fwrite_type() [case 2]: %d bytes to read, but only %d bytes are available\n",datasize*nchan*nitem,bufAvailable);
}
}
else
{
swab(mDecodeState.writebuf, mDecodeState.writefub, datasize * nchan * nitem);
if (datasize*nchan*nitem <= bufAvailable) {
memcpy((void *)&mBuffer[mBytesInBuf],(const void *)mDecodeState.writefub,datasize*nchan*nitem);
mBytesInBuf += datasize*nchan*nitem;
nwrite = nitem;
}
else
{
//fprintf(stderr, "Buffer overrun in fwrite_type() [case 3]: %d bytes to read, but only %d bytes are available\n",datasize*nchan*nitem,bufAvailable);
}
}
break;
case TYPE_S16LH:
case TYPE_U16LH:
if(hilo)
{
swab(mDecodeState.writebuf, mDecodeState.writefub, datasize * nchan * nitem);
if (datasize*nchan*nitem <= bufAvailable) {
memcpy((void *)&mBuffer[mBytesInBuf],(const void *)mDecodeState.writefub,datasize*nchan*nitem);
mBytesInBuf += datasize*nchan*nitem;
nwrite = nitem;
}
else
{
//fprintf(stderr, "Buffer overrun in fwrite_type() [case 4]: %d bytes to read, but only %d bytes are available\n",datasize*nchan*nitem,bufAvailable);
}
}
else
{
if (datasize*nchan*nitem <= bufAvailable) {
memcpy((void *)&mBuffer[mBytesInBuf],(const void *)mDecodeState.writebuf,datasize*nchan*nitem);
mBytesInBuf += datasize*nchan*nitem;
nwrite = nitem;
}
else
{
//fprintf(stderr, "Buffer overrun in fwrite_type() [case 5]: %d bytes to read, but only %d bytes are available\n",datasize*nchan*nitem,bufAvailable);
}
}
break;
}
if(nwrite != nitem)
{
mFatalError = true;
//fprintf(stderr,"Failed to write decompressed stream -\npossible corrupt or truncated file\n");
}
}
/*************/
/* bitshifts */
/*************/
void shn_reader::fix_bitshift(slong *buffer, int nitem, int bitshift, int ftype)
{
int i;
if(ftype == TYPE_AU1)
for(i = 0; i < nitem; i++)
buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
else if(ftype == TYPE_AU2)
for(i = 0; i < nitem; i++) {
if(buffer[i] >= 0)
buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
else if(buffer[i] == -1)
buffer[i] = NEGATIVE_ULAW_ZERO;
else
buffer[i] = ulaw_outward[bitshift][buffer[i] + 129];
}
else
if(bitshift != 0)
for(i = 0; i < nitem; i++)
buffer[i] <<= bitshift;
}

View File

@ -0,0 +1,197 @@
/*
Millennium Sound System
©1999-2000 Subband Software, Inc.
Description: GP Ring Buffer class
Released: 9/15/99
Version history:
Date Who Changes
--------+---------+------------------------------------------------------
06-19-00 AVL parameter types changes, conflicting function names fixed,
IsFreeSpace() changed to IsReadMode(), ReadDataCR() removed.
09-15-99 DAB Initial release.
DAB = Dmitry Boldyrev
AVL = Alex Lagutin
*/
/*
* 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-1307, USA.
*/
#include <string.h>
#include "ringbuffer.h"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
RingBuffer::RingBuffer()
{
mFreeSpace=0;
mBuffer=NULL;
mBufSize=0;
mBufRdIdx=0;
mBufWxIdx=0;
mSaveFreeSpace=-1;
}
int RingBuffer::Init(long inSize)
{
mBufSize=inSize;
if (mBuffer) {
delete[] mBuffer;
}
if ((mBuffer = new char[mBufSize]) == NULL)
return -1;
Empty();
return 0;
}
void
RingBuffer::Empty()
{
mBufRdIdx=0;
mBufWxIdx=0;
mFreeSpace=mBufSize;
mSaveFreeSpace=-1;
// if (mBuffer) {
// memset(mBuffer, 0, mBufSize);
// }
}
RingBuffer::~RingBuffer()
{
if (mBuffer) {
delete[] mBuffer;
}
mBuffer=NULL;
}
long RingBuffer::WriteData(char *data, long len)
{
int written, before;
if (!mBufSize || data==NULL || !mBuffer)
return 0;
written=0;
if (!(len = MIN(FreeSpace(false), len)))
return 0;
while (1)
{
if (len + mBufWxIdx < mBufSize)
{
::memcpy(&mBuffer[mBufWxIdx], &data[written], (size_t) len);
mBufWxIdx += len;
written += len;
mFreeSpace -= len;
if (mSaveFreeSpace != -1)
mSaveFreeSpace -= len;
return written;
} else
{
before = mBufSize - mBufWxIdx;
::memcpy(&mBuffer[mBufWxIdx], &data[written], (size_t) before);
written += before;
len -= before;
mFreeSpace -= before;
if (mSaveFreeSpace != -1)
mSaveFreeSpace -= before;
mBufWxIdx = 0;
}
}
}
void RingBuffer::SaveRead()
{
if (mSaveFreeSpace!=-1)
return;
mSaveReadPos=mBufRdIdx;
mSaveFreeSpace=mFreeSpace;
}
void RingBuffer::RestoreRead()
{
if (mSaveFreeSpace==-1)
return;
mBufRdIdx=mSaveReadPos;
mFreeSpace=mSaveFreeSpace;
mSaveFreeSpace=-1;
}
long RingBuffer::ReadData(char *data, long len)
{
int read, before;
if (!mBufSize) return 0;
read = 0;
if (!(len = MIN(UsedSpace(true), len)))
return 0;
while (1)
{
if (len + mBufRdIdx < mBufSize)
{
if (data) {
::memcpy(&data[read], &mBuffer[mBufRdIdx], (size_t) len);
}
mBufRdIdx += len;
read += len;
mFreeSpace += len;
return read;
} else
{
before = mBufSize - mBufRdIdx;
if (data) {
::memcpy(&data[read], &mBuffer[mBufRdIdx], (size_t) before);
}
read += before;
len -= before;
mFreeSpace += before;
mBufRdIdx = 0;
}
}
}
long RingBuffer::FreeSpace(bool inTrueSpace)
{
if (inTrueSpace)
return mFreeSpace;
else
return (mSaveFreeSpace==-1) ? mFreeSpace : mSaveFreeSpace;
}
long RingBuffer::UsedSpace(bool inTrueSpace)
{
if (inTrueSpace)
return (mBufSize - mFreeSpace);
else
return (mSaveFreeSpace==-1) ? (mBufSize - mFreeSpace) :
(mBufSize - mSaveFreeSpace);
}

View File

@ -0,0 +1,157 @@
/*
* seek.cpp
* shorten_decoder
*
* Created by Alex Lagutin on Tue Jul 09 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/* seek.c - functions related to real-time seeking
* Copyright (C) 2000-2001 Jason Jordan (shnutils@freeshell.org)
*
* 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-1307, USA.
*/
/*
* $Id: seek.c,v 1.4 2001/12/30 05:12:04 jason Exp $
*/
#include <string.h>
#include "shn_reader.h"
#define SEEK_HEADER_SIGNATURE "SEEK"
#define SEEK_TRAILER_SIGNATURE "SHNAMPSK"
#define SEEK_SUFFIX ".skt"
shn_seek_entry *shn_reader::seek_entry_search(ulong goal, ulong min, ulong max)
{
ulong med = (min + max) / 2;
shn_seek_entry *middle = &mSeekTable[med];
ulong sample = uchar_to_ulong_le(middle->data);
if (goal < sample)
return seek_entry_search(goal, min, med-1);
if (goal > sample + 25600)
return seek_entry_search(goal, med+1, max);
return middle;
}
void shn_reader::load_seek_table(const char *fn)
{
FILE *fp;
int found = 0;
if (!(fp = fopen(fn, "r")))
return;
fseek(fp, -SEEK_TRAILER_SIZE, SEEK_END);
if (fread(mSeekTrailer.data, 1, SEEK_TRAILER_SIZE, fp) == SEEK_TRAILER_SIZE)
{
mSeekTrailer.seekTableSize = uchar_to_ulong_le(mSeekTrailer.data);
if (!memcmp(&mSeekTrailer.data[4], SEEK_TRAILER_SIGNATURE, strlen(SEEK_TRAILER_SIGNATURE)))
{
fseek(fp, -mSeekTrailer.seekTableSize, SEEK_END);
mSeekTrailer.seekTableSize -= (SEEK_HEADER_SIZE + SEEK_TRAILER_SIZE);
if (fread(mSeekHeader.data, 1, SEEK_HEADER_SIZE, fp) == SEEK_HEADER_SIZE)
{
long entries = mSeekTrailer.seekTableSize/sizeof(shn_seek_entry);
if ((mSeekTable = (shn_seek_entry *) malloc(sizeof(shn_seek_entry)*entries)))
{
if ((long)fread(mSeekTable, sizeof(shn_seek_entry), entries, fp) == entries)
{
//fprintf(stderr, "Successfully loaded seek table appended to file: '%s'\n", fn);
mSeekTableEntries = entries;
found = 1;
}
else
{
free(mSeekTable);
mSeekTable = NULL;
}
}
}
}
}
fclose(fp);
if (found)
return;
{
// try load from separate seek file
char *slash, *ext;
char seek_fn[MAX_PATH];
strcpy(seek_fn, fn);
slash = strrchr(seek_fn, '/');
ext = strrchr((slash ? slash : seek_fn), '.');
if (ext)
*ext = 0;
strcat(seek_fn, SEEK_SUFFIX);
load_separate_seek_table(seek_fn);
}
}
int shn_reader::load_separate_seek_table(const char *fn)
{
FILE *fp;
long seek_table_len, entries;
int result = 0;
//fprintf(stderr, "Looking for seek table in separate file: '%s'\n", fn);
if (!(fp = fopen(fn, "r")))
return 0;
fseek(fp, 0, SEEK_END);
seek_table_len = (long)ftell(fp) - SEEK_HEADER_SIZE;
entries = seek_table_len/sizeof(shn_seek_entry);
fseek(fp, 0, SEEK_SET);
if (fread(mSeekHeader.data, 1, SEEK_HEADER_SIZE, fp) == SEEK_HEADER_SIZE)
{
mSeekHeader.version = uchar_to_ulong_le(&mSeekHeader.data[4]);
mSeekHeader.shnFileSize = uchar_to_ulong_le(&mSeekHeader.data[8]);
if (!memcmp(mSeekHeader.data, SEEK_HEADER_SIGNATURE, strlen(SEEK_HEADER_SIGNATURE)))
{
if (mSeekHeader.shnFileSize == mWAVEHeader.actual_size)
{
if ((mSeekTable = (shn_seek_entry *) malloc(sizeof(shn_seek_entry)*entries)))
{
if ((long)fread(mSeekTable, sizeof(shn_seek_entry), entries, fp) == entries)
{
//fprintf(stderr, "Successfully loaded seek table in separate file: '%s'\n", fn);
mSeekTableEntries = entries;
}
else
{
free(mSeekTable);
mSeekTable = NULL;
}
}
}
else
{
//fprintf(stderr, "Seek table .shn file size and actual .shn file size differ\n");
}
}
}
fclose(fp);
return result;
}

View File

@ -0,0 +1,979 @@
/*
* shn_reader.cpp
* shorten_decoder
*
* Created by Alex Lagutin on Sun Jul 07 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/* shn.c - main functions for xmms-shn
* Copyright (C) 2000-2001 Jason Jordan (shnutils@freeshell.org)
*
* 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-1307, USA.
*/
/*
* $Id: shn.c,v 1.9 2001/12/30 05:12:04 jason Exp $
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/stat.h>
#include "shn_reader.h"
#define WAVE_RIFF (0x46464952) /* 'RIFF' in little-endian */
#define WAVE_WAVE (0x45564157) /* 'WAVE' in little-endian */
#define WAVE_FMT (0x20746d66) /* ' fmt' in little-endian */
#define WAVE_DATA (0x61746164) /* 'data' in little-endian */
#define WAVE_FORMAT_PCM (0x0001)
#define CANONICAL_HEADER_SIZE (44)
#define CACHE_SIZE (256*1024) //256K
static void init_offset(slong **offset,int nchan,int nblock,int ftype)
{
slong mean = 0;
int chan, i;
/* initialise offset */
switch(ftype)
{
case TYPE_AU1:
case TYPE_S8:
case TYPE_S16HL:
case TYPE_S16LH:
case TYPE_ULAW:
case TYPE_AU2:
case TYPE_AU3:
case TYPE_ALAW:
mean = 0;
break;
case TYPE_U8:
mean = 0x80;
break;
case TYPE_U16HL:
case TYPE_U16LH:
mean = 0x8000;
break;
default:
//fprintf(stderr, "Unknown file type: %d\n", ftype);
break;
}
for(chan = 0; chan < nchan; chan++)
for(i = 0; i < nblock; i++)
offset[chan][i] = mean;
}
shn_reader::shn_reader()
{
init();
pthread_mutex_init(&mRingLock, NULL);
pthread_cond_init(&mRunCond, NULL);
}
shn_reader::~shn_reader()
{
exit();
pthread_mutex_destroy(&mRingLock);
pthread_cond_destroy(&mRunCond);
}
void shn_reader::init()
{
mSeekTable = NULL;
mSeekTo = -1;
mFP = NULL;
mFatalError = false;
mGoing = false;
mEOF = false;
memset(&mDecodeState, 0, sizeof(mDecodeState));
memset(&mWAVEHeader, 0, sizeof(mWAVEHeader));
mRing.Init(CACHE_SIZE);
}
void shn_reader::exit()
{
if (mGoing)
{
mGoing = false;
pthread_cond_signal(&mRunCond);
pthread_join(mThread, NULL);
}
if (mDecodeState.getbuf)
{
free(mDecodeState.getbuf);
mDecodeState.getbuf = NULL;
}
if (mDecodeState.writebuf)
{
free(mDecodeState.writebuf);
mDecodeState.writebuf = NULL;
}
if (mDecodeState.writefub)
{
free(mDecodeState.writefub);
mDecodeState.writefub = NULL;
}
if (mSeekTable)
{
free(mSeekTable);
mSeekTable = NULL;
}
if (mFP)
{
fclose(mFP);
mFP = NULL;
}
}
int shn_reader::open(const char *fn, bool should_load_seek_table)
{
struct stat sz;
exit();
init();
if (stat(fn, &sz))
return -1;
if (!S_ISREG(sz.st_mode))
return -1;
mWAVEHeader.actual_size = (ulong)sz.st_size;
mFP = fopen(fn, "r");
if (!mFP)
return -1;
if (!get_wave_header() || !verify_header())
{
fclose(mFP);
mFP = NULL;
return -1;
}
if (should_load_seek_table)
load_seek_table(fn);
return 0;
}
int shn_reader::go()
{
if (!mFP)
return -1;
fseek(mFP, 0, SEEK_SET);
mGoing = true;
if (pthread_create(&mThread, NULL, (void *(*)(void *))thread_runner, this))
{
mGoing = false;
return -1;
}
return 0;
}
long shn_reader::read(void *buf, long size)
{
long actread;
if (!mGoing)
return -2;
pthread_mutex_lock(&mRingLock);
actread = mRing.ReadData((char *) buf, size);
if (!actread)
actread = mEOF ? -2 : -1;
pthread_mutex_unlock(&mRingLock);
if (actread > 0)
pthread_cond_signal(&mRunCond);
return actread;
}
float shn_reader::seek(float seconds)
{
if (!mSeekTable)
return -1.0f;
mSeekTo = (int) seconds;
shn_seek_entry *seek_info = seek_entry_search(mSeekTo * (ulong)mWAVEHeader.samples_per_sec,0,
(ulong)(mSeekTableEntries - 1));
ulong sample = uchar_to_ulong_le(seek_info->data);
return (float)sample/((float)mWAVEHeader.samples_per_sec);
}
int shn_reader::shn_get_buffer_block_size(int blocks)//derek
{
int blk_size = blocks * (mWAVEHeader.bits_per_sample / 8) * mWAVEHeader.channels;
if(blk_size > OUT_BUFFER_SIZE)
{
blk_size = NUM_DEFAULT_BUFFER_BLOCKS * (mWAVEHeader.bits_per_sample / 8) * mWAVEHeader.channels;
}
return blk_size;
}
unsigned int shn_reader::shn_get_song_length()//derek
{
if(mWAVEHeader.length > 0)
return (unsigned int)(1000 * mWAVEHeader.length);
/* Something failed or just isn't correct */
return (unsigned int)0;
}
bool shn_reader::file_info(long *size, int *nch, float *rate, float *time,
int *samplebits, bool *seekable)
{
float frate;
int frame_size;
if (!mFP)
return false;
if (seekable)
*seekable = mSeekTable ? true : false;
if (size)
*size = mWAVEHeader.actual_size;
if (nch)
*nch = mWAVEHeader.channels;
frame_size = (uint)mWAVEHeader.channels * (uint)mWAVEHeader.bits_per_sample / 8;
frate = (float)mWAVEHeader.samples_per_sec;
if (rate)
*rate = frate;
if (time)
*time = (float)mWAVEHeader.data_size/((float)frame_size * frate);
if (samplebits)
*samplebits = mWAVEHeader.bits_per_sample;
return true;
}
void shn_reader::init_decode_state()
{
if (mDecodeState.getbuf)
free(mDecodeState.getbuf);
if (mDecodeState.writebuf)
free(mDecodeState.writebuf);
if (mDecodeState.writefub)
free(mDecodeState.writefub);
memset(&mDecodeState, 0, sizeof(mDecodeState));
}
int shn_reader::get_wave_header()
{
int version = FORMAT_VERSION;
int ftype = TYPE_EOF;
char *magic = MAGIC;
int internal_ftype;
int retval = 1;
init_decode_state();
mBytesInHeader = 0;
/***********************/
/* EXTRACT starts here */
/***********************/
/* read magic number */
#ifdef STRICT_FORMAT_COMPATABILITY
if(FORMAT_VERSION < 2)
{
for(int i = 0; i < strlen(magic); i++)
if(getc(mFP) != magic[i])
return 0;
/* get version number */
version = getc(mFP);
if (version == EOF)
return 0;
}
else
#endif /* STRICT_FORMAT_COMPATABILITY */
{
int nscan = 0;
version = MAX_VERSION + 1;
while(version > MAX_VERSION)
{
int byte = getc(mFP);
if(byte == EOF)
return 0;
if(magic[nscan] != '\0' && byte == magic[nscan])
nscan++;
else
if(magic[nscan] == '\0' && byte <= MAX_VERSION)
version = byte;
else
{
if(byte == magic[0])
nscan = 1;
else
{
nscan = 0;
}
version = MAX_VERSION + 1;
}
}
}
/* check version number */
if(version > MAX_SUPPORTED_VERSION)
return 0;
/* initialise the variable length file read for the compressed stream */
var_get_init();
if (mFatalError)
return 0;
/* get the internal file type */
internal_ftype = UINT_GET(TYPESIZE);
/* has the user requested a change in file type? */
if(internal_ftype != ftype) {
if(ftype == TYPE_EOF)
ftype = internal_ftype; /* no problems here */
else /* check that the requested conversion is valid */
if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3)
goto got_enough_data;
}
UINT_GET(CHANSIZE);
/* get blocksize if version > 0 */
if(version > 0)
{
int byte, nskip;
UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2));
UINT_GET(LPCQSIZE);
UINT_GET(0);
nskip = UINT_GET(NSKIPSIZE);
for(int i = 0; i < nskip; i++)
{
byte = uvar_get(XBYTESIZE);
}
}
/* find verbatim command */
while(1)
{
int cmd = uvar_get(FNSIZE);
switch(cmd)
{
case FN_VERBATIM:
{
int cklen = uvar_get(VERBATIM_CKSIZE_SIZE);
while (cklen--)
{
if (mBytesInHeader >= OUT_BUFFER_SIZE)
{
retval = 0;
goto got_enough_data;
}
mBytesInBuf = 0;
mHeader[mBytesInHeader++] = (unsigned char)uvar_get(VERBATIM_BYTE_SIZE);
}
}
break;
default:
goto got_enough_data;
}
}
got_enough_data:
/* wind up */
var_get_quit();
mBytesInBuf = 0;
return retval;
}
int shn_reader::verify_header()
{
ulong l;
int cur = 0;
if (mBytesInHeader < CANONICAL_HEADER_SIZE)
return 0;
if (WAVE_RIFF != uchar_to_ulong_le(&mHeader[cur]))
return 0;
cur += 4;
mWAVEHeader.chunk_size = uchar_to_ulong_le(&mHeader[cur]);
cur += 4;
if (WAVE_WAVE != uchar_to_ulong_le(&mHeader[cur]))
return 0;
cur += 4;
for (;;)
{
cur += 4;
l = uchar_to_ulong_le(&mHeader[cur]);
cur += 4;
if (WAVE_FMT == uchar_to_ulong_le(&mHeader[cur-8]))
break;
cur += l;
}
if (l < 16)
return 0;
mWAVEHeader.wave_format = uchar_to_ushort_le(&mHeader[cur]);
cur += 2;
switch (mWAVEHeader.wave_format)
{
case WAVE_FORMAT_PCM:
break;
default:
return 0;
}
mWAVEHeader.channels = uchar_to_ushort_le(&mHeader[cur]);
cur += 2;
mWAVEHeader.samples_per_sec = uchar_to_ulong_le(&mHeader[cur]);
cur += 4;
mWAVEHeader.avg_bytes_per_sec = uchar_to_ulong_le(&mHeader[cur]);
cur += 4;
mWAVEHeader.block_align = uchar_to_ushort_le(&mHeader[cur]);
cur += 2;
mWAVEHeader.bits_per_sample = uchar_to_ushort_le(&mHeader[cur]);
cur += 2;
if (mWAVEHeader.bits_per_sample != 8 && mWAVEHeader.bits_per_sample != 16)
return 0;
l -= 16;
if (l > 0)
cur += l;
for (;;)
{
cur += 4;
l = uchar_to_ulong_le(&mHeader[cur]);
cur += 4;
if (WAVE_DATA == uchar_to_ulong_le(&mHeader[cur-8]))
break;
cur += l;
}
mWAVEHeader.rate = ((uint)mWAVEHeader.samples_per_sec *
(uint)mWAVEHeader.channels *
(uint)mWAVEHeader.bits_per_sample) / 8;
mWAVEHeader.header_size = cur;
mWAVEHeader.data_size = l;
mWAVEHeader.total_size = mWAVEHeader.chunk_size + 8;
mWAVEHeader.length = mWAVEHeader.data_size / mWAVEHeader.rate;
/* header looks ok */
return 1;
}
void shn_reader::write_and_wait(int block_size)
{
int bytes_to_write;
if (mBytesInBuf < block_size)
return;
bytes_to_write = MIN(mBytesInBuf, block_size);
if (bytes_to_write <= 0)
return;
while (mGoing && mSeekTo == -1)
{
long written;
pthread_mutex_lock(&mRingLock);
written = mRing.WriteData((char *) mBuffer, bytes_to_write);
bytes_to_write -= written;
mBytesInBuf -= written;
if (!bytes_to_write)
{
pthread_mutex_unlock(&mRingLock);
break;
}
pthread_cond_wait(&mRunCond, &mRingLock);
pthread_mutex_unlock(&mRingLock);
}
}
void shn_reader::Run()
{
slong **buffer = NULL, **offset = NULL;
slong lpcqoffset = 0;
int version = FORMAT_VERSION, bitshift = 0;
int ftype = TYPE_EOF;
char *magic = MAGIC;
int blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN;
int i, chan, nwrap, nskip = DEFAULT_NSKIP;
int *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT;
int cmd;
int internal_ftype;
int blk_size;
int cklen;
uchar tmp;
restart:
mBytesInBuf = 0;
init_decode_state();
blk_size = 512 * (mWAVEHeader.bits_per_sample / 8) * mWAVEHeader.channels;
/***********************/
/* EXTRACT starts here */
/***********************/
/* read magic number */
#ifdef STRICT_FORMAT_COMPATABILITY
if(FORMAT_VERSION < 2)
{
for(i = 0; i < strlen(magic); i++)
if(getc(this_shn->vars.fd) != magic[i])
{
mFatalError = true;
goto exit_thread;
}
/* get version number */
version = getc(this_shn->vars.fd);
if (version == EOF)
{
mFatalError = true;
goto exit_thread;
}
}
else
#endif /* STRICT_FORMAT_COMPATABILITY */
{
int nscan = 0;
version = MAX_VERSION + 1;
while(version > MAX_VERSION)
{
int byte = getc(mFP);
if(byte == EOF) {
mFatalError = true;
goto exit_thread;
}
if(magic[nscan] != '\0' && byte == magic[nscan])
nscan++;
else
if(magic[nscan] == '\0' && byte <= MAX_VERSION)
version = byte;
else
{
if(byte == magic[0])
nscan = 1;
else
{
nscan = 0;
}
version = MAX_VERSION + 1;
}
}
}
/* check version number */
if(version > MAX_SUPPORTED_VERSION) {
mFatalError = true;
goto exit_thread;
}
/* set up the default nmean, ignoring the command line state */
nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN;
/* initialise the variable length file read for the compressed stream */
var_get_init();
if (mFatalError)
goto exit_thread;
/* initialise the fixed length file write for the uncompressed stream */
fwrite_type_init();
/* get the internal file type */
internal_ftype = UINT_GET(TYPESIZE);
/* has the user requested a change in file type? */
if(internal_ftype != ftype) {
if(ftype == TYPE_EOF)
ftype = internal_ftype; /* no problems here */
else /* check that the requested conversion is valid */
if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3) {
mFatalError = true;
goto cleanup;
}
}
nchan = UINT_GET(CHANSIZE);
/* get blocksize if version > 0 */
if(version > 0)
{
int byte;
blocksize = UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2));
maxnlpc = UINT_GET(LPCQSIZE);
nmean = UINT_GET(0);
nskip = UINT_GET(NSKIPSIZE);
for(i = 0; i < nskip; i++)
{
byte = uvar_get(XBYTESIZE);
}
}
else
blocksize = DEFAULT_BLOCK_SIZE;
nwrap = MAX(NWRAP, maxnlpc);
/* grab some space for the input buffer */
buffer = long2d((ulong) nchan, (ulong) (blocksize + nwrap));
if (mFatalError)
goto exit_thread;
offset = long2d((ulong) nchan, (ulong) MAX(1, nmean));
if (mFatalError) {
if (buffer) {
free(buffer);
buffer = NULL;
}
goto exit_thread;
}
for(chan = 0; chan < nchan; chan++)
{
for(i = 0; i < nwrap; i++)
buffer[chan][i] = 0;
buffer[chan] += nwrap;
}
if(maxnlpc > 0) {
qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc)));
if (mFatalError) {
if (buffer) {
free(buffer);
buffer = NULL;
}
if (offset) {
free(offset);
buffer = NULL;
}
goto exit_thread;
}
}
if(version > 1)
lpcqoffset = V2LPCQOFFSET;
init_offset(offset, nchan, MAX(1, nmean), internal_ftype);
/* get commands from file and execute them */
chan = 0;
while(1)
{
cmd = uvar_get(FNSIZE);
if (mFatalError)
goto cleanup;
switch(cmd)
{
case FN_ZERO:
case FN_DIFF0:
case FN_DIFF1:
case FN_DIFF2:
case FN_DIFF3:
case FN_QLPC:
{
slong coffset, *cbuffer = buffer[chan];
int resn = 0, nlpc, j;
if(cmd != FN_ZERO)
{
resn = uvar_get(ENERGYSIZE);
if (mFatalError)
goto cleanup;
/* this is a hack as version 0 differed in definition of var_get */
if(version == 0)
resn--;
}
/* find mean offset : N.B. this code duplicated */
if(nmean == 0)
coffset = offset[chan][0];
else
{
slong sum = (version < 2) ? 0 : nmean / 2;
for(i = 0; i < nmean; i++)
sum += offset[chan][i];
if(version < 2)
coffset = sum / nmean;
else
coffset = ROUNDEDSHIFTDOWN(sum / nmean, bitshift);
}
switch(cmd)
{
case FN_ZERO:
for(i = 0; i < blocksize; i++)
cbuffer[i] = 0;
break;
case FN_DIFF0:
for(i = 0; i < blocksize; i++) {
cbuffer[i] = var_get(resn) + coffset;
if (mFatalError)
goto cleanup;
}
break;
case FN_DIFF1:
for(i = 0; i < blocksize; i++) {
cbuffer[i] = var_get(resn) + cbuffer[i - 1];
if (mFatalError)
goto cleanup;
}
break;
case FN_DIFF2:
for(i = 0; i < blocksize; i++) {
cbuffer[i] = var_get(resn) + (2 * cbuffer[i - 1] - cbuffer[i - 2]);
if (mFatalError)
goto cleanup;
}
break;
case FN_DIFF3:
for(i = 0; i < blocksize; i++) {
cbuffer[i] = var_get(resn) + 3 * (cbuffer[i - 1] - cbuffer[i - 2]) + cbuffer[i - 3];
if (mFatalError)
goto cleanup;
}
break;
case FN_QLPC:
nlpc = uvar_get(LPCQSIZE);
if (mFatalError)
goto cleanup;
for(i = 0; i < nlpc; i++) {
qlpc[i] = var_get(LPCQUANT);
if (mFatalError)
goto cleanup;
}
for(i = 0; i < nlpc; i++)
cbuffer[i - nlpc] -= coffset;
for(i = 0; i < blocksize; i++)
{
slong sum = lpcqoffset;
for(j = 0; j < nlpc; j++)
sum += qlpc[j] * cbuffer[i - j - 1];
cbuffer[i] = var_get(resn) + (sum >> LPCQUANT);
if (mFatalError)
goto cleanup;
}
if(coffset != 0)
for(i = 0; i < blocksize; i++)
cbuffer[i] += coffset;
break;
}
/* store mean value if appropriate : N.B. Duplicated code */
if(nmean > 0)
{
slong sum = (version < 2) ? 0 : blocksize / 2;
for(i = 0; i < blocksize; i++)
sum += cbuffer[i];
for(i = 1; i < nmean; i++)
offset[chan][i - 1] = offset[chan][i];
if(version < 2)
offset[chan][nmean - 1] = sum / blocksize;
else
offset[chan][nmean - 1] = (sum / blocksize) << bitshift;
}
/* do the wrap */
for(i = -nwrap; i < 0; i++)
cbuffer[i] = cbuffer[i + blocksize];
fix_bitshift(cbuffer, blocksize, bitshift, internal_ftype);
if(chan == nchan - 1)
{
if (!mGoing || mFatalError)
goto cleanup;
fwrite_type(buffer, ftype, nchan, blocksize);
write_and_wait(blk_size);
if (mSeekTo != -1)
{
shn_seek_entry *seek_info = seek_entry_search(mSeekTo * (ulong)mWAVEHeader.samples_per_sec,0,
(ulong)(mSeekTableEntries - 1));
pthread_mutex_lock(&mRingLock);
mRing.Empty();
pthread_mutex_unlock(&mRingLock);
buffer[0][-1] = uchar_to_slong_le(seek_info->data+24);
buffer[0][-2] = uchar_to_slong_le(seek_info->data+28);
buffer[0][-3] = uchar_to_slong_le(seek_info->data+32);
offset[0][0] = uchar_to_slong_le(seek_info->data+48);
offset[0][1] = uchar_to_slong_le(seek_info->data+52);
offset[0][2] = uchar_to_slong_le(seek_info->data+56);
offset[0][3] = uchar_to_slong_le(seek_info->data+60);
if (nchan > 1)
{
buffer[1][-1] = uchar_to_slong_le(seek_info->data+36);
buffer[1][-2] = uchar_to_slong_le(seek_info->data+40);
buffer[1][-3] = uchar_to_slong_le(seek_info->data+44);
offset[1][0] = uchar_to_slong_le(seek_info->data+64);
offset[1][1] = uchar_to_slong_le(seek_info->data+68);
offset[1][2] = uchar_to_slong_le(seek_info->data+72);
offset[1][3] = uchar_to_slong_le(seek_info->data+76);
}
bitshift = uchar_to_ushort_le(seek_info->data+22);
fseek(mFP,(slong)uchar_to_ulong_le(seek_info->data+8),SEEK_SET);
fread((uchar*) mDecodeState.getbuf, 1, BUFSIZ, mFP);
mDecodeState.getbufp = mDecodeState.getbuf + uchar_to_ushort_le(seek_info->data+14);
mDecodeState.nbitget = uchar_to_ushort_le(seek_info->data+16);
mDecodeState.nbyteget = uchar_to_ushort_le(seek_info->data+12);
mDecodeState.gbuffer = uchar_to_ulong_le(seek_info->data+18);
mBytesInBuf = 0;
mSeekTo = -1;
}
}
chan = (chan + 1) % nchan;
break;
}
break;
case FN_QUIT:
/* empty out last of buffer */
write_and_wait(mBytesInBuf);
mEOF = true;
while (1)
{
if (!mGoing)
goto finish;
if (mSeekTo != -1)
{
var_get_quit();
fwrite_type_quit();
if (buffer) free((void *) buffer);
if (offset) free((void *) offset);
if(maxnlpc > 0 && qlpc)
free((void *) qlpc);
fseek(mFP,0,SEEK_SET);
goto restart;
}
}
goto cleanup;
break;
case FN_BLOCKSIZE:
blocksize = UINT_GET((int) (log((double) blocksize) / M_LN2));
if (mFatalError)
goto cleanup;
break;
case FN_BITSHIFT:
bitshift = uvar_get(BITSHIFTSIZE);
if (mFatalError)
goto cleanup;
break;
case FN_VERBATIM:
cklen = uvar_get(VERBATIM_CKSIZE_SIZE);
if (mFatalError)
goto cleanup;
while (cklen--) {
tmp = (uchar)uvar_get(VERBATIM_BYTE_SIZE);
if (mFatalError)
goto cleanup;
}
break;
default:
mFatalError = true;
//fprintf(stderr,"Sanity check fails trying to decode function: %d\n",cmd);
goto cleanup;
}
}
cleanup:
write_and_wait(mBytesInBuf);
finish:
mSeekTo = -1;
mEOF = true;
/* wind up */
var_get_quit();
fwrite_type_quit();
if (buffer) free((void *) buffer);
if (offset) free((void *) offset);
if(maxnlpc > 0 && qlpc)
free((void *) qlpc);
exit_thread:
pthread_exit(NULL);
}

View File

@ -1,5 +1,5 @@
/*
* $Id: sulawalaw.c 19 2005-06-07 04:16:15Z vspader $
* $Id: sulawalaw.c,v 1.5 2001/12/30 05:12:04 jason Exp $
*/
#include <stdio.h>

View File

@ -0,0 +1,139 @@
/*
* vario.cpp
* shorten_decoder
*
* Created by Alex Lagutin on Tue Jul 09 2002.
* Copyright (c) 2002 Eckysoft All rights reserved.
*
*/
/******************************************************************************
* *
* Copyright (C) 1992-1995 Tony Robinson *
* *
* See the file doc/LICENSE.shorten for conditions on distribution and usage *
* *
******************************************************************************/
/*
* $Id: vario.c,v 1.6 2001/12/30 05:12:04 jason Exp $
*/
#include "shn_reader.h"
void shn_reader::var_get_init()
{
int i;
ulong val = 0;
masktab[0] = val;
for (i = 1; i < MASKTABSIZE; i++)
{
val <<= 1;
val |= 1;
masktab[i] = val;
}
mDecodeState.getbuf = (uchar *) malloc(BUFSIZ);
mDecodeState.getbufp = mDecodeState.getbuf;
mDecodeState.nbyteget = 0;
mDecodeState.gbuffer = 0;
mDecodeState.nbitget = 0;
if (!mDecodeState.getbuf)
mFatalError = true;
}
ulong shn_reader::word_get()
{
ulong buffer;
if (mDecodeState.nbyteget < 4)
{
mDecodeState.nbyteget += fread(mDecodeState.getbuf, 1, BUFSIZ, mFP);
if (mDecodeState.nbyteget < 4)
{
mFatalError = true;
return 0;
}
mDecodeState.getbufp = mDecodeState.getbuf;
}
buffer = (((long) (mDecodeState.getbufp[0])) << 24) | (((long) (mDecodeState.getbufp[1])) << 16)
| (((long) (mDecodeState.getbufp[2])) << 8) | ((long) (mDecodeState.getbufp[3]));
mDecodeState.getbufp += 4;
mDecodeState.nbyteget -= 4;
return buffer;
}
long shn_reader::uvar_get(int nbin)
{
long result;
if (!mDecodeState.nbitget)
{
mDecodeState.gbuffer = word_get();
if (mFatalError)
return 0;
mDecodeState.nbitget = 32;
}
for (result = 0; !(mDecodeState.gbuffer & (1L << --(mDecodeState.nbitget))); result++)
{
if (!mDecodeState.nbitget)
{
mDecodeState.gbuffer = word_get();
if (mFatalError)
return 0;
mDecodeState.nbitget = 32;
}
}
while (nbin)
{
if(mDecodeState.nbitget >= nbin)
{
result = (result << nbin) | ((mDecodeState.gbuffer >> (mDecodeState.nbitget-nbin)) & masktab[nbin]);
mDecodeState.nbitget -= nbin;
nbin = 0;
}
else
{
result = (result << mDecodeState.nbitget) | (mDecodeState.gbuffer & masktab[mDecodeState.nbitget]);
mDecodeState.gbuffer = word_get();
if (mFatalError)
return 0;
nbin -= mDecodeState.nbitget;
mDecodeState.nbitget = 32;
}
}
return result;
}
ulong shn_reader::ulong_get()
{
uint nbit = uvar_get(ULONGSIZE);
if (mFatalError)
return 0;
return uvar_get(nbit);
}
long shn_reader::var_get(int nbin)
{
ulong uvar = uvar_get(nbin + 1);
if (mFatalError)
return 0;
return ((uvar & 1) ? ((long) ~(uvar >> 1)) : ((long) (uvar >> 1)));
}
void shn_reader::var_get_quit()
{
free(mDecodeState.getbuf);
mDecodeState.getbuf = NULL;
}

View File

@ -7,62 +7,54 @@
objects = {
/* Begin PBXBuildFile section */
597A37500A2A2C9A00730CFA /* bitshift.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDCD5D0A29226D006C1800 /* bitshift.h */; settings = {ATTRIBUTES = (Public, ); }; };
597A37510A2A2C9A00730CFA /* ringbuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDCD5E0A29226D006C1800 /* ringbuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
597A37520A2A2C9A00730CFA /* shn_reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDCD5F0A29226D006C1800 /* shn_reader.h */; settings = {ATTRIBUTES = (Public, ); }; };
597A37530A2A2C9A00730CFA /* shorten.h in Headers */ = {isa = PBXBuildFile; fileRef = 59FDCD600A29226D006C1800 /* shorten.h */; settings = {ATTRIBUTES = (Public, ); }; };
59F1214E0A311CD40052FE42 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F1214D0A311CD40052FE42 /* config.h */; settings = {ATTRIBUTES = (Public, ); }; };
59FDCD6C0A2922E1006C1800 /* array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD650A2922E1006C1800 /* array.cpp */; };
59FDCD6D0A2922E1006C1800 /* fixio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD660A2922E1006C1800 /* fixio.cpp */; };
59FDCD6E0A2922E1006C1800 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD670A2922E1006C1800 /* ringbuffer.cpp */; };
59FDCD6F0A2922E1006C1800 /* seek.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD680A2922E1006C1800 /* seek.cpp */; };
59FDCD700A2922E1006C1800 /* shn_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD690A2922E1006C1800 /* shn_reader.cpp */; };
59FDCD710A2922E1006C1800 /* sulawalaw.c in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD6A0A2922E1006C1800 /* sulawalaw.c */; };
59FDCD720A2922E1006C1800 /* vario.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59FDCD6B0A2922E1006C1800 /* vario.cpp */; };
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
8E756C7109F3174E0080F1EE /* bitshift.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E756C6C09F3174E0080F1EE /* bitshift.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E756C7209F3174E0080F1EE /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E756C6D09F3174E0080F1EE /* config.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E756C7309F3174E0080F1EE /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E756C6E09F3174E0080F1EE /* decode.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E756C7409F3174E0080F1EE /* shn.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E756C6F09F3174E0080F1EE /* shn.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E756C7509F3174E0080F1EE /* shorten.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E756C7009F3174E0080F1EE /* shorten.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E756C8609F317680080F1EE /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7A09F317680080F1EE /* array.c */; };
8E756C8709F317680080F1EE /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7B09F317680080F1EE /* convert.c */; };
8E756C8809F317680080F1EE /* decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7C09F317680080F1EE /* decode.c */; };
8E756C8909F317680080F1EE /* fixio.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7D09F317680080F1EE /* fixio.c */; };
8E756C8A09F317680080F1EE /* id3v2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7E09F317680080F1EE /* id3v2.c */; };
8E756C8B09F317680080F1EE /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C7F09F317680080F1EE /* misc.c */; };
8E756C8C09F317680080F1EE /* output.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8009F317680080F1EE /* output.c */; };
8E756C8D09F317680080F1EE /* seek.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8109F317680080F1EE /* seek.c */; };
8E756C8E09F317680080F1EE /* shorten.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8209F317680080F1EE /* shorten.c */; };
8E756C8F09F317680080F1EE /* sulawalaw.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8309F317680080F1EE /* sulawalaw.c */; };
8E756C9009F317680080F1EE /* vario.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8409F317680080F1EE /* vario.c */; };
8E756C9109F317680080F1EE /* wave.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E756C8509F317680080F1EE /* wave.c */; };
/* End PBXBuildFile section */
/* Begin PBXBuildStyle section */
014CEA440018CDF011CA2923 /* Debug */ = {
8E8303D10A3226D3008E1F34 /* Development */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = NO;
};
name = Debug;
name = Development;
};
014CEA450018CDF011CA2923 /* Release */ = {
8E8303D20A3226D3008E1F34 /* Deployment */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = YES;
};
name = Release;
name = Deployment;
};
/* End PBXBuildStyle section */
/* Begin PBXFileReference section */
089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
59F1214D0A311CD40052FE42 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = Files/shorten/include/config.h; sourceTree = "<group>"; };
59FDCD5D0A29226D006C1800 /* bitshift.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = bitshift.h; path = Files/shorten/include/bitshift.h; sourceTree = "<group>"; };
59FDCD5E0A29226D006C1800 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ringbuffer.h; path = Files/shorten/include/ringbuffer.h; sourceTree = "<group>"; };
59FDCD5F0A29226D006C1800 /* shn_reader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = shn_reader.h; path = Files/shorten/include/shn_reader.h; sourceTree = "<group>"; };
59FDCD600A29226D006C1800 /* shorten.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = shorten.h; path = Files/shorten/include/shorten.h; sourceTree = "<group>"; };
59FDCD650A2922E1006C1800 /* array.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = array.cpp; path = Files/shorten/src/array.cpp; sourceTree = "<group>"; };
59FDCD660A2922E1006C1800 /* fixio.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = fixio.cpp; path = Files/shorten/src/fixio.cpp; sourceTree = "<group>"; };
59FDCD670A2922E1006C1800 /* ringbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ringbuffer.cpp; path = Files/shorten/src/ringbuffer.cpp; sourceTree = "<group>"; };
59FDCD680A2922E1006C1800 /* seek.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = seek.cpp; path = Files/shorten/src/seek.cpp; sourceTree = "<group>"; };
59FDCD690A2922E1006C1800 /* shn_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = shn_reader.cpp; path = Files/shorten/src/shn_reader.cpp; sourceTree = "<group>"; };
59FDCD6A0A2922E1006C1800 /* sulawalaw.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sulawalaw.c; path = Files/shorten/src/sulawalaw.c; sourceTree = "<group>"; };
59FDCD6B0A2922E1006C1800 /* vario.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = vario.cpp; path = Files/shorten/src/vario.cpp; sourceTree = "<group>"; };
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8DC2EF5B0486A6940098B216 /* Shorten.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Shorten.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8E756C6C09F3174E0080F1EE /* bitshift.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = bitshift.h; path = Files/shorten/include/bitshift.h; sourceTree = "<group>"; };
8E756C6D09F3174E0080F1EE /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = Files/shorten/include/config.h; sourceTree = "<group>"; };
8E756C6E09F3174E0080F1EE /* decode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = decode.h; path = Files/shorten/include/decode.h; sourceTree = "<group>"; };
8E756C6F09F3174E0080F1EE /* shn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = shn.h; path = Files/shorten/include/shn.h; sourceTree = "<group>"; };
8E756C7009F3174E0080F1EE /* shorten.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = shorten.h; path = Files/shorten/include/shorten.h; sourceTree = "<group>"; };
8E756C7A09F317680080F1EE /* array.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = array.c; path = Files/shorten/src/array.c; sourceTree = "<group>"; };
8E756C7B09F317680080F1EE /* convert.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = convert.c; path = Files/shorten/src/convert.c; sourceTree = "<group>"; };
8E756C7C09F317680080F1EE /* decode.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = decode.c; path = Files/shorten/src/decode.c; sourceTree = "<group>"; };
8E756C7D09F317680080F1EE /* fixio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = fixio.c; path = Files/shorten/src/fixio.c; sourceTree = "<group>"; };
8E756C7E09F317680080F1EE /* id3v2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = id3v2.c; path = Files/shorten/src/id3v2.c; sourceTree = "<group>"; };
8E756C7F09F317680080F1EE /* misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = misc.c; path = Files/shorten/src/misc.c; sourceTree = "<group>"; };
8E756C8009F317680080F1EE /* output.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = output.c; path = Files/shorten/src/output.c; sourceTree = "<group>"; };
8E756C8109F317680080F1EE /* seek.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = seek.c; path = Files/shorten/src/seek.c; sourceTree = "<group>"; };
8E756C8209F317680080F1EE /* shorten.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = shorten.c; path = Files/shorten/src/shorten.c; sourceTree = "<group>"; };
8E756C8309F317680080F1EE /* sulawalaw.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sulawalaw.c; path = Files/shorten/src/sulawalaw.c; sourceTree = "<group>"; };
8E756C8409F317680080F1EE /* vario.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vario.c; path = Files/shorten/src/vario.c; sourceTree = "<group>"; };
8E756C8509F317680080F1EE /* wave.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wave.c; path = Files/shorten/src/wave.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -131,18 +123,13 @@
8E756C6A09F317170080F1EE /* Source */ = {
isa = PBXGroup;
children = (
8E756C7A09F317680080F1EE /* array.c */,
8E756C7B09F317680080F1EE /* convert.c */,
8E756C7C09F317680080F1EE /* decode.c */,
8E756C7D09F317680080F1EE /* fixio.c */,
8E756C7E09F317680080F1EE /* id3v2.c */,
8E756C7F09F317680080F1EE /* misc.c */,
8E756C8009F317680080F1EE /* output.c */,
8E756C8109F317680080F1EE /* seek.c */,
8E756C8209F317680080F1EE /* shorten.c */,
8E756C8309F317680080F1EE /* sulawalaw.c */,
8E756C8409F317680080F1EE /* vario.c */,
8E756C8509F317680080F1EE /* wave.c */,
59FDCD650A2922E1006C1800 /* array.cpp */,
59FDCD660A2922E1006C1800 /* fixio.cpp */,
59FDCD670A2922E1006C1800 /* ringbuffer.cpp */,
59FDCD680A2922E1006C1800 /* seek.cpp */,
59FDCD690A2922E1006C1800 /* shn_reader.cpp */,
59FDCD6A0A2922E1006C1800 /* sulawalaw.c */,
59FDCD6B0A2922E1006C1800 /* vario.cpp */,
);
name = Source;
sourceTree = "<group>";
@ -150,11 +137,11 @@
8E756C6B09F3171C0080F1EE /* Headers */ = {
isa = PBXGroup;
children = (
8E756C6C09F3174E0080F1EE /* bitshift.h */,
8E756C6D09F3174E0080F1EE /* config.h */,
8E756C6E09F3174E0080F1EE /* decode.h */,
8E756C6F09F3174E0080F1EE /* shn.h */,
8E756C7009F3174E0080F1EE /* shorten.h */,
59F1214D0A311CD40052FE42 /* config.h */,
59FDCD5D0A29226D006C1800 /* bitshift.h */,
59FDCD5E0A29226D006C1800 /* ringbuffer.h */,
59FDCD5F0A29226D006C1800 /* shn_reader.h */,
59FDCD600A29226D006C1800 /* shorten.h */,
);
name = Headers;
sourceTree = "<group>";
@ -162,15 +149,15 @@
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
8DC2EF500486A6940098B216 /* Headers */ = {
597A374E0A2A2C5300730CFA /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8E756C7109F3174E0080F1EE /* bitshift.h in Headers */,
8E756C7209F3174E0080F1EE /* config.h in Headers */,
8E756C7309F3174E0080F1EE /* decode.h in Headers */,
8E756C7409F3174E0080F1EE /* shn.h in Headers */,
8E756C7509F3174E0080F1EE /* shorten.h in Headers */,
597A37500A2A2C9A00730CFA /* bitshift.h in Headers */,
597A37510A2A2C9A00730CFA /* ringbuffer.h in Headers */,
597A37520A2A2C9A00730CFA /* shn_reader.h in Headers */,
597A37530A2A2C9A00730CFA /* shorten.h in Headers */,
59F1214E0A311CD40052FE42 /* config.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -181,15 +168,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Shorten" */;
buildPhases = (
8DC2EF500486A6940098B216 /* Headers */,
597A374E0A2A2C5300730CFA /* Headers */,
8DC2EF520486A6940098B216 /* Resources */,
8DC2EF540486A6940098B216 /* Sources */,
8DC2EF560486A6940098B216 /* Frameworks */,
);
buildRules = (
);
buildSettings = {
};
dependencies = (
);
name = Shorten;
@ -207,8 +192,8 @@
buildSettings = {
};
buildStyles = (
014CEA440018CDF011CA2923 /* Debug */,
014CEA450018CDF011CA2923 /* Release */,
8E8303D10A3226D3008E1F34 /* Development */,
8E8303D20A3226D3008E1F34 /* Deployment */,
);
hasScannedForEncodings = 1;
mainGroup = 0867D691FE84028FC02AAC07 /* Shorten */;
@ -236,18 +221,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8E756C8609F317680080F1EE /* array.c in Sources */,
8E756C8709F317680080F1EE /* convert.c in Sources */,
8E756C8809F317680080F1EE /* decode.c in Sources */,
8E756C8909F317680080F1EE /* fixio.c in Sources */,
8E756C8A09F317680080F1EE /* id3v2.c in Sources */,
8E756C8B09F317680080F1EE /* misc.c in Sources */,
8E756C8C09F317680080F1EE /* output.c in Sources */,
8E756C8D09F317680080F1EE /* seek.c in Sources */,
8E756C8E09F317680080F1EE /* shorten.c in Sources */,
8E756C8F09F317680080F1EE /* sulawalaw.c in Sources */,
8E756C9009F317680080F1EE /* vario.c in Sources */,
8E756C9109F317680080F1EE /* wave.c in Sources */,
59FDCD6C0A2922E1006C1800 /* array.cpp in Sources */,
59FDCD6D0A2922E1006C1800 /* fixio.cpp in Sources */,
59FDCD6E0A2922E1006C1800 /* ringbuffer.cpp in Sources */,
59FDCD6F0A2922E1006C1800 /* seek.cpp in Sources */,
59FDCD700A2922E1006C1800 /* shn_reader.cpp in Sources */,
59FDCD710A2922E1006C1800 /* sulawalaw.c in Sources */,
59FDCD720A2922E1006C1800 /* vario.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -315,6 +295,12 @@
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
.,
../include,
../../include,
include,
);
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
@ -325,6 +311,12 @@
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
.,
../include,
../../include,
include,
);
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};

View File

@ -7,18 +7,18 @@
//
#import <Cocoa/Cocoa.h>
#import <Shorten/shn_reader.h>
#import "SoundFile.h"
#import "Shorten/shorten.h"
#import "Shorten/shn.h"
#import "Shorten/decode.h"
@interface ShnFile : SoundFile {
shn_file *handle;
//shn_file *handle;
shn_reader *decoder;
int bufferSize; //total size
long bufferSize; //total size
void *buffer;
int bufferAmount; //amount currently in
void *inputBuffer;//derek
long bufferAmount; //amount currently in
}
@end

View File

@ -1,115 +0,0 @@
//
// ShnFile.m
// Cog
//
// Created by Vincent Spader on 6/6/05.
// Copyright 2005 Vincent Spader All rights reserved.
//
#import "ShnFile.h"
@implementation ShnFile
- (BOOL)open:(const char *)filename
{
if ([self readInfo:filename] == NO)
return NO;
bufferSize = shn_get_buffer_block_size(handle, 512);
buffer = malloc(bufferSize);
return YES;
}
- (BOOL)readInfo:(const char *)filename
{
shn_config conf;
int r;
conf.error_output_method = ERROR_OUTPUT_DEVNULL;
conf.seek_tables_path = NULL;
conf.relative_seek_tables_path = ".";
conf.verbose = 0;
conf.swap_bytes = 0;
handle = shn_load((char *)filename, conf);
if (!handle)
return NO;
r = shn_init_decoder(handle);
if (r < 0)
return NO;
channels = shn_get_channels(handle);
frequency = shn_get_samplerate(handle);
bitsPerSample = shn_get_bitspersample(handle);
unsigned int length;
length = shn_get_song_length(handle);
totalSize = (((double)(length)*frequency)/1000.0) * channels * (bitsPerSample/8);
bitRate = (int)((double)totalSize/((double)length/1000.0));
return YES;
}
- (int)fillBuffer:(void *)buf ofSize:(UInt32)size
{
int numread = bufferAmount;
int count = 0;
//Fill from buffer, going by bufferAmount
//if still needs more, decode and repeat
if (bufferAmount == 0)
{
bufferAmount = shn_read(handle, buffer, bufferSize);
if (bufferAmount == 0)
return 0;
}
count = bufferAmount;
if (bufferAmount > size)
{
count = size;
}
memcpy(buf, buffer, count);
bufferAmount -= count;
if (bufferAmount > 0)
memmove(buffer, &buffer[count], bufferAmount);
if (count < size)
numread = [self fillBuffer:(&((char *)buf)[count]) ofSize:(size - count)];
else
numread = 0;
return count + numread;
}
- (double)seekToTime:(double)milliseconds
{
unsigned int sec;
if (!shn_seekable(handle))
return -1.0;
sec = (int)(milliseconds/1000.0);
shn_seek(handle, sec);
return (sec * 1000.0);
}
- (void)close
{
if (buffer)
free(buffer);
if (shn_cleanup_decoder(handle))
shn_unload(handle);
}
@end