Rockbox Technical Forums

Support and General Use => Audio Playback, Database and Playlists => Topic started by: aaronamm on November 18, 2021, 12:38:49 AM

Title: How to delay at least 2 seconds between each song?
Post by: aaronamm on November 18, 2021, 12:38:49 AM
Hello everyone.
I want to use my iRiver iHP120 with Rockbox as a music source for recording MD discs.

The problem is an MD player needs at least 2 seconds of silence before starting a new song to create an auto-tracking correctly.

However, I could not find any existing setting or plugin to create at least two seconds gap between each song when playing with Rockbox.

Therefore, please could you suggest to me how to configure Rockbox, an existing plugin, or an idea to develop a plugin/code example to delay the amount of time before starting a new song.

Thank you so much.
Title: Re: How to delay at least 2 seconds between each song?
Post by: saratoga on November 18, 2021, 12:46:50 AM
 You could fake it with a playlist that had a bunch of short silent tracks between real tracks or else write your own plugin to add a pause between tracks, but I don't think there is a built in way to do this.

Also recording MD? What year is it :)
Title: Re: How to delay at least 2 seconds between each song?
Post by: aaronamm on November 18, 2021, 02:11:02 AM
Hello @saratoga
Thanks for your suggestion. It is a nice tip. However, I only wonder if we have a way to automate a process.
I would be glad if you could point me to a code example which controls/interrupts playing of a song.
Then I can use it in a custom plugin code.

Thank you.

Title: Re: How to delay at least 2 seconds between each song?
Post by: Bilgus on November 18, 2021, 09:42:22 AM
https://github.com/Rockbox/rockbox/blob/master/apps/plugins/lua_scripts/playback.lua#L352
this should get you started..

Code: [Select]
local function create_playlist(startdir, file_search, maxfiles)
--In lua you can define a function (locally) within another function
--find file function is passed to the get_files() fn
-- it allows us to do things with the match (accept or reject)
    function f_filedir_(name)
        if name:len() <= 2 and (name == "." or name == "..") then
            return false --reject
        end
        if name:find(file_search) ~= nil then
            maxfiles = maxfiles -1
            if maxfiles < 1 then
                action_set_quit(true)
                return true
            end
            return true --accept
        else
            return false --reject
        end
    end

    local norecurse  = false -- don't enter subdirs
    local f_finddir  = nil
    local f_findfile = f_filedir_
    local files = {}
    local dirs = {}
    local max_depth = 3

    dirs, files = get_files(startdir, norecurse, f_finddir, f_findfile, nil, max_depth, dirs, files)

    if #files > 0 then
        -- rb.audio("stop") -- for the pb example
        rb.playlist("create", scrpath .. "/", "playback.m3u8")
    end

    for i = 1, #files do
        if(i > 1) then
            rb.playlist("insert_track", "/yourtransition_file.mp3" or "?") -- might need to check if exist first...
        end
        rb.playlist("insert_track", string.match(files[i], "[^;]+") or "?")
    end
    if #files > 0 then
        rb.playlist("start", 0, 0, 0) --start playing it
    end

    for i=1, #dirs do dirs[i] = nil end -- empty table
    for i=1, #files do files[i] = nil end -- empty table
    --action_set_quit(false) -- for the pb example
end -- create_playlist
Title: Re: How to delay at least 2 seconds between each song?
Post by: aaronamm on November 18, 2021, 10:08:00 AM
@Bilgus

Thanks for your code example, I appreciate it.
This must be fun but it haven't done with Lua script before.
It's time for me to start learning Lua.

Thanks.
Title: Re: How to delay at least 2 seconds between each song?
Post by: aaronamm on February 28, 2022, 09:53:02 PM
@Bilgus
I have tried your code but I wonder if can solve a problem without a playlist with silent/transition song.
I tested the following code block but it doesn't show any message when playing a music.

Code: [Select]
function playback_event(id, event_data)
    rb.splash(0, id)
    rb.sleep(5 * rb.HZ)
end

