mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-27 17:31:31 +00:00
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "oboe/FifoControllerBase.h"
|
||||
#include "fifo/FifoController.h"
|
||||
#include "fifo/FifoControllerIndirect.h"
|
||||
#include "oboe/FifoBuffer.h"
|
||||
|
||||
namespace oboe {
|
||||
|
||||
FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames)
|
||||
: mBytesPerFrame(bytesPerFrame)
|
||||
, mStorage(nullptr)
|
||||
, mFramesReadCount(0)
|
||||
, mFramesUnderrunCount(0)
|
||||
{
|
||||
mFifo = std::make_unique<FifoController>(capacityInFrames);
|
||||
// allocate buffer
|
||||
int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
|
||||
mStorage = new uint8_t[bytesPerBuffer];
|
||||
mStorageOwned = true;
|
||||
}
|
||||
|
||||
FifoBuffer::FifoBuffer( uint32_t bytesPerFrame,
|
||||
uint32_t capacityInFrames,
|
||||
std::atomic<uint64_t> *readCounterAddress,
|
||||
std::atomic<uint64_t> *writeCounterAddress,
|
||||
uint8_t *dataStorageAddress
|
||||
)
|
||||
: mBytesPerFrame(bytesPerFrame)
|
||||
, mStorage(dataStorageAddress)
|
||||
, mFramesReadCount(0)
|
||||
, mFramesUnderrunCount(0)
|
||||
{
|
||||
mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
|
||||
readCounterAddress,
|
||||
writeCounterAddress);
|
||||
mStorage = dataStorageAddress;
|
||||
mStorageOwned = false;
|
||||
}
|
||||
|
||||
FifoBuffer::~FifoBuffer() {
|
||||
if (mStorageOwned) {
|
||||
delete[] mStorage;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t FifoBuffer::convertFramesToBytes(int32_t frames) {
|
||||
return frames * mBytesPerFrame;
|
||||
}
|
||||
|
||||
int32_t FifoBuffer::read(void *buffer, int32_t numFrames) {
|
||||
if (numFrames <= 0) {
|
||||
return 0;
|
||||
}
|
||||
// safe because numFrames is guaranteed positive
|
||||
uint32_t framesToRead = static_cast<uint32_t>(numFrames);
|
||||
uint32_t framesAvailable = mFifo->getFullFramesAvailable();
|
||||
framesToRead = std::min(framesToRead, framesAvailable);
|
||||
|
||||
uint32_t readIndex = mFifo->getReadIndex(); // ranges 0 to capacity
|
||||
uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
|
||||
uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
|
||||
if ((readIndex + framesToRead) > mFifo->getFrameCapacity()) {
|
||||
// read in two parts, first part here is at the end of the mStorage buffer
|
||||
int32_t frames1 = static_cast<int32_t>(mFifo->getFrameCapacity() - readIndex);
|
||||
int32_t numBytes = convertFramesToBytes(frames1);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
destination += numBytes;
|
||||
// read second part, which is at the beginning of mStorage
|
||||
source = &mStorage[0];
|
||||
int32_t frames2 = static_cast<uint32_t>(framesToRead - frames1);
|
||||
numBytes = convertFramesToBytes(frames2);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
} else {
|
||||
// just read in one shot
|
||||
int32_t numBytes = convertFramesToBytes(framesToRead);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
}
|
||||
mFifo->advanceReadIndex(framesToRead);
|
||||
|
||||
return framesToRead;
|
||||
}
|
||||
|
||||
int32_t FifoBuffer::write(const void *buffer, int32_t numFrames) {
|
||||
if (numFrames <= 0) {
|
||||
return 0;
|
||||
}
|
||||
// Guaranteed positive.
|
||||
uint32_t framesToWrite = static_cast<uint32_t>(numFrames);
|
||||
uint32_t framesAvailable = mFifo->getEmptyFramesAvailable();
|
||||
framesToWrite = std::min(framesToWrite, framesAvailable);
|
||||
|
||||
uint32_t writeIndex = mFifo->getWriteIndex();
|
||||
int byteIndex = convertFramesToBytes(writeIndex);
|
||||
const uint8_t *source = reinterpret_cast<const uint8_t *>(buffer);
|
||||
uint8_t *destination = &mStorage[byteIndex];
|
||||
if ((writeIndex + framesToWrite) > mFifo->getFrameCapacity()) {
|
||||
// write in two parts, first part here
|
||||
int32_t frames1 = static_cast<uint32_t>(mFifo->getFrameCapacity() - writeIndex);
|
||||
int32_t numBytes = convertFramesToBytes(frames1);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
// read second part
|
||||
source += convertFramesToBytes(frames1);
|
||||
destination = &mStorage[0];
|
||||
int frames2 = static_cast<uint32_t>(framesToWrite - frames1);
|
||||
numBytes = convertFramesToBytes(frames2);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
} else {
|
||||
// just write in one shot
|
||||
int32_t numBytes = convertFramesToBytes(framesToWrite);
|
||||
if (numBytes < 0) {
|
||||
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||||
}
|
||||
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||||
}
|
||||
mFifo->advanceWriteIndex(framesToWrite);
|
||||
|
||||
return framesToWrite;
|
||||
}
|
||||
|
||||
int32_t FifoBuffer::readNow(void *buffer, int32_t numFrames) {
|
||||
int32_t framesRead = read(buffer, numFrames);
|
||||
if (framesRead < 0) {
|
||||
return framesRead;
|
||||
}
|
||||
int32_t framesLeft = numFrames - framesRead;
|
||||
mFramesReadCount += framesRead;
|
||||
mFramesUnderrunCount += framesLeft;
|
||||
// Zero out any samples we could not set.
|
||||
if (framesLeft > 0) {
|
||||
uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
|
||||
destination += convertFramesToBytes(framesRead); // point to first byte not set
|
||||
int32_t bytesToZero = convertFramesToBytes(framesLeft);
|
||||
memset(destination, 0, static_cast<size_t>(bytesToZero));
|
||||
}
|
||||
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
|
||||
uint32_t FifoBuffer::getBufferCapacityInFrames() const {
|
||||
return mFifo->getFrameCapacity();
|
||||
}
|
||||
|
||||
} // namespace oboe
|
||||
Reference in New Issue
Block a user