haiku/src/kits/media/Sound.cpp

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; }