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