6#include "GuiSoundOggPlayer.h"
12#include <coreinit/cache.h>
17GuiSoundOggPlayer::GuiSoundOggPlayer() : vfOpen(false), threadRunning(false), streamPaused(false), sampleRate(0), channels(0) {
18 pcmBuffer[0] = (uint8_t*)memalign(32, BUFFER_SIZE);
19 pcmBuffer[1] = (uint8_t*)memalign(32, BUFFER_SIZE);
20 bufferReady[0] =
false;
21 bufferReady[1] =
false;
26GuiSoundOggPlayer::~GuiSoundOggPlayer() {
32size_t GuiSoundOggPlayer::readOgg(
void* ptr,
size_t size,
size_t nmemb,
void* datasource) {
33 MemFile* mem =
static_cast<MemFile*
>(datasource);
34 size_t bytesToRead = size * nmemb;
35 if (mem->pos >= mem->size)
return 0;
36 if (
static_cast<size_t>(mem->pos) + bytesToRead >
static_cast<size_t>(mem->size)) {
37 bytesToRead =
static_cast<size_t>(mem->size - mem->pos);
39 memcpy(ptr, mem->data + mem->pos, bytesToRead);
40 mem->pos += bytesToRead;
41 return bytesToRead / size;
44int GuiSoundOggPlayer::seekOgg(
void* datasource, ogg_int64_t offset,
int whence) {
45 MemFile* mem =
static_cast<MemFile*
>(datasource);
47 case SEEK_SET: mem->pos = offset;
break;
48 case SEEK_CUR: mem->pos += offset;
break;
49 case SEEK_END: mem->pos = mem->size + offset;
break;
51 if (mem->pos < 0) mem->pos = 0;
52 if (mem->pos > mem->size) mem->pos = mem->size;
56int GuiSoundOggPlayer::closeOgg(
void*) {
return 0; }
57long GuiSoundOggPlayer::tellOgg(
void* datasource) {
return static_cast<MemFile*
>(datasource)->pos; }
63 memFile.size = length;
66 ov_callbacks cb = { readOgg, seekOgg, closeOgg, tellOgg };
67 if (ov_open_callbacks(&memFile, &vf,
nullptr, 0, cb) < 0) {
72 vorbis_info* vi = ov_info(&vf, -1);
73 sampleRate = vi->rate;
74 channels = vi->channels;
77 if (time_pos > 0) ov_time_seek(&vf, time_pos);
79 bufferReady[0] =
false;
80 bufferReady[1] =
false;
87 if (!decodeThread.start(threadEntry,
this, 16384, ThreadPriority::High)) {
89 threadRunning =
false;
102 threadRunning =
false;
104 if (decodeThread.isRunning())
114 streamPaused =
pause;
118 if (bufferReady[playIndex]) {
119 *outSize = pcmBufferSize[playIndex];
120 return pcmBuffer[playIndex];
126 bufferReady[playIndex] =
false;
130void* GuiSoundOggPlayer::threadEntry(
void* arg) {
135void GuiSoundOggPlayer::threadLoop() {
136 while (threadRunning && !decodeThread.stopRequested()) {
142 if (!bufferReady[decodeIndex]) {
145 while (bytesRead < BUFFER_SIZE && threadRunning && !streamPaused && !decodeThread.stopRequested()) {
146 int currentSection = 0;
147 long ret = ov_read(&vf, (
char*)pcmBuffer[decodeIndex] + bytesRead, BUFFER_SIZE - bytesRead, ¤tSection);
153 if (bytesRead == 0) threadRunning =
false;
156 }
else if (ret < 0) {
157 if (ret != OV_HOLE && !streamLoop) {
158 if (bytesRead == 0) threadRunning =
false;
167 DCFlushRange(pcmBuffer[decodeIndex], bytesRead);
168 pcmBufferSize[decodeIndex] = bytesRead;
169 bufferReady[decodeIndex] =
true;
171 }
else if (!threadRunning) {
Platform-agnostic Tremor (integer OGG) decoder.
void consumeBuffer()
Releases the buffer last returned by getReadyBuffer(), letting the decode thread reuse that ring slot...
void pause(bool pause)
Pauses or resumes the decode thread without stopping it.
const uint8_t * getReadyBuffer(int32_t *outSize)
bool play(const uint8_t *data, int32_t length, int time_pos, bool loop)
Starts decoding data on a new thread.
void stop()
Stops playback and joins the decode thread.