0
0

I think that it is possible to calculate the length of a MOD file. I might be wrong but wouldn’t you be able to play the module file through and when the order number equals the max number of orders it closes the file and returns the time using FMUSIC_GetTime. The only problem is that you would have to play the whole file through.

I wrote some code that might do this:
[code:1gvx0i0l]

Public Function Calc_ModuleTime(filename As String) As Single

Dim tempChannel As Long
Dim tempModule As Long

tempModule = FMUSIC_LoadSong(filename)
FMUSIC_SetMasterVolume tempModule, 0
tempChannel = FMUSIC_PlaySong(tempModule)

Do Until FMUSIC_GetOrder(tempModule) = FMUSIC_GetNumOrders(tempModule)
    If FMUSIC_GetOrder(tempModule) = FMUSIC_GetNumOrders(tempModule) Then
        Calc_ModuleTime = FMUSIC_GetTime(tempModule)
        FMUSIC_StopSong (tempModule)
        FMUSIC_FreeSong (tempModule)
        tempChannel = 0
        tempModule = 0
    End If
Loop

End Function
[/code:1gvx0i0l]

Is there anyt way to speed up the song so that calculating the length doesn’t take so long?

Thanks.

  • You must to post comments
0
0

Just a thought but u could use my formual to preset a time difference when setting an order. For by keeping track of the “st” variable you could take the order number you are setting it to, multiple by st and that would be your posistion in MS, then just add that to fmods playtime and vola.

Hope ya know what i mean, if not i will clarify.

++Cire.

  • You must to post comments
0
0

Hmmm, interesting thought! I understand what you mean, thanks. ๐Ÿ˜€

  • You must to post comments
0
0

Ok its a really old thread :-)
but it doesnt work correct here.
[code:3efg4xrn]
FMUSIC_PlaySong(fMod);

int NumChannels,sng_NumOrders,i,end;
double t,st,bpm,speed;

bpm = FMUSIC_GetBPM(fMod);
speed = FMUSIC_GetSpeed(fMod);
end=(sng_NumOrders – 1);
// end=(sng_NumOrders); // tried both
for(i=0;i<=end;i++)
t+=FMUSIC_GetPatternLength(fMod, i); NSLog(@"\nSongLenghtInBytes:%.0lf\nSongLenghtInS:%.0lf\nSpeed:%.0lf\nBPM:%.0lf",t,(t*st)/1000,speed,bpm);[/code:3efg4xrn]
the first two or four PlaySong i get some really strange results.
and then about 90% are completly incorrect.

Sven

  • You must to post comments
0
0

That is how WinAmp tries to calculate the duration of a MOD (play the entire MOD as fast as possible with no sound output), but it still falls over when a loop is performed before the last pattern in the order. This is for MODs that have no end. WinAmp eventually times out on these MODs after a couple of minutes, ending up with something like 262,000 minutes.

  • You must to post comments
0
0

hmm, you looking for C code? Heres a snip from my app, applogies about not cleaning it up real nice but it should help you out. Once I have calculated the lenght, in my timer i simply keep checking against fmods time played of the mod/xm/it, whatever and if its duration is greater then or equal to what i calculated then I select another song, its not a perfect soulation but it does work well for most mods.

You could improve it by reading speed changes and what not and making adjustments on the fly, some mods i have tested jump speeds alot, and this can throw off the calculations quite a bit, but i’am just too lazy. :)

Anyhow hope it helps.

[code:alt6ezoe]
FMUSIC_MODULE * STRM;
int sng_NumOrders, sp, t, st, i;
FSOUND_STREAM * tmpStrm;
HANDLE fHandle;
DWORD bytesread;
char Buffer[31];
clApp *myApp = (clApp *)app;

STRM = FMUSIC_LoadSong( myApp-&gt;Song-&gt;chFileName);
FMUSIC_PlaySong(STRM);

NumChannels = FMUSIC_GetNumChannels(STRM);
sng_NumOrders = FMUSIC_GetNumOrders(STRM);
BPM = FMUSIC_GetBPM(STRM);
sp = FMUSIC_GetSpeed(STRM);
KBPS = ((BPM * 2) / 5);
st = int(((1.0 / KBPS) * 1000) * sp);
t = 0;

