Issues

Issue #421 resolved

MOD music formats don't loop correctly on "pattern jumps"

Anonymous created an issue

MOD music formats don't loop correctly on "pattern jumps"

There are cmds in MOD music files to loop parts of music seamlessly. I'm sure libmodplug should support this type of looping if enabled, for example in ModPlug player it could be enabled with "Repeat" button by clicking it several times to set "Repeat Infinite" mode.

Currently in Love 0.8.0 even with setLooping(true) done, MOD music decoder doesn't loop correctly on "pattern jump" cmds.

Could you, please, fix it?

Comments (8)

  1. Boolsheet

    I'm guessing ModPlug Player works very close with the source of the decoder because libmodplug only has a looping option at loadtime of the module which seems to be disabled (commented out in the source) anyway. How odd.

  2. Anonymous

    Well, I've read thru the code and I see now it's quite hard to implement such looping due to its dynamic nature.

    I suppose it still could be implemented via additional param in newDecoder (thus forcing mLoopCount = -1) and then creating source only as "stream" (automatically, ignoring second argument of newSource), but maybe it's a way too complex for lovely simplicity of LOVE...

    Hmm. Okay, let's face it -- such looping is not the thing anyone needs "in first place".

    But I will greatly appreciate if you ever implement the workaround: newDecoder( "test.mod", 2048, "dynamic_stream") forcing mLoopCount=-1 in ModPlugDecoder and newSource internally forced to "stream" to always read data from decoder by blocks, because "dynamic_stream" mode is supposed to "possibly never end".

    How do you think?

  3. Anonymous

    Now I've read src of libmodplug, ModPlug_Settings.mLoopCount -> SetRepeatCount(n) -> m_nRepeatCount commented only in sndmix.cpp, but actually used in snd_fx.cpp (CSoundFile::ProcessEffects), because it should only loop on fx "pattern jump" cmds, so I think it should work as intended and loop looped modules.

    Anyway, for LOVE this requires "dynamic_stream" mode. And in such mode fx looping is internal behaviour of stream itself and should not tried to be controlled via setLooping().

    So I suggest it's all possible, with "dynamic_stream" mode.

  4. Anonymous

    Consider these scenarios:

    s1 = love.audio.newSource( "test1.mod", "dynamic_stream" ) s1.play() -- creates ModPlugDecoder and switches it to dynamic mode (loops enabled)

    d2a = love.sound.newDecoder( "test2.mod", 2048 ) s2a = love.audio.newSource( d2a, "dynamic_stream" ) s2a.play() -- switches given d2a decoder to dynamic mode (with loops for ModPlugDecoder, re-loads module)

    d2b = love.sound.newDecoder( "test2.mod", 2048, "dynamic" ) s2b = love.audio.newSource( d2b ) -- second arg ignored and forced to "dynamic_stream", because d2b is "dynamic" s2b.play() -- d2b in dynamic mode (loops enabld for ModPlugDecoder, no re-loading required)

    d3 = love.sound.newDecoder( "test3.mod", 2048 ) s3 = love.audio.newSource( d3, "stream" ) s3.setLooping(true) s3.play() -- normal stream mode, standard looping works

    d4 = love.sound.newDecoder( "test4.mod", 2048 ) s4 = love.audio.newSource( d4, "static" ) s4.setLooping(true) s4.play() -- static mode, sound data created internally, standard looping works

    Any flaws?

  5. Boolsheet

    Oh, I see. libmodplug didn't like the two modules I tested. Looping worked with the third module I threw at it.

    Such a looping option surely is attractive for modules, but libmodplug just can't make any friends around here. As you said, there must be an additional newDecoder argument just for libmodplug. I have the feeling that it'll be a very low priority.

  6. Log in to comment