Mercurial > hg > easaier-soundaccess
comparison data/fileio/MP3FileReader.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 | |
2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
3 | |
4 /* | |
5 Sonic Visualiser | |
6 An audio file viewer and annotation editor. | |
7 Centre for Digital Music, Queen Mary, University of London. | |
8 This file copyright 2006 Chris Cannam. | |
9 | |
10 This program is free software; you can redistribute it and/or | |
11 modify it under the terms of the GNU General Public License as | |
12 published by the Free Software Foundation; either version 2 of the | |
13 License, or (at your option) any later version. See the file | |
14 COPYING included with this distribution for more information. | |
15 */ | |
16 | |
17 #ifdef HAVE_MAD | |
18 | |
19 #include "MP3FileReader.h" | |
20 #include "system/System.h" | |
21 | |
22 #include <sys/types.h> | |
23 #include <sys/stat.h> | |
24 #include <fcntl.h> | |
25 | |
26 #include <iostream> | |
27 | |
28 #include <QApplication> | |
29 #include <QFileInfo> | |
30 #include <QProgressDialog> | |
31 | |
32 MP3FileReader::MP3FileReader(QString path, bool showProgress, CacheMode mode) : | |
33 CodedAudioFileReader(mode), | |
34 m_path(path) | |
35 { | |
36 m_frameCount = 0; | |
37 m_channelCount = 0; | |
38 m_sampleRate = 0; | |
39 m_fileSize = 0; | |
40 m_bitrateNum = 0; | |
41 m_bitrateDenom = 0; | |
42 m_frameCount = 0; | |
43 m_cancelled = false; | |
44 | |
45 struct stat stat; | |
46 if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { | |
47 m_error = QString("File %1 does not exist.").arg(path); | |
48 return; | |
49 } | |
50 | |
51 m_fileSize = stat.st_size; | |
52 | |
53 int fd = -1; | |
54 if ((fd = ::open(path.toLocal8Bit().data(), O_RDONLY | |
55 #ifdef _WIN32 | |
56 | O_BINARY | |
57 #endif | |
58 , 0)) < 0) { | |
59 m_error = QString("Failed to open file %1 for reading.").arg(path); | |
60 return; | |
61 } | |
62 | |
63 unsigned char *filebuffer = 0; | |
64 | |
65 try { | |
66 filebuffer = new unsigned char[m_fileSize]; | |
67 } catch (...) { | |
68 m_error = QString("Out of memory"); | |
69 ::close(fd); | |
70 return; | |
71 } | |
72 | |
73 ssize_t sz = 0; | |
74 size_t offset = 0; | |
75 while (offset < m_fileSize) { | |
76 sz = ::read(fd, filebuffer + offset, m_fileSize - offset); | |
77 if (sz < 0) { | |
78 m_error = QString("Read error for file %1 (after %2 bytes)") | |
79 .arg(path).arg(offset); | |
80 delete[] filebuffer; | |
81 ::close(fd); | |
82 return; | |
83 } else if (sz == 0) { | |
84 std::cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") | |
85 .arg(offset).arg(m_fileSize).toStdString() << std::endl; | |
86 m_fileSize = offset; | |
87 break; | |
88 } | |
89 offset += sz; | |
90 } | |
91 | |
92 ::close(fd); | |
93 | |
94 if (showProgress) { | |
95 m_progress = new QProgressDialog | |
96 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), | |
97 QObject::tr("Stop"), 0, 100); | |
98 m_progress->hide(); | |
99 } | |
100 | |
101 if (!decode(filebuffer, m_fileSize)) { | |
102 m_error = QString("Failed to decode file %1.").arg(path); | |
103 delete[] filebuffer; | |
104 return; | |
105 } | |
106 | |
107 if (isDecodeCacheInitialised()) finishDecodeCache(); | |
108 | |
109 if (showProgress) { | |
110 delete m_progress; | |
111 m_progress = 0; | |
112 } | |
113 | |
114 delete[] filebuffer; | |
115 } | |
116 | |
117 MP3FileReader::~MP3FileReader() | |
118 { | |
119 } | |
120 | |
121 bool | |
122 MP3FileReader::decode(void *mm, size_t sz) | |
123 { | |
124 DecoderData data; | |
125 struct mad_decoder decoder; | |
126 | |
127 data.start = (unsigned char const *)mm; | |
128 data.length = (unsigned long)sz; | |
129 data.reader = this; | |
130 | |
131 mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0); | |
132 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); | |
133 mad_decoder_finish(&decoder); | |
134 | |
135 return true; | |
136 } | |
137 | |
138 enum mad_flow | |
139 MP3FileReader::input(void *dp, struct mad_stream *stream) | |
140 { | |
141 DecoderData *data = (DecoderData *)dp; | |
142 | |
143 if (!data->length) return MAD_FLOW_STOP; | |
144 mad_stream_buffer(stream, data->start, data->length); | |
145 data->length = 0; | |
146 | |
147 return MAD_FLOW_CONTINUE; | |
148 } | |
149 | |
150 enum mad_flow | |
151 MP3FileReader::output(void *dp, | |
152 struct mad_header const *header, | |
153 struct mad_pcm *pcm) | |
154 { | |
155 DecoderData *data = (DecoderData *)dp; | |
156 return data->reader->accept(header, pcm); | |
157 } | |
158 | |
159 enum mad_flow | |
160 MP3FileReader::accept(struct mad_header const *header, | |
161 struct mad_pcm *pcm) | |
162 { | |
163 int channels = pcm->channels; | |
164 int frames = pcm->length; | |
165 | |
166 if (header) { | |
167 m_bitrateNum += header->bitrate; | |
168 m_bitrateDenom ++; | |
169 } | |
170 | |
171 if (frames < 1) return MAD_FLOW_CONTINUE; | |
172 | |
173 if (m_channelCount == 0) { | |
174 m_channelCount = channels; | |
175 m_sampleRate = pcm->samplerate; | |
176 } | |
177 | |
178 if (m_bitrateDenom > 0) { | |
179 double bitrate = m_bitrateNum / m_bitrateDenom; | |
180 double duration = double(m_fileSize * 8) / bitrate; | |
181 double elapsed = double(m_frameCount) / m_sampleRate; | |
182 double percent = ((elapsed * 100.0) / duration); | |
183 int progress = int(percent); | |
184 if (progress < 1) progress = 1; | |
185 if (progress > 99) progress = 99; | |
186 if (progress > m_progress->value()) { | |
187 m_progress->setValue(progress); | |
188 m_progress->show(); | |
189 m_progress->raise(); | |
190 qApp->processEvents(); | |
191 if (m_progress->wasCanceled()) { | |
192 m_cancelled = true; | |
193 } | |
194 } | |
195 } | |
196 | |
197 if (m_cancelled) return MAD_FLOW_STOP; | |
198 | |
199 m_frameCount += frames; | |
200 | |
201 if (!isDecodeCacheInitialised()) { | |
202 initialiseDecodeCache(); | |
203 } | |
204 | |
205 for (int i = 0; i < frames; ++i) { | |
206 | |
207 for (int ch = 0; ch < channels; ++ch) { | |
208 mad_fixed_t sample = 0; | |
209 if (ch < int(sizeof(pcm->samples) / sizeof(pcm->samples[0]))) { | |
210 sample = pcm->samples[ch][i]; | |
211 } | |
212 float fsample = float(sample) / float(MAD_F_ONE); | |
213 addSampleToDecodeCache(fsample); | |
214 } | |
215 | |
216 if (! (i & 0xffff)) { | |
217 // periodically munlock to ensure we don't exhaust real memory | |
218 // if running with memory locked down | |
219 MUNLOCK_SAMPLEBLOCK(m_data); | |
220 } | |
221 } | |
222 | |
223 if (frames > 0) { | |
224 MUNLOCK_SAMPLEBLOCK(m_data); | |
225 } | |
226 | |
227 return MAD_FLOW_CONTINUE; | |
228 } | |
229 | |
230 enum mad_flow | |
231 MP3FileReader::error(void *dp, | |
232 struct mad_stream *stream, | |
233 struct mad_frame *) | |
234 { | |
235 DecoderData *data = (DecoderData *)dp; | |
236 | |
237 fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", | |
238 stream->error, mad_stream_errorstr(stream), | |
239 stream->this_frame - data->start); | |
240 | |
241 return MAD_FLOW_CONTINUE; | |
242 } | |
243 | |
244 void | |
245 MP3FileReader::getSupportedExtensions(std::set<QString> &extensions) | |
246 { | |
247 extensions.insert("mp3"); | |
248 } | |
249 | |
250 #endif |