for( i = 0;i &lt; (sng_NumOrders - 1);i++ ) {
      t += FMUSIC_GetPatternLength(STRM, i);
}

LenInBytes = t;
myApp-&gt;Song-&gt;lSongLenght = t * st;

FMUSIC_StopSong(STRM);
FMUSIC_FreeSong(STRM);

myApp-&gt;Song-&gt;blReadSongData = true;

[/code:alt6ezoe]

++Cire.

  • You must to post comments
0
0

I use the following Snip of code to calculate a modules lenght, though not 100% accurate it is very fast.

[code:haln9woo]
STRM = FMUSIC_LoadSong(strFileName)
Call FMUSIC_PlaySong(STRM)

sng_NumChans = FMUSIC_GetNumChannels(STRM)
NumChannels = sng_NumChans
sng_NumOrders = FMUSIC_GetNumOrders(STRM)
BPM = FMUSIC_GetBPM(STRM)
speed = FMUSIC_GetSpeed(STRM)
KBPS = ((BPM * 2) / 5)
st = ((1 / KBPS) * 1000) * speed

For i = 0 To (sng_NumOrders - 1)
    t = t + FMUSIC_GetPatternLength(STRM, i)
Next i

SongLenghtInBytes = t
SongLenghtInMS = t * st

[/code:haln9woo]

Hope it helps. Again, this is not 100% accurate and will fail on some modules but the 99% of them will work correctly. Ideally this should be adjusted to adjust the songs length, should the songs speed be changed. For example if its playing at speed 3 and then changes to 5 at order 20 then adjustments should be done however i’am to lazy to do that right now, lol. :) Anyhow best of luck.

++Cire.

  • You must to post comments
0
0

thanks. Works great with both libs …fmod and mikmod.
i recalculate the time every second, and by some files the times jumps extremly …..
but it works …. :-)

Sven

  • You must to post comments
0
0

Hey, nice code. It works great, except for what you’ve already mentioned about the never ending mods. Thanks.

  • You must to post comments
0
0

Recalculate each second, ouch, might be a bit over doing it there, probably better to sorta lenght and then make modifications if th speed changes.

Anyhow glad it helped.

++Cire.

  • You must to post comments
0
0

Alright, I’ll try that. Thanks.

  • You must to post comments
0
0

That’s how I calculate length of module (currently only XM format is supported):

[code:11jcfjc4]uses Bitwise;

type XMRow = record
Note, Inst, Volc, Effc, Effp : byte;
end;

function XMGetLengthSec(Filename : string) : single;
const
cCorrection = 1.1;
cMaxDuration = 10700;
var h, i, c, r, b : integer;
sngSecLength : Single;
T1 : String[64];
T2, {SngLength, sngChnls, sngPatterns, sngSpeed, sngBPM,} TPS, PRows,
cBPM, cSpd, cPat, cRow, eeMod, cJmp, cLp, cLpNo : Word;

Data: array of array of array of XMRow;
SngLength, sngChnls, sngPatterns, sngSpeed, sngBPM : Word;
PatternTable: array[1..256] of Byte;

T3 : LongWord;
T4, Cmd1, Cmd2, Cmd3, Cmd4, Cmd5, Cmd1t : byte;
cBrk : Boolean;
//Data: array{[1..256,1..32,1..256,1..5]} of Word;//Order, Channel, Row, Byte

begin
h := FileOpen(FileName,0);
FileRead(h,T1,60);
sngSecLength := 0;

FileRead(h,T3,4);
FileRead(h,sngLength,2);
FileRead(h,T2,2);
FileRead(h,sngChnls,2);
FileRead(h,sngPatterns,2);
FileRead(h,T2,2);
FileRead(h,T2,2);
FileRead(h,sngSpeed,2);
FileRead(h,sngBPM,2);
FileRead(h,PatternTable,256);

SetLength(Data, sngPatterns);

for i := 1 to sngPatterns do begin
FileRead(h,T3,4);
FileRead(h,T4,1);
FileRead(h,PRows,2);
FileRead(h,TPS,2);

SetLength(Data[i-1], PRows);

