Skip to content

Commit

Permalink
ogg seeking in the interface
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdruppe committed Nov 20, 2022
1 parent 7d475b1 commit 1f6ead0
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 5 deletions.
49 changes: 48 additions & 1 deletion simpleaudio.d
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,17 @@ interface SampleController {
+/
bool paused();

/++
Seeks to a point in the sample, if possible. If impossible, this function does nothing.
Params:
where = point to seek to, in seconds
History:
Added November 20, 2022 (dub v10.10)
+/
void seek(float where);

/++
Sets a delegate that will be called on the audio thread when the sample is finished
playing; immediately after [finished] becomes `true`.
Expand All @@ -247,6 +258,8 @@ private class DummySample : SampleController {
float position() { return float.init; }
bool finished() { return true; }
bool paused() { return true; }

void seek(float where) {}
}

private class SampleControlFlags : SampleController {
Expand All @@ -262,7 +275,10 @@ private class SampleControlFlags : SampleController {
bool finished() { return finished_; }
bool paused() { return paused_; }

void seek(float where) { synchronized(this) {requestedSeek = where;} }

float currentPosition = 0.0;
float requestedSeek = float.init;
}

/++
Expand Down Expand Up @@ -909,6 +925,15 @@ final class AudioPcmOutThreadImplementation : Thread {
if(cast(int) buffer.length != buffer.length)
throw new Exception("eeeek");

synchronized(scf)
if(scf.requestedSeek !is float.init) {
if(v.seek(cast(uint) (scf.requestedSeek * v.sampleRate))) {
scf.currentPosition = scf.requestedSeek;
}

scf.requestedSeek = float.init;
}

plain:
auto got = v.getSamplesShortInterleaved(2, buffer.ptr, cast(int) buffer.length);
if(got == 0) {
Expand Down Expand Up @@ -940,6 +965,15 @@ final class AudioPcmOutThreadImplementation : Thread {
tmp[0] = buffersIn[0].ptr;
tmp[1] = buffersIn[1].ptr;

synchronized(scf)
if(scf.requestedSeek !is float.init) {
if(v.seekFrame(cast(uint) (scf.requestedSeek * v.sampleRate))) {
scf.currentPosition = scf.requestedSeek;
}

scf.requestedSeek = float.init;
}

loop:
auto actuallyGot = v.getSamplesFloat(v.chans, tmp.ptr, cast(int) buffersIn[0].length);
if(actuallyGot == 0 && loop) {
Expand Down Expand Up @@ -970,6 +1004,9 @@ final class AudioPcmOutThreadImplementation : Thread {
Please note that the static type may change in the future. It will always be a subtype of [SampleController], but it may be more specialized as I add more features and this will not necessarily match its sister functions, [playOgg] and [playWav], though all three will share an ancestor in [SampleController]. Therefore, if you use `auto`, there's no guarantee the static type won't change in future versions and I will NOT consider that a breaking change since the base interface will remain compatible.
Bugs:
Mp3s cannot be seeked or looped in the current implementation.
History:
Automatic resampling support added Nov 7, 2020.
Expand Down Expand Up @@ -1030,6 +1067,15 @@ final class AudioPcmOutThreadImplementation : Thread {
if(cast(int) buffer.length != buffer.length)
throw new Exception("eeeek");

synchronized(scf)
if(scf.requestedSeek !is float.init) {
if(mp3.seek(cast(uint) (scf.requestedSeek * v.sampleRate))) {
scf.currentPosition = scf.requestedSeek;
}

scf.requestedSeek = float.init;
}

more:
if(next.length >= buffer.length) {
buffer[] = next[0 .. buffer.length];
Expand Down Expand Up @@ -1057,8 +1103,9 @@ final class AudioPcmOutThreadImplementation : Thread {
}
}

if(scf.stopped)
if(scf.stopped) {
scf.finished_ = true;
}
return !scf.stopped;
}
);
Expand Down
24 changes: 20 additions & 4 deletions vorbis.d
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ struct ProbedPage {
private int error (VorbisDecoder f, STBVorbisError e) {
f.error = e;
if (!f.eof && e != STBVorbisError.need_more_data) {
// import std.stdio; debug writeln(e);
f.error = e; // breakpoint for debugging
}
return 0;
Expand Down Expand Up @@ -1030,7 +1031,7 @@ private bool getn (VorbisDecoder f, void* data, int n) {
}

private void skip (VorbisDecoder f, int n) {
if (f.eof || n <= 0) return;
if (f.eof || n == 0) return;
f.rawSkip(n);
}

Expand Down Expand Up @@ -1125,6 +1126,7 @@ private int maybe_start_packet (VorbisDecoder f) {
if (f.next_seg == -1) {
auto x = get8(f);
if (f.eof) return false; // EOF at page boundary is not an error!
// import std.stdio; debug writefln("CAPTURE %x %x", x, f.stpos);
if (0x4f != x ) return error(f, STBVorbisError.missing_capture_pattern);
if (0x67 != get8(f)) return error(f, STBVorbisError.missing_capture_pattern);
if (0x67 != get8(f)) return error(f, STBVorbisError.missing_capture_pattern);
Expand Down Expand Up @@ -4097,7 +4099,15 @@ private:
}
return 0;
}
void rawSkip (int n) { static if (__VERSION__ > 2067) pragma(inline, true); if (isOpened && n > 0) { if ((stpos += n) > stend) stpos = stend; } }
void rawSkip (int n) { static if (__VERSION__ > 2067) pragma(inline, true);
if (isOpened) {
stpos += n;
if(stpos < stst)
stpos = stst;
else if(stpos > stend)
stpos = stend;
}
}
void rawSeek (int n) { static if (__VERSION__ > 2067) pragma(inline, true); if (isOpened) { stpos = stst+(n < 0 ? 0 : n); if (stpos > stend) stpos = stend; } }
void rawClose () { static if (__VERSION__ > 2067) pragma(inline, true); if (isOpened) { isOpened = false; stmread(null, 0, this); } }

Expand All @@ -4121,14 +4131,17 @@ private:

static int stflRead (void[] buf, uint ofs, VorbisDecoder vb) {
if (buf !is null) {
//{ import core.stdc.stdio; printf("stflRead: ofs=%u; len=%u\n", ofs, cast(uint)buf.length); }
if (vb.stlastofs != ofs) {
// { import core.stdc.stdio; printf("stflRead: ofs=%u; len=%u\n", ofs, cast(uint)buf.length); }
import core.stdc.stdio : fseek, SEEK_SET;
vb.stlastofs = ofs;
fseek(vb.stfl, ofs, SEEK_SET);
}
import core.stdc.stdio : fread;
return cast(int)fread(buf.ptr, 1, buf.length, vb.stfl);
auto rd = cast(int)fread(buf.ptr, 1, buf.length, vb.stfl);
if(rd > 0)
vb.stlastofs += rd;
return rd;
} else {
if (vb.stclose) {
import core.stdc.stdio : fclose;
Expand Down Expand Up @@ -4492,6 +4505,8 @@ public:
assert(this.current_loc_valid);
assert(this.current_loc <= sample_number);

import std.stdio;

// linear search for the relevant packet
max_frame_samples = (this.blocksize_1*3-this.blocksize_0)>>2;
while (this.current_loc < sample_number) {
Expand All @@ -4514,6 +4529,7 @@ public:
}
// the next frame will start with the sample
assert(this.current_loc == sample_number);

return 1;
}

Expand Down

0 comments on commit 1f6ead0

Please sign in to comment.