MaxMod2 ChannelSeek() doesn't work right

BlitzMax Forums/BlitzMax Programming/MaxMod2 ChannelSeek() doesn't work right

GfK(Posted 2014) [#1]
Hello

Yep, MaxMod2 again! Bit of a long shot if anyone will be able to sort this...

Basically I want to resume music from the point at which it was last played. ChannelSeek() is the very function I need.

Now, it works IF I stream audio direct from the file. However, I'm loading the audio into a TBank first, and streaming the audio from there - that part works. But if I try to use ChannelSeek() on a channel being played from a TBank, the music always sets off from the beginning instead of from the specified position.

Does anybody have the knowhow to dig around in MaxMod and put this right?

FAILS:
Strict

Import MaxMod2.RtAudio
Import MaxMod2.OGG

SetAudioDriver("MaxMod RtAudio")
MaxModVerbose True

Graphics 800,600

Local bank:TBank = LoadBank("map.ogg")
Local chan:TChannel = CueMusic(bank)
ChannelSeek(chan,300000,MM_SAMPLES)
chan.setPaused(False)
Repeat
	Delay 1
Until AppTerminate() Or KeyHit(key_escape)


WORKS:
Strict

Import MaxMod2.RtAudio
Import MaxMod2.OGG

SetAudioDriver("MaxMod RtAudio")
MaxModVerbose True

Graphics 800,600

Local chan:TChannel = CueMusic("map.ogg")
ChannelSeek(chan,300000,MM_SAMPLES)
chan.setPaused(False)
Repeat
	Delay 1
Until AppTerminate() Or KeyHit(key_escape)



Derron(Posted 2014) [#2]
Depending on the audio source (incbin/tbank vs file) maxmod uses

MaxMod_CreateStream
or
MaxMod_CreateMemoryStream


Seems that the memory stream produces this problem. In my game I use TBanks too for musicstreams... never used "seeking" just pausing/resuming - which work like intented.
Maybe someone with time and "joy" has an eye on it.


bye
Ron


Kryzon(Posted 2014) [#3]
Hello.
I took a look at the source and it appears that, for some unknown reason, the Seek() method of MemAudioStream is commented out. It`s not doing anything.
It is located in `Maxmod2.mod\code\memorystream.cpp.`

Try uncommenting it by removing the double slashes at the beginning of each line, and rebuild the module.

You are handling the seeking correctly. Despite a comment in the source stating that one should seek with the Music object, seeking with the Channel object instead should be more appropriate as the Channel objects seem to manage the low level Music objects.


GfK(Posted 2014) [#4]
Yeah I tried that and it still was the same. Probably why it was commented out.


Derron(Posted 2014) [#5]
That commented portion isn't called when trying to seek in a tbank'ed ogg file.

Seems that "memorystream" is something like "recording the output to a memory stream".


The seeking within a file or tbank is done in file.cpp (but only the initial one).
-> cfile or cmem objects.

The "MUSIC->POS" is also set accordingly, maybe the "buffer" is kept filled.
Other ideas?


bye
Ron


GfK(Posted 2014) [#6]
Dunno. C++ is almost completely over my head. Am at a loss with it.


Kryzon(Posted 2014) [#7]
I have gone through the source a second time and I did not find anything that would produce that behaviour.
I suggest experimenting more to try and find more clues about what causes this. Use a different file, a different format, other seek positions etc.


Derron(Posted 2014) [#8]
As it happens to me too -- and I use another file this isn't the source, same for seek positions etc.

It just seems that changing the current position of the MUSIC-object does not change the currently played thingies.


Think the "easiest" thing is to add some "mmPrint" (or
cout << "mytext" << endl;
) within the functions and check how they get called - or if they do not get called correctly.

bye
Ron


Brucey(Posted 2014) [#9]
Cheer up, GfK. Get yourself rezzed next weekend and forget your troubles for a day :-p


GfK(Posted 2014) [#10]
I'm there all weekend!


Kryzon(Posted 2014) [#11]
I'm sure that this is not the cause, but I think the SeekFrom method of the Cmem class (used for memory streams) has some incorrect code.

In maxmod2.mod/code/file.cpp, the cmem::SeekFrom method needs this in place of its SEEK_END case:
		case SEEK_END:
			END=1;
			POS=SIZE+pos; return POS;



Derron(Posted 2014) [#12]
==== INCORRECT/WRONG - see EDIT4 ====

The OggLoader (ogg.cpp) responses with another stream-SIZE when using a memory stream instead of a file stream.


When thinking about the approach at all - there is no fault in it. A memoryStream consists of a memory block containing some data. This data could come from an internet stream. Doesn't it ?
So instead of using more and more memory the following might be done:
- A memory block large enough to store X seconds + latency seconds of "sound".
- The player now starts to play from MemBlockStart and plays until reaching MemBlockEnd - then he starts at MemBlockStart again. Meanwhile - the loader fills the MemBlock again with fresh data.


If that assumption is the way everything works - it naturally explains why "seeking" is not possible at all. Why its functions contain code... I don't know, maybe it is possible if you use a different memory stream.


When listening to an internet radio you cannot "seek" too (and I think you just accept it the way it is).


If you really need "preloaded" BANK-Music to avoid HDD-access - or in "traffic" in the case of remote-files (from your website) you might try something like a "filestream" or something acting like a "local file" - but this enforces you to know the total length of the file you stream...


Best bet is to change from "bank" to "file" as this simplifies things a lot - and reduces loading times a lot (load during usage not during startup).

Maybe I am totally wrong and someone fixes this... if so, I would be glad to include the fixes in my framework.


EDIT: I followed the suggestion to check another sound type (oggdec myfile.ogg -> myfile.wav) - seeking is then of course to call with a higher number ( about *10) but works for both: banks and uris.
This means: that things like "file.cpp" seem to work as intended and the difference is in format specific parts (or something "Ogg" defines itself).

EDIT2: within ogg.cpp special callbacks get defined ... if the stream consists of a memory stream, the size of the stream seems to get calculated incorrectly. So either that ogg-sources do something wrong - or they communication between that sources and the stream is somehow doing something wrong.

==== / INCORRECT/WRONG ====



EDIT3: Ok, back to file.cpp - seems something isn't correct with SeekFrom - rewrote that part (still have to fiddle with that "END" thingie ... shouldn't be needed) and now the debug messages seem to read correct sample
amounts. (file starts at the given spot too).

EDIT4: Shame on me... at the end I ended up with what Kryzon already posted... Thought I checked it before digging deeper ...seems I just spent some time doing the exact same thing he wrote.

file.cpp



bye
Ron


Kryzon(Posted 2014) [#13]
EDIT: I followed the suggestion to check another sound type (oggdec myfile.ogg -> myfile.wav) - seeking is then of course to call with a higher number ( about *10) but works for both: banks and uris.

If what you're stating is that a bank with WAV data can be sought correctly, then it is clear that the problem lies with the OGG player logic.


Kryzon(Posted 2014) [#14]
Another point worth of mention is that when you use LoadBank, the entire contents of the file are loaded into memory.
This means that using the CueMusic function to stream from the bank won't pose the same benefits that streaming from a file would.
A file would be streamed from the hard disk into memory in pieces, so the entire music file is never in memory at once.
A bank is streamed from memory, so the entire "file" is already loaded in memory.

This means that you can load the ogg music as a sound by using the MaxMod2 RTAudio driver with LoadSound and CueSound. Using a maxmod sound instead of a music will use a different seeking code and hopefully will allow you to seek without that resetting issue. The memory footprint should be the same as well.


Derron(Posted 2014) [#15]
I thought using "loadSound" means storing the whole thing decompressed in memory. Storing the OGGs as banks increases the overall memory usage but with a by 10 lower factor than with WAVs or "LoadSound-decoded ogg/mp3".

Banks would allow a "diskless" running mode (sometimes this might be wished) - it also allows standalone-binaries (incbin).


All in all I am on your side: loading from file should be the best thing as it saves memory (HDD > RAM in most cases). But there are surely cases which would benefit from other options.


If what you're stating is that a bank with WAV data can be sought correctly, then it is clear that the problem lies with the OGG player logic.

Most things get obvious _afterwards_ ;D


bye
Ron


GfK(Posted 2014) [#16]
loading from file should be the best thing as it saves memory
But we're talking maybe 3MB of memory for a 3-minute OGG file, plus a little maybe for buffering during playback, and the load-time is near-instant as no decompression is being done at that point. Plus you're losing the ongoing dependency on the hard drive. So streaming from RAM is the best option.

Using LoadSound for music is the worst option as the loading/decompression is slow.


Derron(Posted 2014) [#17]
@GfK
Better answer if this solves your problem or if this is still problematic on your side :D


bye
Ron


GfK(Posted 2014) [#18]
Nope, it's still bust. With Kryzon's addition I get the following output in verbose mode, then the tracks starts from the beginning:
MaxMod2: CMEM SEEK
MaxMod2: OGG Loader...
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: CMEM SEEK
MaxMod2: OGG accepted! samples=0
MaxMod2: channels=2
MaxMod2: freq=44100
MaxMod2: Ogg seek to:300000



[edit] ...and with yours, I get the same, only without the multiple CMEM SEEKs.


Derron(Posted 2014) [#19]
MaxMod2: OGG accepted! samples=0


Compare that amount of samples with the one when using the "Load(url)" method.

Yours stated - the seek-functionality returned something wrong.

If you want so see what happens - you could add a more detailed debug log:

ogg.cpp



Does it happen to ALL of your OGG files? did you check a one from the internet (maybe your encoder is problematic somehow).

If you "watch" what seek-calls are made you will see when loading from "url" you can compare if from "bank" leads to the same results or at which point they differ.


EDIT: hmm that is odd .. now the code seems to be not doing what it was supposed to do yesterday...

EDIT2: ahh ok ... forgot to change from "build release threaded" to "build release" (I only rebuilt the modules for "normal and debug").


Using the "cout << bla"-line of above I get the following:

soundfile: https://github.com/GWRon/TVTower/blob/master/res/music/Light%20banjo.ogg

oggCue.bmx


output:



bye
Ron


Kryzon(Posted 2014) [#20]
Dear GfK, if you're still looking for a solution to this, please post what is the console output of those two examples that you shared on the first post, when executed with a fresh install of the MaxMod2 module (without modifications).
I would like to know more information about this problem.


GfK(Posted 2014) [#21]
Um... haven't given it a thought, to be honest. Been away at EGX Rezzed since last Thursday night and haven't been near a PC [for coding purposes] all weekend.