if not(TPS = 0) then begin
  for r := 1 to PRows do begin
    SetLength(Data[i-1,r-1], sngChnls);
    for c := 1 to sngChnls do begin
      Cmd1 := 0;
      FileRead(h,Cmd1,1);
      Cmd2 := 0;
      Cmd3 := 0;
      Cmd4 := 0;
      Cmd5 := 0;
      if not(Bit(Cmd1,7)) then begin
        FileRead(h,Cmd2,1);
        FileRead(h,Cmd3,1);
        FileRead(h,Cmd4,1);
        FileRead(h,Cmd5,1);
        Cmd1t := Cmd1;
      end else
      if Bit(Cmd1,7) then begin
        if Bit(Cmd1,0) then
          FileRead(h,Cmd1t,1);
        if Bit(Cmd1,1) then
          FileRead(h,Cmd2,1);
        if Bit(Cmd1,2) then
          FileRead(h,Cmd3,1);
        if Bit(Cmd1,3) then
          FileRead(h,Cmd4,1);
        if Bit(Cmd1,4) then
          FileRead(h,Cmd5,1);
      end;
      Data[i-1,r-1,c-1].Note := Cmd1t;
      Data[i-1,r-1,c-1].Inst := Cmd2;
      Data[i-1,r-1,c-1].Volc := Cmd3;
      Data[i-1,r-1,c-1].Effc := Cmd4;
      Data[i-1,r-1,c-1].Effp := Cmd5;
    end;
  end;
end else begin
  for r := 1 to PRows do begin
    SetLength(Data[i-1,r-1], sngChnls);
    for c := 1 to sngChnls do begin
      Data[i-1,r-1,c-1].Note := 0;
      Data[i-1,r-1,c-1].Inst := 0;
      Data[i-1,r-1,c-1].Volc := 0;
      Data[i-1,r-1,c-1].Effc := 0;
      Data[i-1,r-1,c-1].Effp := 0;
    end;
  end;
end;

end;

cBPM := sngBPM;
cSpd := sngSpeed+1;
cPat := 0;
cRow := 0;
cLp := 65535;
cLpNo := 0;
repeat
eeMod := 1;
cBrk := False;
cJmp := 65535;
for c := 0 to sngChnls – 1 do begin
if Data[PatternTable[cPat],cRow,c].Effc = $F then
if Data[PatternTable[cPat],cRow,c].Effp > 31 then cBPM := Data[PatternTable[cPat],cRow,c].Effp else cSpd := Data[PatternTable[cPat],cRow,c].Effp;
if (Data[PatternTable[cPat],cRow,c].Effc = $E) and (Data[PatternTable[cPat],cRow,c].Effp div $10 = $F0) then begin
eeMod := Data[PatternTable[cPat],cRow,c].Effp mod $10 + 1;
end;
if (Data[PatternTable[cPat],cRow,c].Effc = $D) then cBrk := True;
if (Data[PatternTable[cPat],cRow,c].Effc = $B) then cJmp := Data[PatternTable[cPat],cRow,c].Effp;
if (Data[PatternTable[cPat],cRow,c].Effc = $E) and ((Data[PatternTable[cPat],cRow,c].Effp – (Data[PatternTable[cPat],cRow,c].Effp – 240)) = $60) then
if Data[PatternTable[cPat],cRow,c].Effp – 96 = 0 then cLp := cRow else begin
if cLpNo = 0 then cLpNo := Data[PatternTable[cPat],cRow,c].Effp – 96;
end;

  if not(cLpNo = 0) and not(cLp = 65535) then begin
    cRow := cLp;
    cLpNo := cLpNo - 1;
  end;
  if cLpNo = 0 then
    cLp := 65535;
end;
sngSecLength := sngSecLength + cCorrection*(2/(cBPM / cSPD))*(eeMod);
cRow := cRow + 1;
if (cJmp &lt;&gt; 65535) then begin
  cRow := 0;
  cPat := cJmp;
end;
if (cRow &gt; High(Data[PatternTable[cPat]])) or cBrk then begin
  cRow := 0;
  cPat := cPat + 1;
end;

until (cPat >= sngLength) or (sngSecLength > cMaxDuration);

FileClose(h);

if sngSecLength < {7200}cMaxDuration then Result := sngSecLength else result := 65535;
end;[/code:11jcfjc4]