local evp = rockev.register("playback", playback_event)


Could you please give me  a code block to register an event when playing a music?
Here is my idea:

Code: [Select]
function playback_event(id, event_data)
 -- if ending track event fired, pause playing for 2 seconds. 
end

local evp = rockev.register("playback", playback_event)

Thank you.
Title: Re: How to delay at least 2 seconds between each song?
Post by: Bilgus on February 28, 2022, 11:11:18 PM
Hey thats a pretty good plan!

The issue is that you need to keep the script running to process the events

you can increase the sleep to save power at the cost of waiting longer when you go to exit

here is the basic framework of what you are looking for

Code: [Select]

require("actions")
local evt -- Timer handle
function playback_event(id, event_data)

    if id == rb.PLAYBACK_EVENT_CUR_TRACK_READY then
        rb.splash(0, "Track Ready")
    elseif id == rb.PLAYBACK_EVENT_TRACK_SKIP then
        rb.splash(0, "Track Skip")
    elseif id == rb.PLAYBACK_EVENT_TRACK_BUFFER then
        rb.splash(0, "Track Buffered")
    elseif id == rb.PLAYBACK_EVENT_TRACK_CHANGE then
        rb.splash(0, "Track Change")
        rb.audio("pause")
        evt = rockev.register("timer", tmr_function, rb.HZ * 2)
    elseif id == rb.PLAYBACK_EVENT_START_PLAYBACK then
        rb.splash(0, "Start Playback")
    elseif id == rb.PLAYBACK_EVENT_TRACK_FINISH then
        rb.splash(0, "Track Finished")

    elseif id == rb.PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE then
            rb.splash(0, "Next Track Id3 Available")
    else
        rb.splash(0, "unknown id " .. id)
    end

end

function tmr_function(id, data)
    rockev.unregister(evt) -- remove timer
    rb.audio("resume")
    rb.splash(rb.HZ * 2, "Timer Fired")
    rb.lcd_clear_display()
    rb.lcd_update()
    rb.splash(0, "Waiting...")
end

do
    local act = rb.actions
    local quit = false

    function action_event(action)
        local event
        if action == act.PLA_EXIT or action == act.PLA_CANCEL then
            quit = true
        end
    end

    function action_set_quit(bQuit)
        quit = bQuit
    end

    function action_quit()
        return quit
    end
end

local function main()
    local TRACK_CHANGE = 16
    local TRACK_BUFFER = 2

    local eva = rockev.register("action", action_event)
    --local evp = rockev.register("playback", playback_event)
    --local evp = rockev.register("playback", playback_event, bit.bor(TRACK_CHANGE, TRACK_BUFFER ))
    local evp = rockev.register("playback", playback_event, TRACK_CHANGE)

    rb.lcd_clear_display()
    rb.lcd_update()
    rb.splash(0, "Waiting...")
    while not action_quit() do
        rb.sleep(rb.HZ / 2)
    end

    rb.splash(100, "Goodbye")
end

main()



my concern would be that sometimes you might get an event too late and the next song has started playing then paused for 2 seconds
you might be able to use the buffer event but thats probably too early..
Title: Re: How to delay at least 2 seconds between each song?
Post by: Bilgus on March 01, 2022, 12:24:22 AM
if you do have issues you could probably set Single Mode _> Track and then it will auto pause after every track unconditionally and the script will resume it

Settings>Playback Settings>Single Mode>Track
Title: Re: How to delay at least 2 seconds between each song?
Post by: Bilgus on March 01, 2022, 01:36:14 AM
Here is a version that sets single mode when started and restores the previous playback mode on exit
Works Well!

Code: [Select]

require("actions")
require("settings")

-- Functions for reading / writing settings
local var = {offset = 1, size = 2, type = 3, fields = 3}
local function get_var_fields(s_var)
    -- converts member string into table
    -- var = {offset, size, "type"}
    s_var = s_var or ""
    local o, s, t = string.match(s_var, "(0x%x+),%s*(%d+),%s*(.+)")
    local tvar = {o, s, t}

    return #tvar == var.fields and tvar or nil
