272 lines
4.8 KiB
C++
272 lines
4.8 KiB
C++
/*
|
|
* Copyright 2009-2019, Haiku Inc. All Rights Reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Jacob Secunda
|
|
* Marcus Overhagen
|
|
* Michael Lotz <mmlr@mlotz.ch>
|
|
*/
|
|
|
|
#include <Sound.h>
|
|
|
|
#include <new>
|
|
#include <string.h>
|
|
|
|
#include <File.h>
|
|
#include <MediaDebug.h>
|
|
|
|
#include "TrackReader.h"
|
|
|
|
|
|
BSound::BSound(void* data, size_t size, const media_raw_audio_format& format,
|
|
bool freeWhenDone)
|
|
: fData(data),
|
|
fDataSize(size),
|
|
fFile(NULL),
|
|
fRefCount(1),
|
|
fStatus(B_NO_INIT),
|
|
fFormat(format),
|
|
fFreeWhenDone(freeWhenDone),
|
|
fTrackReader(NULL)
|
|
{
|
|
if (fData == NULL)
|
|
return;
|
|
|
|
fStatus = B_OK;
|
|
}
|
|
|
|
|
|
BSound::BSound(const entry_ref* soundFile, bool loadIntoMemory)
|
|
: fData(NULL),
|
|
fDataSize(0),
|
|
fFile(new(std::nothrow) BFile(soundFile, B_READ_ONLY)),
|
|
fRefCount(1),
|
|
fStatus(B_NO_INIT),
|
|
fFreeWhenDone(false),
|
|
fTrackReader(NULL)
|
|
{
|
|
if (fFile == NULL) {
|
|
fStatus = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
fStatus = fFile->InitCheck();
|
|
if (fStatus != B_OK)
|
|
return;
|
|
|
|
memset(&fFormat, 0, sizeof(fFormat));
|
|
fTrackReader = new(std::nothrow) BPrivate::BTrackReader(fFile, fFormat);
|
|
if (fTrackReader == NULL) {
|
|
fStatus = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
fStatus = fTrackReader->InitCheck();
|
|
if (fStatus != B_OK)
|
|
return;
|
|
|
|
fFormat = fTrackReader->Format();
|
|
fStatus = B_OK;
|
|
}
|
|
|
|
|
|
BSound::BSound(const media_raw_audio_format& format)
|
|
: fData(NULL),
|
|
fDataSize(0),
|
|
fFile(NULL),
|
|
fRefCount(1),
|
|
fStatus(B_ERROR),
|
|
fFormat(format),
|
|
fFreeWhenDone(false),
|
|
fTrackReader(NULL)
|
|
{
|
|
// unimplemented protected constructor
|
|
UNIMPLEMENTED();
|
|
}
|
|
|
|
|
|
BSound::~BSound()
|
|
{
|
|
delete fTrackReader;
|
|
delete fFile;
|
|
|
|
if (fFreeWhenDone)
|
|
free(fData);
|
|
}
|
|
|
|
|
|
status_t
|
|
BSound::InitCheck()
|
|
{
|
|
return fStatus;
|
|
}
|
|
|
|
|
|
BSound*
|
|
BSound::AcquireRef()
|
|
{
|
|
atomic_add(&fRefCount, 1);
|
|
return this;
|
|
}
|
|
|
|
|
|
bool
|
|
BSound::ReleaseRef()
|
|
{
|
|
if (atomic_add(&fRefCount, -1) == 1) {
|
|
delete this;
|
|
return false;
|
|
}
|
|
|
|
// TODO: verify those returns
|
|
return true;
|
|
}
|
|
|
|
|
|
int32
|
|
BSound::RefCount() const
|
|
{
|
|
return fRefCount;
|
|
}
|
|
|
|
|
|
bigtime_t
|
|
BSound::Duration() const
|
|
{
|
|
float frameRate = fFormat.frame_rate;
|
|
|
|
if (frameRate == 0.0)
|
|
return 0;
|
|
|
|
uint32 bytesPerSample = fFormat.format &
|
|
media_raw_audio_format::B_AUDIO_SIZE_MASK;
|
|
int64 frameCount = Size() / (fFormat.channel_count * bytesPerSample);
|
|
|
|
return (bigtime_t)ceil((1000000LL * frameCount) / frameRate);
|
|
}
|
|
|
|
|
|
const media_raw_audio_format&
|
|
BSound::Format() const
|
|
{
|
|
return fFormat;
|
|
}
|
|
|
|
|
|
const void*
|
|
BSound::Data() const
|
|
{
|
|
return fData;
|
|
}
|
|
|
|
|
|
off_t
|
|
BSound::Size() const
|
|
{
|
|
if (fFile != NULL) {
|
|
off_t result = 0;
|
|
fFile->GetSize(&result);
|
|
return result;
|
|
}
|
|
|
|
return fDataSize;
|
|
}
|
|
|
|
|
|
bool
|
|
BSound::GetDataAt(off_t offset, void* intoBuffer, size_t bufferSize,
|
|
size_t* outUsed)
|
|
{
|
|
if (intoBuffer == NULL)
|
|
return false;
|
|
|
|
if (fData != NULL) {
|
|
size_t copySize = MIN(bufferSize, fDataSize - offset);
|
|
memcpy(intoBuffer, (uint8*)fData + offset, copySize);
|
|
if (outUsed != NULL)
|
|
*outUsed = copySize;
|
|
return true;
|
|
}
|
|
|
|
if (fTrackReader != NULL) {
|
|
int32 frameSize = fTrackReader->FrameSize();
|
|
int64 frameCount = fTrackReader->CountFrames();
|
|
int64 startFrame = offset / frameSize;
|
|
if (startFrame > frameCount)
|
|
return false;
|
|
|
|
if (fTrackReader->SeekToFrame(&startFrame) != B_OK)
|
|
return false;
|
|
|
|
off_t bufferOffset = offset - startFrame * frameSize;
|
|
int64 directStartFrame = (offset + frameSize - 1) / frameSize;
|
|
int64 directFrameCount = (offset + bufferSize - directStartFrame
|
|
* frameSize) / frameSize;
|
|
|
|
if (bufferOffset != 0) {
|
|
int64 indirectFrameCount = directStartFrame - startFrame;
|
|
size_t indirectSize = indirectFrameCount * frameSize;
|
|
void* buffer = malloc(indirectSize);
|
|
if (buffer == NULL)
|
|
return false;
|
|
|
|
if (fTrackReader->ReadFrames(buffer, indirectFrameCount) != B_OK) {
|
|
free(buffer);
|
|
return false;
|
|
}
|
|
|
|
memcpy(intoBuffer, (uint8*)buffer + bufferOffset,
|
|
indirectSize - bufferOffset);
|
|
if (outUsed != NULL)
|
|
*outUsed = indirectSize - bufferOffset;
|
|
|
|
free(buffer);
|
|
} else if (outUsed != NULL)
|
|
*outUsed = 0;
|
|
|
|
if (fTrackReader->ReadFrames((uint8*)intoBuffer + bufferOffset,
|
|
directFrameCount) != B_OK)
|
|
return false;
|
|
|
|
if (outUsed != NULL)
|
|
*outUsed += directFrameCount * frameSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
status_t
|
|
BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BSound::UnbindFrom(BSoundPlayer* player)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BSound::Perform(int32 code, ...)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; }
|
|
status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; }
|
|
status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; }
|
|
status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; }
|
|
status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; }
|
|
status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; }
|