1 /* 2 * Copyright 2009-2019, Haiku Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jacob Secunda 7 * Marcus Overhagen 8 * Michael Lotz <mmlr@mlotz.ch> 9 */ 10 11 #include <Sound.h> 12 13 #include <new> 14 #include <string.h> 15 16 #include <File.h> 17 #include <MediaDebug.h> 18 19 #include "TrackReader.h" 20 21 22 BSound::BSound(void* data, size_t size, const media_raw_audio_format& format, 23 bool freeWhenDone) 24 : fData(data), 25 fDataSize(size), 26 fFile(NULL), 27 fRefCount(1), 28 fStatus(B_NO_INIT), 29 fFormat(format), 30 fFreeWhenDone(freeWhenDone), 31 fTrackReader(NULL) 32 { 33 if (fData == NULL) 34 return; 35 36 fStatus = B_OK; 37 } 38 39 40 BSound::BSound(const entry_ref* soundFile, bool loadIntoMemory) 41 : fData(NULL), 42 fDataSize(0), 43 fFile(new(std::nothrow) BFile(soundFile, B_READ_ONLY)), 44 fRefCount(1), 45 fStatus(B_NO_INIT), 46 fFreeWhenDone(false), 47 fTrackReader(NULL) 48 { 49 if (fFile == NULL) { 50 fStatus = B_NO_MEMORY; 51 return; 52 } 53 54 fStatus = fFile->InitCheck(); 55 if (fStatus != B_OK) 56 return; 57 58 memset(&fFormat, 0, sizeof(fFormat)); 59 fTrackReader = new(std::nothrow) BPrivate::BTrackReader(fFile, fFormat); 60 if (fTrackReader == NULL) { 61 fStatus = B_NO_MEMORY; 62 return; 63 } 64 65 fStatus = fTrackReader->InitCheck(); 66 if (fStatus != B_OK) 67 return; 68 69 fFormat = fTrackReader->Format(); 70 fStatus = B_OK; 71 } 72 73 74 BSound::BSound(const media_raw_audio_format& format) 75 : fData(NULL), 76 fDataSize(0), 77 fFile(NULL), 78 fRefCount(1), 79 fStatus(B_ERROR), 80 fFormat(format), 81 fFreeWhenDone(false), 82 fTrackReader(NULL) 83 { 84 // unimplemented protected constructor 85 UNIMPLEMENTED(); 86 } 87 88 89 BSound::~BSound() 90 { 91 delete fTrackReader; 92 delete fFile; 93 94 if (fFreeWhenDone) 95 free(fData); 96 } 97 98 99 status_t 100 BSound::InitCheck() 101 { 102 return fStatus; 103 } 104 105 106 BSound* 107 BSound::AcquireRef() 108 { 109 atomic_add(&fRefCount, 1); 110 return this; 111 } 112 113 114 bool 115 BSound::ReleaseRef() 116 { 117 if (atomic_add(&fRefCount, -1) == 1) { 118 delete this; 119 return false; 120 } 121 122 // TODO: verify those returns 123 return true; 124 } 125 126 127 int32 128 BSound::RefCount() const 129 { 130 return fRefCount; 131 } 132 133 134 bigtime_t 135 BSound::Duration() const 136 { 137 float frameRate = fFormat.frame_rate; 138 139 if (frameRate == 0.0) 140 return 0; 141 142 uint32 bytesPerSample = fFormat.format & 143 media_raw_audio_format::B_AUDIO_SIZE_MASK; 144 int64 frameCount = Size() / (fFormat.channel_count * bytesPerSample); 145 146 return (bigtime_t)ceil((1000000LL * frameCount) / frameRate); 147 } 148 149 150 const media_raw_audio_format& 151 BSound::Format() const 152 { 153 return fFormat; 154 } 155 156 157 const void* 158 BSound::Data() const 159 { 160 return fData; 161 } 162 163 164 off_t 165 BSound::Size() const 166 { 167 if (fFile != NULL) { 168 off_t result = 0; 169 fFile->GetSize(&result); 170 return result; 171 } 172 173 return fDataSize; 174 } 175 176 177 bool 178 BSound::GetDataAt(off_t offset, void* intoBuffer, size_t bufferSize, 179 size_t* outUsed) 180 { 181 if (intoBuffer == NULL) 182 return false; 183 184 if (fData != NULL) { 185 size_t copySize = MIN(bufferSize, fDataSize - offset); 186 memcpy(intoBuffer, (uint8*)fData + offset, copySize); 187 if (outUsed != NULL) 188 *outUsed = copySize; 189 return true; 190 } 191 192 if (fTrackReader != NULL) { 193 int32 frameSize = fTrackReader->FrameSize(); 194 int64 frameCount = fTrackReader->CountFrames(); 195 int64 startFrame = offset / frameSize; 196 if (startFrame > frameCount) 197 return false; 198 199 if (fTrackReader->SeekToFrame(&startFrame) != B_OK) 200 return false; 201 202 off_t bufferOffset = offset - startFrame * frameSize; 203 int64 directStartFrame = (offset + frameSize - 1) / frameSize; 204 int64 directFrameCount = (offset + bufferSize - directStartFrame 205 * frameSize) / frameSize; 206 207 if (bufferOffset != 0) { 208 int64 indirectFrameCount = directStartFrame - startFrame; 209 size_t indirectSize = indirectFrameCount * frameSize; 210 void* buffer = malloc(indirectSize); 211 if (buffer == NULL) 212 return false; 213 214 if (fTrackReader->ReadFrames(buffer, indirectFrameCount) != B_OK) { 215 free(buffer); 216 return false; 217 } 218 219 memcpy(intoBuffer, (uint8*)buffer + bufferOffset, 220 indirectSize - bufferOffset); 221 if (outUsed != NULL) 222 *outUsed = indirectSize - bufferOffset; 223 224 free(buffer); 225 } else if (outUsed != NULL) 226 *outUsed = 0; 227 228 if (fTrackReader->ReadFrames((uint8*)intoBuffer + bufferOffset, 229 directFrameCount) != B_OK) 230 return false; 231 232 if (outUsed != NULL) 233 *outUsed += directFrameCount * frameSize; 234 235 return true; 236 } 237 238 return false; 239 } 240 241 242 status_t 243 BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format) 244 { 245 UNIMPLEMENTED(); 246 return B_ERROR; 247 } 248 249 250 status_t 251 BSound::UnbindFrom(BSoundPlayer* player) 252 { 253 UNIMPLEMENTED(); 254 return B_ERROR; 255 } 256 257 258 status_t 259 BSound::Perform(int32 code, ...) 260 { 261 UNIMPLEMENTED(); 262 return B_ERROR; 263 } 264 265 266 status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; } 267 status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; } 268 status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; } 269 status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; } 270 status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; } 271 status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; } 272