end
local function bytesLE_n(str)
    str = str or ""
    local tbyte={str:byte(1, -1)}
    local bpos, num = 1, 0
    for k = 1,#tbyte do -- (k = #t, 1, -1 for BE)
        num = num + tbyte[k] * bpos
        bpos = bpos * 256 --1<<8
    end
    return num
end
--

local evt -- Timer handle
function playback_event(id, event_data)

    if id == rb.PLAYBACK_EVENT_CUR_TRACK_READY then
        rb.splash(0, "Track Ready")
    elseif id == rb.PLAYBACK_EVENT_TRACK_SKIP then
        rb.splash(0, "Track Skip")
    elseif id == rb.PLAYBACK_EVENT_TRACK_BUFFER then
        rb.splash(0, "Track Buffered")
    elseif id == rb.PLAYBACK_EVENT_TRACK_CHANGE then
        rb.splash(0, "Track Change")
        --rb.audio("pause")
        evt = rockev.register("timer", tmr_function, rb.HZ * 2)
    elseif id == rb.PLAYBACK_EVENT_START_PLAYBACK then
        rb.splash(0, "Start Playback")
    elseif id == rb.PLAYBACK_EVENT_TRACK_FINISH then
        rb.splash(0, "Track Finished")

    elseif id == rb.PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE then
            rb.splash(0, "Next Track Id3 Available")
    else
        rb.splash(0, "unknown id " .. id)
    end

end

function tmr_function(id, data)
    rockev.unregister(evt) -- remove timer
    rb.audio("resume")
    rb.splash(rb.HZ * 2, "Timer Fired")
    rb.lcd_clear_display()
    rb.lcd_update()
    rb.splash(0, "Waiting...")
end

do
    local act = rb.actions
    local quit = false

    function action_event(action)
        local event
        if action == act.PLA_EXIT or action == act.PLA_CANCEL then
            quit = true
        end
    end

    function action_set_quit(bQuit)
        quit = bQuit
    end

    function action_quit()
        return quit
    end
end

local function main()
    local pbmode = nil;
    local tvar = get_var_fields(rb.system.global_settings.single_mode)
    local voffset, vsize, vtype = tvar[var.offset], tvar[var.size], tvar[var.type]
    if (tvar ~= nil) then
        local singlemode = 1
        pbmode = bytesLE_n(rb.global_settings(voffset, vsize))
        if (pbmode ~= nil and pbmode >= 0) then
            -- set single mode
            rb.global_settings(voffset, vsize, singlemode)
        end
    end

    local TRACK_CHANGE = 16
    local TRACK_BUFFER = 2

    local eva = rockev.register("action", action_event)
    local evp = rockev.register("playback", playback_event, TRACK_CHANGE)

    rb.lcd_clear_display()
    rb.lcd_update()
    rb.splash(0, "Waiting...")
    while not action_quit() do
        rb.sleep(rb.HZ / 2)
    end

    --restore pbmode
    if (pbmode ~= nil and pbmode >= 0) then
        rb.global_settings(voffset, vsize, pbmode)
    end

    rb.splash(100, "Goodbye")
end

main()

Title: Re: How to delay at least 2 seconds between each song?
Post by: aaronamm on March 01, 2022, 10:16:12 AM
@Bilgus
Thank you so much for a working Lua script.
It is very useful and works as I expected.
I have tested with my iRiver iHP120 and it worked like a charm.

Really appreciate your help.
Title: Re: How to delay at least 2 seconds between each song?
Post by: aaronamm on March 04, 2022, 11:34:13 PM
@Bilgus

I have created a new Gist for syntax highlight and add credit message to you at the top of the script.
https://gist.github.com/aaronamm/41dbf6f46ea3063e383666cda8f0d998

Thanks again.
Title: Re: How to delay at least 2 seconds between each song?
Post by: Bilgus on March 05, 2022, 08:03:21 AM
@aaronamm I'm glad it worked for you!