I don’t recomend to use it at this stage, coz it is not completed.
But if I finish it, I will post it here.

The general idea is to go throught all module, untill end, calculating time for each note. If time gets bigger than cMaxDuration than exit, telling user that it is infinite loop.

Function returns time in seconds, or 65535 if module is looped.

For this time, there is a bug, so I can say that it is 60-80% accurate. But, with-out bug, it can be up to 99% accurate!

This piece of code may help you:
[code:11jcfjc4] Nrw := 1;
Npt := 1;
Nrw := (FMUSIC_GetOrder(module)FMUSIC_GetPatternLength(Module, FMUSIC_GetOrder(module)-1) + 1 + FMUSIC_GetRow(module)) / (FMUSIC_GetPatternLength(Module, 0)FMUSIC_GetNumOrders(module));//(FMUSIC_GetRow(module)(FMUSIC_GetPatternLength(Module, FMUSIC_GetOrder(module)))) / (FMUSIC_GetPatternLength(Module, FMUSIC_GetOrder(module))FMUSIC_GetNumOrders(module));
Nmax := (FMUSIC_GetNumOrders(module)FMUSIC_GetPatternLength(Module, FMUSIC_GetNumOrders(module)-1) + 1 + FMUSIC_GetPatternLength(Module, FMUSIC_GetNumOrders(module))) / (FMUSIC_GetPatternLength(Module, 0)FMUSIC_GetNumOrders(module));
//Npt := FMUSIC_GetOrder(module) / FMUSIC_GetNumOrders(module)+0.1;
TimeBar.Caption := format(’Module | Time: %s of %s’,[FromatTime(round(FSongs[Index].TimeNrw10)),FromatTime(round(FSongs[Index].TimeNMax10))]);[/code:11jcfjc4]

Ignore “FromatTime” function, it is for internal puporses.
Again, that’s MY way, and I don’t ask yo to follow it.

And helpful thing…

[code:11jcfjc4]unit Bitwise;

interface

function Bit(const val: longint; const TheBit: byte): boolean;
function BitOn(const val: longint; const TheBit: byte): LongInt;
function BitOff(const val: longint; const TheBit: byte): LongInt;
function BitToggle(const val: longint; const TheBit: byte): LongInt;

implementation

function Bit(const val: longint; const TheBit: byte): boolean;
begin

result := (val and (1 shl TheBit)) <> 0;
end;

function BitOn(const val: longint; const TheBit: byte): LongInt;
begin

result := val or (1 shl TheBit);
end;

function BitOff(const val: longint; const TheBit: byte): LongInt;
begin

result := val and ((1 shl TheBit) xor $FFFFFFFF);
end;

function BitToggle(const val: longint; const TheBit: byte): LongInt;
begin

result := val xor (1 shl TheBit);
end;

end. [/code:11jcfjc4]
Always yours, Black Phoenix.

  • You must to post comments
0
0

How would I update the FMUSIC_GetTime after seeking a module using FMUSIC_SetOrder? Because after I use SetOrder the time doesn’t change according to the position. Oh, and also, how do I use FMUSIC_GetName? When I use it all I get is a string of numbers.

Thanks.

  • You must to post comments
0
0

Hi Alex

the function gallery reports – file not found – for most if not all of the functions and I would like to plot the log_spiral – can you help?

Best wishes,
Nic

  • You must to post comments
0
0

Not sure about the order thing, it might be a slight bug within Fmod, however, you can get the songs name via this function call.

[code:1g2w4vi6]
strSongName = GetStringFromPointer(FMUSIC_GetName(STRM))
[/code:1g2w4vi6]

The GetStringFromPointer should be defined within the Fmod.bas file. If you don’t have it I can post it here.

++Cire.

  • You must to post comments
0
0

Oh ok, thanks Cire. It works good. I might have to ask Brett about the order thing, but what I was thinking is that since FMUSIC_GetTime just gives the amount of seconds past since the song started playing, it wouldn’t be able to update according to an order change, but maybe I’m wrong :)

  • You must to post comments
0
0

Hehe, interesting hypothesis! ๐Ÿ˜€ Black hole, lol.

  • You must to post comments
Showing 16 results
Your Answer

Please first to submit.