Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: foo loop play with LoopStart/LoopLength/LoopEnd tags (Read 3072 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

foo loop play with LoopStart/LoopLength/LoopEnd tags

# foo_loop_play_with_tags

This is a foobar2000 component/plugin for gapless/seamless looping play of tracks with loop tags/metadata/points.

- Version 1.0. Build with SDK 2023-09-23, should work with foobar2000 v1.5 and newer.
- Supported processor architectures: x86 32-bit, x86 64-bit.

## Supported loop tags/metadata
- The supported tags are LOOPSTART/LOOPLENGTH/LOOPEND and Loop_Start/Loop_Length/Loop_End, case insensitive.
- Integer values are treated as samples and decimals with a decimal point are treated as seconds.
- The loop start tag must be present, and if loop length and end cannot be found, the end of the track is used as the loop end.

## Features
- When looping, the slider loops to the loop_start point in the seebar, and the statusbar displays the corresponding playback time of the original track.
- Configurable Loop count and total looping playback time.
- The number of loops and total time played can be configured to be displayed on the statusbar using the provided title formatting fields.
- All metadata reads and writes are redirected to the original track.

## Basic Usage
1. Install the component to foobar2000.
2. Activate the "Loop play with LoopStart/Length/End tags" DSP and place the DSP at the beginning of the DSP chain. (Preferences -> Playback -> DSP Manager)
3. Play tracks that have loop tags. It will loop play 8 times or play 16:32.256 (minutes:seconds.fractional seconds) with default configuration.
4. (Optional) Append the next line to the end of the status bar's formatting string to display looping count and played time. ("Preferences -> Display -> Default User Interface -> Playback state display formatting -> Status Bar")

Code: [Select]
[ | %loop_playing_section%: ][%loop_looping_count%][ / %loopcfg_loop_count%][ | %loop_played_time%][ / %loopcfg_play_time%]
## Configuration
Configuration is available at Preferences -> Playback -> Decoding -> ".looper shim file decoder to loop play with LoopStart/LoopLength/LoopEnd tags." -> "configure".
1. Loop mode
   - Loop normally: Loops for the specified number of times or playback the specified time, stopping when either comes first.
     * Loop count: Integer, 0 means no limit. When set to n > 0, the intro + loop x n times + outro will be played.
     * Playback time: [HH:][MM:]SS[.fff], 08:16:32.256 or 29792.256 is ok, 0 means no limit.
   - Loop forever: Loop playback with no limit.
   - Loop disable: Disable loop playback.
2. Loop sample accurate: decode forward and then discard samples instead of seeking internally, seeking to the very beginning first if necessary. Default: unchecked.
3. Force loop: loops the whole track when no valid loop tags found. Default: unchecked.
4. Enable .looper decoder for all extensions to loop playback without a shim file. May need to manually place the decoder at the beginning of the precedence list for this to work.
5. Enable .loopcut decoder for all extensions to cut tracks without a shim file. May need to manually place the decoder at the beginning of the precedence list for this to work.

## Title formatting fields
This component comes with several title formatting fields. Available only in contexts where playback related data is displayed, such as statusbar.
Syntax                      Description                
---------------------------- ----------------------------
%loopcfg_loop_count%        Configured loop count, displayed as 0 when loops forever.
%loopcfg_play_time%         Configured playback time, formatted as [HH:]MM:SS, displayed as 0:00 when loops forever.
%loopcfg_play_time_seconds% Configured playback time, in seconds, displayed as 0 when loops forever.
%loop_looping_count%        Current looping count, 0 for the intro section, 1 for the first loop section, and increasing on new loops. Reset to 0/1 on seek.
%loop_played_time%          The total time played of the current playback, formatted as [HH:]MM:SS. Reset to seek time on seek.
%loop_played_time_seconds%  The total time played of the current playback, in seconds. Reset to seek time on seek.
%loop_playing_section%      Current playback section, intro/loop/outro.
## Supported modes
This component has several modes.
For playback, the decoder shim mode is preferred, followed by the .looper shim file mode.
When looping with valid loop tags, the console will print the LOOP_START and LOOP_END tags in sample, decimal seconds, and human-readable [MM:]SS.fff formats.

### decoder shim mode
1. When the DSP is active and placed at the beginning of the DSP chain.
2. Can auto loop with valid loop tags found.
3. All configurations and title formatting fields are valid.
4. Cannot be used for conversion.
5. The console will print "Using decoder shim instead of DSP: Loop play with LoopStart/LoopLength/LoopEnd tags".

### dsp mode
1. When the DSP actived and not placed at the beginning of the DSP chain.
2. Can only loop in the "Loop forever" mode with "Repeat (track)" playback order selected.
3. Only the "Loop disable" configuration is valid. Title formatting fields are invalid.
4. Cannot be used for conversion.
5. The console will print "Using DSP instead of decoder shim. Select the "Repeat (track)" playback order to loop play", for loopable tracks when not in.

### .looper decoder mode
1. Create a blank shim file "file.ext.looper" and play it. The .looper file can be virtual for playing. To do a batch process, export all tracks to a m3u/m3u8 playlist file. Open the playlist in a text editor and add .looper to the end of each filename.ext. Then open the new m3u/m3u8 playlist, each track should run in loop mode.
2. Can auto loop without DSP. The decoder can be enabled for all extensions to loop playback without a shim file. (configuration 4)
3. All configurations and title formatting fields are valid.
4. Can be used for conversion. The .looper shim file should be present when converting. For convenience, you can enable configuration 4 and convert the original tracks directly.
5. The Properties dialog box will display the <.LOOPER_TARGET> info in the Details tab.

### .loopcut decoder mode
1. The ".loopcut" shim file is used to cut loopable tracks into intro/loop/outro subsongs/sections. Create a blank shim file "file.ext.loopcut" and play it. Or use a m3u/m3u8 playlist file, just like .looper file.
2. Can loop play the "loop section" using foobar2000's "Repeat (track)" playback order.
3. Only the "Loop sample accurate" configuration is valid. Title formatting fields are invalid.
4. Can be used for conversion. The .looper shim file should be present when converting or enable configuration 5 to load the original tracks directly.
5. The Properties dialog box will display the <.LOOPCUT_TARGET> info in the Details tab.

Copyright (c) 2025 litproca

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #1
THANK YOU. I was literally just bemoaning that foobar doesn't support loop tags and decided to check just in case, and find a brand new plugin! It works perfectly, hallelujah.


Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #3
as mentioned in the text, you can put the loop to only once.

Also, thanks for making this. Now I just need to find a way calculate samplerate from 48000 to 44100 XD


A nitpick perhaps, but will you include support for LOOPS tag? Apparently some games use LOOPSTART-LOOPLENGTH in a single tag.
This is not a life-ending issue, as I can easily use mp3tag to extract that info and reintroduce it as seperate tags
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #4
Can this be used with "1 loop" for start and end, for the purposes @Giacomo requested in topic https://hydrogenaud.io/index.php/topic,127572.0.html ?
Yes, but take effect for all tracks. When these configurations are set, all tracks will play only the desired duration or reach end normally. The desired duration can be adjusted during playback.

  • Loop mode: Loop normally
  • Loop count: 1
  • Playback time: desired duration
  • Force loop: checked

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #5
as mentioned in the text, you can put the loop to only once.

Also, thanks for making this. Now I just need to find a way calculate samplerate from 48000 to 44100 XD


A nitpick perhaps, but will you include support for LOOPS tag? Apparently some games use LOOPSTART-LOOPLENGTH in a single tag.
This is not a life-ending issue, as I can easily use mp3tag to extract that info and reintroduce it as seperate tags
Probably not, too many other types of loop tags. As you said, you can convert the tags to regular tags. If you don't want to change the original file, you can use this plugin with foo_extenal_tags or m-tags.

Or use vgmstream alone as an alternative, which has a high probability of supporting such tags. As vgmstream automatically exports LOOP_START and LOOP_END tags, you can even use this plugin with vgmstrem to provide a different seek behavior and title format display.

BTW, I don't get the point of this sentence.
Quote
need to find a way calculate samplerate from 48000 to 44100

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #6
the amount of "samples" in a track is based on the length of the track and the samplerate (Hz). (seconds * samplerate = samples)

so if a track uses samples for it's accurace, then it will be affected by the samplerate.

Example: Gens D'armes from Ys 8: Lacrimosa of Dana
File 1: PC game file: .ogg / 158 seconds / 48000kHz / 7 604 224 samples
File 2: OST Rip: .flac / 173 seconds / 44100kHz / 7 632 240 samples
File 3: OST Rip2: .flac / 173 seconds / 48000kHz / 8 307 200 samples (upscaled File 2 to 48000kHz for this example)

Loop value on all files:
START: 207792
END: 7450198

As you hopefully can see if the simple image I created, the start and end points are different, depending on sample rate.
X

File 2 will loop later, because in this example, the OST rip version is longer, so the amount of samples are more than the game rip, but if File 2 had been as long as the game file, then it would most likely break, as the the END point would've been outside the track's length. Re-encoding File 2 to 48000 (File 3), the same loop point works flawlessly.

So to fix this, I either re-encode all OST files to 48000kHz (to no apparent gain), or recalculate all the samples from 48000 to 44100, and hope it doesn't sound too horrible XD

Edit: Just to verify, I'm not blaming you for this isn't working. The game devs inserted the tags based on their encoded data, not the CD, so it's on me to correct it. I was just showing you what I mean by the difference between 44100 and 48000 samples count

Edit 2: I just tried recalculating this track from 48000 to 44100 (easiest way I know is to "SAMPLE_COUNT/48000*44100=NEW SAMPLE_COUNT"), and I couldn't hear the looping
START went from 207792 to 190909, and
END went from 7450198 to 6844869.
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #7
Edit 2: I just tried recalculating this track from 48000 to 44100 (easiest way I know is to "SAMPLE_COUNT/48000*44100=NEW SAMPLE_COUNT"), and I couldn't hear the looping
START went from 207792 to 190909, and
END went from 7450198 to 6844869.
It should be fine,  check the console log. "When looping with valid loop tags, the console will print the LOOP_START and LOOP_END tags in sample, decimal seconds, and human-readable [MM:]SS.fff formats." So it should print something like this.
Quote
foo_loop_play_with_tags: LOOP_START: 190909   4.3290023   0:04.329
foo_loop_play_with_tags: LOOP_END: 6844869   155.2124490   2:35.212

To batch convert loop tags for different samplerate when resampling, you can use Properties/Automatically Fill Values for multiple tracks.
  • select Source : "Other..."
Code: [Select]
$div($mul(%loop_start%,%samplerate%),48000)|$div($mul(%loop_end%,%samplerate%),48000)
  • Pattern
Code: [Select]
%loop_start%|%loop_end%

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #8
To batch convert loop tags for different samplerate when resampling, you can use Properties/Automatically Fill Values for multiple tracks.
  • select Source : "Other..."
Code: [Select]
$div($mul(%loop_start%,%samplerate%),48000)|$div($mul(%loop_end%,%samplerate%),48000)
  • Pattern
Code: [Select]
%loop_start%|%loop_end%

Already did that with mp3tag. since I had to get LOOPSTART and LOOPEND from LOOPS anyways for some of the tracks.
But I didn't know you could do something similar with automatically fill, so will try that :)
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #9
I just made a seekbar script that can show the loop section for Spider Monkey Panel. Hope someone likes it.
X
Edit: Above is the Waveform Minibar (mod), below is the seekbar script.

Today was my first time using SMP. when I found seekbar.js. I realized I might be able to implement a feature I've always wanted to implement. I hadn't written JavaScript before, so I spent hours writing code with search. Finally I made it, cheers!

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #10
When using $if, which variable would you prefer we'd use?
I'll try to use %loop_playing_section% at the moment for a more overarching section. Ofcourse, this addition only currently works for Loops using sample count.

Code: [Select]
$if(%loop_playing_section%,%loop_playing_section%: %loop_looping_count% / %loopcfg_loop_count% | %loop_played_time% / %loopcfg_play_time% | Loop point: $if2(%LOOPEND%,$add(%LOOPSTART%,%LOOPLENGTH%)) | Current sample: ~$mul(%playback_time_seconds%,%samplerate%),)

intro: 0 / 2 | 0:01 / 10:00 | Loop point: 6837229 | Current sample: ~44100
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #11
When using $if, which variable would you prefer we'd use?
I'll try to use %loop_playing_section% at the moment for a more overarching section. Ofcourse, this addition only currently works for Loops using sample count.

Code: [Select]
$if(%loop_playing_section%,%loop_playing_section%: %loop_looping_count% / %loopcfg_loop_count% | %loop_played_time% / %loopcfg_play_time% | Loop point: $if2(%LOOPEND%,$add(%LOOPSTART%,%LOOPLENGTH%)) | Current sample: ~$mul(%playback_time_seconds%,%samplerate%),)

intro: 0 / 2 | 0:01 / 10:00 | Loop point: 6837229 | Current sample: ~44100
%loop_playing_section% is preferred. These title formatting fields are valid only when looping play is enabled and valid tags are found.

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #12
I don't know if this is too big of an ask, but is there a possibility to add a "soft stop" function?

What I mean is, when the feature is turned on/activated, instead of ending directly after the Playback time counter has been reach, play the current loop out (or set %loop_looping_count% to the last loop) and then progress to the outro.
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #13
I don't know if this is too big of an ask, but is there a possibility to add a "soft stop" function?

What I mean is, when the feature is turned on/activated, instead of ending directly after the Playback time counter has been reach, play the current loop out (or set %loop_looping_count% to the last loop) and then progress to the outro.
I thought about designing the “play time” the way it is now or the way you said, but what you said can be done by modifying the “loop count”, so it's the way it's implemented now. Consider that someone might need to loop for at least a specific amount of time and play to the end. What you said about adding a switch is a good idea. I'll add a config in the next release.

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #14
I've currently set it to 5 loops or 6 minutes (and 5 seconds, because I have a DSP fade-out of 5 seconds), so shorter tracks will usually play all their loops before reaching the playtime counter, but longer tracks with longer loops (one example I have is about 4 minutes long), so the 2nd loop will cut in the middle of the the loop instead of letting the song end "naturally".

To be honest, this was just a thing I started thinking about yesterday. Before, I've let game audio files, midis and MOD loop end whenever their respective playtime settings had been reached, but having listened more and more to OSTs, where they usually only let the songs loop ones or twice, that just feels more natural to me now.
Hardcore DJ

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #15
I don't know if this is too big of an ask, but is there a possibility to add a "soft stop" function?

What I mean is, when the feature is turned on/activated, instead of ending directly after the Playback time counter has been reach, play the current loop out (or set %loop_looping_count% to the last loop) and then progress to the outro.
foo_loop_play_with_tags v1.1

Add an option "Continue playback to end" under "Playback time". When playback time reached, continue playback to the end instead of stopping abruptly.

 

Re: foo loop play with LoopStart/LoopLength/LoopEnd tags

Reply #16
Thanks!
I just tested it, and it worked just as I had requested :)
Hardcore DJ