00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "WAVAudioFileSource.hh"
00022 #include "InputFile.hh"
00023 #include "GroupsockHelper.hh"
00024
00026
00027 WAVAudioFileSource*
00028 WAVAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) {
00029 do {
00030 FILE* fid = OpenInputFile(env, fileName);
00031 if (fid == NULL) break;
00032
00033 WAVAudioFileSource* newSource = new WAVAudioFileSource(env, fid);
00034 if (newSource != NULL && newSource->bitsPerSample() == 0) {
00035
00036 Medium::close(newSource);
00037 break;
00038 }
00039
00040 newSource->fFileSize = (unsigned)GetFileSize(fileName, fid);
00041
00042 return newSource;
00043 } while (0);
00044
00045 return NULL;
00046 }
00047
00048 unsigned WAVAudioFileSource::numPCMBytes() const {
00049 if (fFileSize < fWAVHeaderSize) return 0;
00050 return fFileSize - fWAVHeaderSize;
00051 }
00052
00053 void WAVAudioFileSource::setScaleFactor(int scale) {
00054 fScaleFactor = scale;
00055
00056 if (fScaleFactor < 0 && ftell(fFid) > 0) {
00057
00058
00059
00060 int const bytesPerSample = (fNumChannels*fBitsPerSample)/8;
00061 fseek(fFid, -bytesPerSample, SEEK_CUR);
00062 }
00063 }
00064
00065 void WAVAudioFileSource::seekToPCMByte(unsigned byteNumber) {
00066 byteNumber += fWAVHeaderSize;
00067 if (byteNumber > fFileSize) byteNumber = fFileSize;
00068
00069 fseek(fFid, byteNumber, SEEK_SET);
00070 }
00071
00072 unsigned char WAVAudioFileSource::getAudioFormat() {
00073 return fAudioFormat;
00074 }
00075
00076
00077 #define nextc fgetc(fid)
00078
00079 static Boolean get4Bytes(FILE* fid, unsigned& result) {
00080 int c0, c1, c2, c3;
00081 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF ||
00082 (c2 = nextc) == EOF || (c3 = nextc) == EOF) return False;
00083 result = (c3<<24)|(c2<<16)|(c1<<8)|c0;
00084 return True;
00085 }
00086
00087 static Boolean get2Bytes(FILE* fid, unsigned short& result) {
00088 int c0, c1;
00089 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF) return False;
00090 result = (c1<<8)|c0;
00091 return True;
00092 }
00093
00094 static Boolean skipBytes(FILE* fid, int num) {
00095 while (num-- > 0) {
00096 if (nextc == EOF) return False;
00097 }
00098 return True;
00099 }
00100
00101 WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid)
00102 : AudioInputDevice(env, 0, 0, 0, 0),
00103 fFid(fid), fLastPlayTime(0), fWAVHeaderSize(0), fFileSize(0), fScaleFactor(1),
00104 fAudioFormat(WA_UNKNOWN) {
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 Boolean success = False;
00115 do {
00116
00117 if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break;
00118 if (!skipBytes(fid, 4)) break;
00119 if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break;
00120
00121
00122 if (nextc != 'f' || nextc != 'm' || nextc != 't' || nextc != ' ') break;
00123 unsigned formatLength;
00124 if (!get4Bytes(fid, formatLength)) break;
00125 unsigned short audioFormat;
00126 if (!get2Bytes(fid, audioFormat)) break;
00127
00128 fAudioFormat = (unsigned char)audioFormat;
00129 if (fAudioFormat != WA_PCM && fAudioFormat != WA_PCMA && fAudioFormat != WA_PCMU) {
00130
00131 env.setResultMsg("Audio format is not PCM/PCMU/PCMA");
00132 break;
00133 }
00134 unsigned short numChannels;
00135 if (!get2Bytes(fid, numChannels)) break;
00136 fNumChannels = (unsigned char)numChannels;
00137 if (fNumChannels < 1 || fNumChannels > 2) {
00138 char errMsg[100];
00139 sprintf(errMsg, "Bad # channels: %d", fNumChannels);
00140 env.setResultMsg(errMsg);
00141 break;
00142 }
00143 if (!get4Bytes(fid, fSamplingFrequency)) break;
00144 if (fSamplingFrequency == 0) {
00145 env.setResultMsg("Bad sampling frequency: 0");
00146 break;
00147 }
00148 if (!skipBytes(fid, 6)) break;
00149 unsigned short bitsPerSample;
00150 if (!get2Bytes(fid, bitsPerSample)) break;
00151 fBitsPerSample = (unsigned char)bitsPerSample;
00152 if (fBitsPerSample == 0) {
00153 env.setResultMsg("Bad bits-per-sample: 0");
00154 break;
00155 }
00156 if (!skipBytes(fid, formatLength - 16)) break;
00157
00158
00159 int c = nextc;
00160 if (c == 'f') {
00161 if (nextc != 'a' || nextc != 'c' || nextc != 't') break;
00162 unsigned factLength;
00163 if (!get4Bytes(fid, factLength)) break;
00164 if (!skipBytes(fid, factLength)) break;
00165 c = nextc;
00166 }
00167
00168
00169 if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break;
00170 if (!skipBytes(fid, 4)) break;
00171
00172
00173 fWAVHeaderSize = ftell(fid);
00174 success = True;
00175 } while (0);
00176
00177 if (!success) {
00178 env.setResultMsg("Bad WAV file format");
00179
00180 fBitsPerSample = 0;
00181 return;
00182 }
00183
00184 fPlayTimePerSample = 1e6/(double)fSamplingFrequency;
00185
00186
00187
00188
00189
00190 unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample);
00191 unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency);
00192 unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame
00193 ? desiredSamplesPerFrame : maxSamplesPerFrame;
00194 fPreferredFrameSize = (samplesPerFrame*fNumChannels*fBitsPerSample)/8;
00195 }
00196
00197 WAVAudioFileSource::~WAVAudioFileSource() {
00198 CloseInputFile(fFid);
00199 }
00200
00201
00202
00203 void WAVAudioFileSource::doGetNextFrame() {
00204 if (feof(fFid) || ferror(fFid)) {
00205 handleClosure(this);
00206 return;
00207 }
00208
00209
00210
00211 if (fPreferredFrameSize < fMaxSize) {
00212 fMaxSize = fPreferredFrameSize;
00213 }
00214 unsigned const bytesPerSample = (fNumChannels*fBitsPerSample)/8;
00215 unsigned bytesToRead = fMaxSize - fMaxSize%bytesPerSample;
00216 if (fScaleFactor == 1) {
00217
00218 fFrameSize = fread(fTo, 1, bytesToRead, fFid);
00219 } else {
00220
00221 fFrameSize = 0;
00222 while (bytesToRead > 0) {
00223 size_t bytesRead = fread(fTo, 1, bytesPerSample, fFid);
00224 if (bytesRead <= 0) break;
00225 fTo += bytesRead;
00226 fFrameSize += bytesRead;
00227 bytesToRead -= bytesRead;
00228
00229
00230 fseek(fFid, (fScaleFactor-1)*bytesPerSample, SEEK_CUR);
00231 }
00232 }
00233
00234
00235 if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
00236
00237 gettimeofday(&fPresentationTime, NULL);
00238 } else {
00239
00240 unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
00241 fPresentationTime.tv_sec += uSeconds/1000000;
00242 fPresentationTime.tv_usec = uSeconds%1000000;
00243 }
00244
00245
00246 fDurationInMicroseconds = fLastPlayTime
00247 = (unsigned)((fPlayTimePerSample*fFrameSize)/bytesPerSample);
00248
00249
00250 #if defined(__WIN32__) || defined(_WIN32)
00251
00252
00253
00254
00255
00256
00257
00258 afterGetting(this);
00259 #else
00260 nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00261 (TaskFunc*)FramedSource::afterGetting, this);
00262 #endif
00263 }
00264
00265 Boolean WAVAudioFileSource::setInputPort(int ) {
00266 return True;
00267 }
00268
00269 double WAVAudioFileSource::getAverageLevel() const {
00270 return 0.0;
00271 }