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 && TellFile64(fFid) > 0) {
00057
00058
00059
00060 int bytesPerSample = (fNumChannels*fBitsPerSample)/8;
00061 if (bytesPerSample == 0) bytesPerSample = 1;
00062 SeekFile64(fFid, -bytesPerSample, SEEK_CUR);
00063 }
00064 }
00065
00066 void WAVAudioFileSource::seekToPCMByte(unsigned byteNumber, unsigned numBytesToStream) {
00067 byteNumber += fWAVHeaderSize;
00068 if (byteNumber > fFileSize) byteNumber = fFileSize;
00069
00070 SeekFile64(fFid, byteNumber, SEEK_SET);
00071
00072 fNumBytesToStream = numBytesToStream;
00073 fLimitNumBytesToStream = fNumBytesToStream > 0;
00074 }
00075
00076 unsigned char WAVAudioFileSource::getAudioFormat() {
00077 return fAudioFormat;
00078 }
00079
00080
00081 #define nextc fgetc(fid)
00082
00083 static Boolean get4Bytes(FILE* fid, unsigned& result) {
00084 int c0, c1, c2, c3;
00085 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF ||
00086 (c2 = nextc) == EOF || (c3 = nextc) == EOF) return False;
00087 result = (c3<<24)|(c2<<16)|(c1<<8)|c0;
00088 return True;
00089 }
00090
00091 static Boolean get2Bytes(FILE* fid, unsigned short& result) {
00092 int c0, c1;
00093 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF) return False;
00094 result = (c1<<8)|c0;
00095 return True;
00096 }
00097
00098 static Boolean skipBytes(FILE* fid, int num) {
00099 while (num-- > 0) {
00100 if (nextc == EOF) return False;
00101 }
00102 return True;
00103 }
00104
00105 WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid)
00106 : AudioInputDevice(env, 0, 0, 0, 0),
00107 fFid(fid), fLastPlayTime(0), fWAVHeaderSize(0), fFileSize(0), fScaleFactor(1),
00108 fLimitNumBytesToStream(False), fNumBytesToStream(0), fAudioFormat(WA_UNKNOWN) {
00109
00110
00111
00112
00113
00114
00115 Boolean success = False;
00116 do {
00117
00118 if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break;
00119 if (!skipBytes(fid, 4)) break;
00120 if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break;
00121
00122
00123 if (nextc != 'f' || nextc != 'm' || nextc != 't' || nextc != ' ') break;
00124 unsigned formatLength;
00125 if (!get4Bytes(fid, formatLength)) break;
00126 unsigned short audioFormat;
00127 if (!get2Bytes(fid, audioFormat)) break;
00128
00129 fAudioFormat = (unsigned char)audioFormat;
00130 if (fAudioFormat != WA_PCM && fAudioFormat != WA_PCMA && fAudioFormat != WA_PCMU && fAudioFormat != WA_IMA_ADPCM) {
00131
00132 env.setResultMsg("Audio format is not one that we handle (PCM/PCMU/PCMA or IMA ADPCM)");
00133 break;
00134 }
00135 unsigned short numChannels;
00136 if (!get2Bytes(fid, numChannels)) break;
00137 fNumChannels = (unsigned char)numChannels;
00138 if (fNumChannels < 1 || fNumChannels > 2) {
00139 char errMsg[100];
00140 sprintf(errMsg, "Bad # channels: %d", fNumChannels);
00141 env.setResultMsg(errMsg);
00142 break;
00143 }
00144 if (!get4Bytes(fid, fSamplingFrequency)) break;
00145 if (fSamplingFrequency == 0) {
00146 env.setResultMsg("Bad sampling frequency: 0");
00147 break;
00148 }
00149 if (!skipBytes(fid, 6)) break;
00150 unsigned short bitsPerSample;
00151 if (!get2Bytes(fid, bitsPerSample)) break;
00152 fBitsPerSample = (unsigned char)bitsPerSample;
00153 if (fBitsPerSample == 0) {
00154 env.setResultMsg("Bad bits-per-sample: 0");
00155 break;
00156 }
00157 if (!skipBytes(fid, formatLength - 16)) break;
00158
00159
00160 int c = nextc;
00161 if (c == 'f') {
00162 if (nextc != 'a' || nextc != 'c' || nextc != 't') break;
00163 unsigned factLength;
00164 if (!get4Bytes(fid, factLength)) break;
00165 if (!skipBytes(fid, factLength)) break;
00166 c = nextc;
00167 }
00168
00169
00170 if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break;
00171 if (!skipBytes(fid, 4)) break;
00172
00173
00174 fWAVHeaderSize = (unsigned)TellFile64(fid);
00175 success = True;
00176 } while (0);
00177
00178 if (!success) {
00179 env.setResultMsg("Bad WAV file format");
00180
00181 fBitsPerSample = 0;
00182 return;
00183 }
00184
00185 fPlayTimePerSample = 1e6/(double)fSamplingFrequency;
00186
00187
00188
00189
00190
00191 unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample);
00192 unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency);
00193 unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame ? 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) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
00205 handleClosure(this);
00206 return;
00207 }
00208
00209
00210 if (fLimitNumBytesToStream && fNumBytesToStream < fMaxSize) {
00211 fMaxSize = fNumBytesToStream;
00212 }
00213 if (fPreferredFrameSize < fMaxSize) {
00214 fMaxSize = fPreferredFrameSize;
00215 }
00216 unsigned bytesPerSample = (fNumChannels*fBitsPerSample)/8;
00217 if (bytesPerSample == 0) bytesPerSample = 1;
00218 unsigned bytesToRead = fMaxSize - fMaxSize%bytesPerSample;
00219 if (fScaleFactor == 1) {
00220
00221 fFrameSize = fread(fTo, 1, bytesToRead, fFid);
00222 fNumBytesToStream -= fFrameSize;
00223 } else {
00224
00225 fFrameSize = 0;
00226 while (bytesToRead > 0) {
00227 size_t bytesRead = fread(fTo, 1, bytesPerSample, fFid);
00228 if (bytesRead <= 0) break;
00229 fTo += bytesRead;
00230 fFrameSize += bytesRead;
00231 fNumBytesToStream -= bytesRead;
00232 bytesToRead -= bytesRead;
00233
00234
00235 SeekFile64(fFid, (fScaleFactor-1)*bytesPerSample, SEEK_CUR);
00236 }
00237 }
00238
00239
00240 if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
00241
00242 gettimeofday(&fPresentationTime, NULL);
00243 } else {
00244
00245 unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
00246 fPresentationTime.tv_sec += uSeconds/1000000;
00247 fPresentationTime.tv_usec = uSeconds%1000000;
00248 }
00249
00250
00251 fDurationInMicroseconds = fLastPlayTime
00252 = (unsigned)((fPlayTimePerSample*fFrameSize)/bytesPerSample);
00253
00254
00255 #if defined(__WIN32__) || defined(_WIN32)
00256
00257
00258
00259
00260
00261
00262
00263 afterGetting(this);
00264 #else
00265 nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00266 (TaskFunc*)FramedSource::afterGetting, this);
00267 #endif
00268 }
00269
00270 Boolean WAVAudioFileSource::setInputPort(int ) {
00271 return True;
00272 }
00273
00274 double WAVAudioFileSource::getAverageLevel() const {
00275 return 0.0;
00276 }