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 22BSound::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 40BSound::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 74BSound::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 89BSound::~BSound() 90{ 91 delete fTrackReader; 92 delete fFile; 93 94 if (fFreeWhenDone) 95 free(fData); 96} 97 98 99status_t 100BSound::InitCheck() 101{ 102 return fStatus; 103} 104 105 106BSound* 107BSound::AcquireRef() 108{ 109 atomic_add(&fRefCount, 1); 110 return this; 111} 112 113 114bool 115BSound::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 127int32 128BSound::RefCount() const 129{ 130 return fRefCount; 131} 132 133 134bigtime_t 135BSound::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 150const media_raw_audio_format& 151BSound::Format() const 152{ 153 return fFormat; 154} 155 156 157const void* 158BSound::Data() const 159{ 160 return fData; 161} 162 163 164off_t 165BSound::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 177bool 178BSound::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 242status_t 243BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format) 244{ 245 UNIMPLEMENTED(); 246 return B_ERROR; 247} 248 249 250status_t 251BSound::UnbindFrom(BSoundPlayer* player) 252{ 253 UNIMPLEMENTED(); 254 return B_ERROR; 255} 256 257 258status_t 259BSound::Perform(int32 code, ...) 260{ 261 UNIMPLEMENTED(); 262 return B_ERROR; 263} 264 265 266status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; } 267status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; } 268status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; } 269status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; } 270status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; } 271status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; } 272