Need Help Finding Sample Number When Song Fades Out

Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Need Help Finding Sample Number When Song Fades Out

fredvs
Administrator
**@rfetn42: your post was wrongly deleted, sorry**

The short story is I want to replace an old free version of ZaraRadio Free Edition (radio station automation software) which has not been updated in years with a new Object Pascal program based on my own requirements.

I am currently using a recently downloaded flat version of UOS in Lazarus 4.6 and FPC 3.2.2 on a beefy laptop running Fedora Linux 44 (Workstation Edition).  Using the provided examples, I created an application that plays MP3s, shows the position on a track bar, jumps to random positions via the track bar, implements VU meters, and displays waveforms.

One major requirement of mine that ZaraRadio Free Edition cannot do is find the last sample of an audio file before it drops below a certain threshold.  In other words, as a song fades out, when it drops below a certain level, I want to start the next song playing.

Without examples on how to do that, I ask several AIs how they would do it.  They keep giving me code that will not compile calling functions that do not exist and when I call them on that, I eventually can get code that at least compiles after I fix a few things, but then ultimately will not work.  For example:
// uos_InputBufferRead returns data in bytes. 1 sample (16-bit) = 2 bytes.
BytesRead := uos_InputBufferRead(ScanPlayer, InIdx, @Buffer[0], SizeOf(Buffer));

I did locate an example using “uos_InputSetLevelArrayEnable” and “uos_EndProc” and in the end procedure called “uos_InputGetLevelArray” to get what I think is averaged data, but I cannot get the sample number where the fadeout started.

Is there a good example out there how to do what I suspect should be relatively simple task?  From what I have learned, it may be complex as a MP3 file has to be reconstituted and the real solution will resemble something like the waveform example.
Reply | Threaded
Open this post in threaded view
|

Re: Need Help Finding Sample Number When Song Fades Out

fredvs
Administrator
@rfetn42: Welcome to uos forum.

I apologize for your post wrongly deleted.

It is possible to do what you asked, I will give you a demo asap.

Write you later.

Fred
Reply | Threaded
Open this post in threaded view
|

Re: Need Help Finding Sample Number When Song Fades Out

fredvs
Administrator
This post was updated on .
Hello.

Not sure that i understood what you want but for this you may use uos_LoopProcIn().

Example:

var
Inputlength1 : integer;
mixisdone : boolean = false;

procedure tsongplayerfo.createplayer();
begin
...
Inputlength1 = uos_Inputlength(theplayer, Inputindex1);
uos_InputSetPositionEnable(theplayer, Inputindex1, 1);
uos_OutputSetLevelEnable(theplayer, Outputindex1, 2);
uos_LoopProcIn(theplayer, Inputindex1, @LoopProcPlayer1);
...
end;

   
procedure tsongplayerfo.LoopProcPlayer1();
var
mixlevel : float = 0.2 ; // the minimum volume
startcheckposition : integer = 10000 ; // the position when to start to check level
begin
if mixisdone = false then // was the mix already done
if uos_InputPosition(theplayer, Inputindex1) > Inputlength1 - startcheckposition then // when start to check volume
if (uos_outputGetLevelLeft(theplayer, outputindex1) < mixlevel) or
   (uos_outputGetLevelright(theplayer, outputindex1 < mixlevel) then // the level when to do the mix
  begin
  mixisdone = true;
  uos_play(theplayer2); //play the player2 to mix
  end;
end;
------------------------------------------

If you want that more than one sample is used and do a average you can use a array to store uos_outputGetLevel() and in LoopProcPlayer1 fill that array at each loop on a new index, something like

var
levelar : array of float;
indexar: integer = 0;
lengthofar : integer = 100;

// in init
setlength(levelar, lengthofar) // set the length of the array

procedure tsongplayerfo.LoopProcPlayer1();
var
mixlevel : float = 0.2 ; // the minimum volume
startcheckposition : integer = 10000 ; // the position when to start to check level

begin
if mixisdone = false then // was the mix already done
if uos_InputPosition(theplayer, Inputindex1) > Inputlength1 - startcheckposition then // when start to check volume
then begin
levelar[indexar] :=( (uos_outputGetLevelLeft(theplayer, outputindex1) +  (uos_outputGetLevelRight(theplayer, outputindex1) / 2);
if indexar = lengthofar - 1 then
  begin
  // calculate the average of the array I let you do it
  if averageofarray <= mixlevel then
    begin
    mixisdone = true;
    uos_play(theplayer2); //play the player2 to mix
    end else indexar := 0;
end else inc(indexar);
end;



     
Reply | Threaded
Open this post in threaded view
|

Re: Need Help Finding Sample Number When Song Fades Out

rfetn42
Thank you for the reply.  I was able to get the first of your examples working.  At first it did not work, getting caught in the default frame being too large to catch the fade out of the song.  Dropping the frame rate to 4,096 did the trick as well as increasing the "startcheckposition" to one million.

But the level at that resolution dropped below 0.2 too early and the next song started playing many seconds too early.  Something I was sure would happen occasionally.

What I really want to do is start at the end of the MP3 file and look for the first place the level increases above 0,2.  Then note that sample number.  This could happen while the song starts playing the main player and a second player does the reverse level check.  Then when the main player hits that sample number, it would start the next player playing.  Does that make sense?

I did get really excited to have the second song start automatically playing even if it was too early.  Proved what I want to do is possible.
Reply | Threaded
Open this post in threaded view
|

Re: Need Help Finding Sample Number When Song Fades Out

fredvs
Administrator
This post was updated on .
Hello and sorry for the delay.

About calculate the level from the end of a second player, of course you can do it, take a look at formspectrum example.
But imho it is more complicated because you need to load a second player and have to calculate the relative position.
Did you try the second demo in first post using a array of levels, it should be more accurate than using only one buffer of samples like in first example. Of course you must adapt the parameters, in the demo they are only to give the idea.
Reply | Threaded
Open this post in threaded view
|

Re: Need Help Finding Sample Number When Song Fades Out

rfetn42
Good news.  I pondered and tried the ideas from your latest post, but as I was getting it to work, I realized it was not exactly what I wanted to do.

Then I returned to the simple player code.  First I added a line to put the right level, left level, and current sample into the form's caption.  Then I added a button to move the current play position to the end.  Then I checked the reverse box and let it start playing.  Then I hit the end button and the song immediately stopped playing.  After some guesses, I figured out I needed to go to the end of the song minus the frame rate minus one.  Then when I hit the end button, I could see the left and right levels start at zero and work their way up as the song faded up backwards.

Now I have logic than can calculate the sample where the volume falls below a certain threshold.  Next I need to isolate that and see if I can accomplish the same thing in the same player.  Hopefully I can share that logic towards the end of the week.