1 #include "debug.h" 2 #include "input_speex.h" 3 4 5 namespace audiere { 6 7 class FileReader : public speexfile::Reader { 8 private: 9 FilePtr m_file; 10 bool m_seekable; 11 12 public: FileReader(FilePtr file)13 FileReader(FilePtr file) { 14 m_file = file; 15 16 // Hacky test to see whether we can seek in the file. 17 m_seekable = m_file->seek(0, File::BEGIN); 18 } 19 read(void * ptr,int size)20 int read(void* ptr, int size) { 21 return m_file->read(ptr, size); 22 } 23 seek(speexfile::offset_t offset)24 speexfile::offset_t seek(speexfile::offset_t offset) { 25 m_file->seek(static_cast<int>(offset), File::BEGIN); 26 return get_position(); 27 } 28 get_position()29 speexfile::offset_t get_position() { 30 return m_file->tell(); 31 } 32 get_length()33 speexfile::offset_t get_length() { 34 speexfile::offset_t c = get_position(); 35 m_file->seek(0, File::END); 36 speexfile::offset_t l = get_position(); 37 m_file->seek(static_cast<int>(c), File::BEGIN); 38 return l; 39 } 40 can_seek()41 bool can_seek() { 42 return m_seekable; 43 } 44 }; 45 46 SpeexInputStream()47 SpeexInputStream::SpeexInputStream() { 48 m_speexfile = 0; 49 m_position = 0; 50 } 51 52 ~SpeexInputStream()53 SpeexInputStream::~SpeexInputStream() { 54 delete m_speexfile; 55 } 56 57 58 /// @todo this really should be replaced with a factory function 59 bool initialize(FilePtr file)60 SpeexInputStream::initialize(FilePtr file) { 61 #if defined(_MSC_VER) && (_MSC_VER <= 1200) 62 m_reader = std::auto_ptr<speexfile::Reader>(new FileReader(file)); 63 #else 64 m_reader.reset(new FileReader(file)); 65 #endif 66 m_speexfile = new speexfile::speexfile(m_reader.get()); 67 68 // @todo How should we handle files with multiple streams? 69 if (m_speexfile->get_streams() != 1) { 70 delete m_speexfile; 71 m_speexfile = 0; 72 return false; 73 } 74 75 speexfile::int32_t rate = m_speexfile->stream_get_samplerate(); 76 speexfile::int32_t channels = m_speexfile->stream_get_channels(); 77 if (rate == 0 || channels == 0) { 78 delete m_speexfile; 79 m_speexfile = 0; 80 return false; 81 } 82 83 for (int i = 0; i < m_speexfile->stream_get_tagcount(); ++i) { 84 const speexfile::speextags* tag = m_speexfile->stream_get_tags()[i]; 85 addTag( 86 tag->item ? tag->item : "", 87 tag->value ? tag->value : "", 88 "Speex"); 89 } 90 91 return true; 92 } 93 94 95 void getFormat(int & channel_count,int & sample_rate,SampleFormat & sample_format)96 SpeexInputStream::getFormat( 97 int& channel_count, 98 int& sample_rate, 99 SampleFormat& sample_format) 100 { 101 channel_count = m_speexfile->stream_get_channels(); 102 sample_rate = m_speexfile->stream_get_samplerate(); 103 sample_format = SF_S16; 104 } 105 106 107 int doRead(int frame_count,void * buffer)108 SpeexInputStream::doRead(int frame_count, void* buffer) { 109 s16* out = (s16*)buffer; 110 111 int total_read = 0; 112 while (frame_count > 0) { 113 // If the buffer is empty, decode a little from the speex file. 114 if (m_read_buffer.getSize() == 0) { 115 float decode_buffer[2000]; // Size defined by speexfile API. 116 int speex_read = m_speexfile->decode(decode_buffer); 117 if (speex_read == 0) { 118 break; 119 } 120 121 m_read_buffer.write(decode_buffer, speex_read * sizeof(float)); 122 } 123 124 const int BUFFER_SIZE = 1024; 125 float read_buffer[BUFFER_SIZE]; 126 127 int should_read = std::min(frame_count, BUFFER_SIZE); 128 int actual_read = m_read_buffer.read(read_buffer, should_read * sizeof(float)) / sizeof(float); 129 ADR_ASSERT(actual_read != 0, "Read queue should have data"); 130 131 for (int i = 0; i < actual_read; ++i) { 132 out[i] = s16(read_buffer[i] * 32767); 133 } 134 135 frame_count -= actual_read; 136 total_read += actual_read; 137 out += actual_read; 138 } 139 m_position += total_read; 140 return total_read; 141 } 142 143 144 void reset()145 SpeexInputStream::reset() { 146 setPosition(0); // need to update m_position 147 } 148 149 150 bool isSeekable()151 SpeexInputStream::isSeekable() { 152 return true; 153 } 154 155 156 int getLength()157 SpeexInputStream::getLength() { 158 return static_cast<int>(m_speexfile->get_samples()); 159 } 160 161 162 void setPosition(int position)163 SpeexInputStream::setPosition(int position) { 164 m_speexfile->seek_sample(position); 165 m_position = position; 166 } 167 168 169 int getPosition()170 SpeexInputStream::getPosition() { 171 return m_position; 172 } 173 174 } 175