Recent

Author Topic: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event  (Read 19241 times)

fauri

  • New Member
  • *
  • Posts: 15
Hi everyone! Firstly, sorry for my english.

I wonder if there a optimized way to run small sound files at intervals of a few milliseconds with UOS. I'm developing a drum machine, and I haven't found a way to store a sound that will be played countless times (like a kick drum or snare, for example). Until now, the only way I found was to use uos_CreatePlayer and uos_AddFromFile functions at each execution.

Is there a way to create a player only once and just use uos_Play () inside a OnTimer event? Thanks.

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #1 on: February 20, 2017, 04:07:23 pm »
Hello.
Quote
Is there a way to create a player only once and just use uos_Play () inside a OnTimer event?

Yes. You should use:
Code: Pascal  [Select][+][-]
  1. uos_PlayNoFree()
instead of 
Code: Pascal  [Select][+][-]
  1. uos_Play()

It will start playing but will not free the player after stop. (You have to free it by code when needed.)

Fre;D


I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

metis

  • Sr. Member
  • ****
  • Posts: 300
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #2 on: February 20, 2017, 06:45:38 pm »
@fauri

Slowest Way:
Open & Close, resp. Start & Stop the Player again and again.

Better:
Store the StartPosition of the Loop, and then seek back to it repetitively in Your App.

Even better:
Store the StartPosition of the Loop, and then seek back to it repetitively in the DecodingLoop.
BTW: This is done in the last Release of 'FFPlay4Laz', when You press <l> (= Looping): 
     http://forum.lazarus.freepascal.org/index.php/topic,26666.msg215455.html#msg215455

Much better:
Put the AudioSamples into a Queue, and have them repeated.
As an Example for how to read from/write to a SampleQueue in Pascal, see the PacketQueue of 'FFPlay4Laz':
http://forum.lazarus.freepascal.org/index.php/topic,26666.msg196377.html#msg196377
-> Download the Attachment 'DrangerTutorial08.c2FPC.lpr.zip'
   -> GoTo: 'packet_queue_put()' and 'packet_queue_get()'.

Tip:
To achieve "intervals of a few milliseconds", use an Endless-Loop, instead of a Timer.

 :)
« Last Edit: February 27, 2017, 05:13:51 pm by metis »
Life could be so easy, if there weren't those f*** Details.
My FFmpeg4Lazarus = FFPlay4Laz + FFGrab4Laz + FFInfo4Laz

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #3 on: February 20, 2017, 08:04:52 pm »
@Fred, thanks for the tips. I tested it in two ways:

Inside OnTimer
Code: Pascal  [Select][+][-]
  1.    uos_Stop(0);
  2.    uos_PlayNoFree(0);

and

 
Code: Pascal  [Select][+][-]
  1. uos_Seek(0, input, 0);
  2. uos_PlayNoFree(0);

In both ways, uos_PlayNoFree becomes out of sync with OnTimer. It looks like the function waits the end of the sound, even using uos_Stop or uos_Seek.

@metis, amazing suggestions! I'll take a look. By the way, I'm not using a TTimer, but a ThreadTimer, with a OnTimer function.

Thanks for now, guys!
« Last Edit: February 20, 2017, 08:31:29 pm by fauri »

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #4 on: February 20, 2017, 08:52:28 pm »
Hello.

Did you look at MorseTL (Morse translator) demo ?
It uses 2 players and uos_EndProc(player, @CreateMorsePlayer);

At end of the sound (or stop), a procedure : EndProc is executed.
In that case it creates a new player but you can use it with uos_PlayNoFree() too.
So you do not need any timer.

But if you prefer use a timer, IMO, you will have better result when using 2 players, with the same sound loaded and you jump form Player1 <> Player2.

for example:

Code: Pascal  [Select][+][-]
  1. var
  2. i : integer = 0;
  3. ...
  4. uos_CreatePlayer(0);
  5. uos_CreatePlayer(1);
  6. uos_AddIntoDevOut(0);
  7. uos_AddIntoDevOut(1);
  8. uos_AddFromFile(0,pchar(thesound));
  9. uos_AddFromFile(1,pchar(thesound));
  10.  
  11. uos_PlayNoFree(0);

And in Timer.onTimer:

Code: Pascal  [Select][+][-]
  1. ...
  2. if odd(i) then
  3. begin
  4. uos_PlayNoFree(1);
  5. uos_Stop(0);
  6. end else
  7. begin
  8. uos_PlayNoFree(0);
  9. uos_Stop(1);
  10. end;
  11.  
  12. inc(i);

Fre;D
« Last Edit: February 20, 2017, 09:03:42 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #5 on: February 20, 2017, 09:22:52 pm »
I understood. The timer is used for bpm control. As the user increases a value, it decreases the timer interval, and vice versa. Take a look:

Code: Pascal  [Select][+][-]
  1. Snare | 0 0 0 0    x 0 0 0    0 0 0 0    x 0 0 0
  2. -----
  3. Kick  | x 0 0 0    0 0 0 0    x 0 x 0    0 0 0 0
  4. -----
  5. Hat   | x 0 x 0    x 0 x 0    x 0 x 0    x 0 x 0
  6. -----
  7.  .
  8.  .
  9.  .

Each column is a OnTimer event. If one or more sounds are marked, they must be executed at the same time. So, as you suggested, I'd have to create two players for each line (one for kick, other for snare...), correct? Thanks!

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #6 on: February 20, 2017, 09:30:02 pm »
Quote
So, as you suggested, I'd have to create two players for each line (one for kick, other for snare...), correct?
Yes, IMHO, each line, for example the kick will have 2 players with same kick-sample, idem for each instrument.

But this, of course, only if you repeat the instrument, otherwise, one player is enough.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #7 on: February 20, 2017, 10:52:52 pm »
@Fred, unfortunately, what you suggested only works well when there is a longer delay between timer executions (lower bpm). The higher bpm is, more unsynchronized it gets. A possible hack would be to create multiple players, but the problem is when there are several sounds, with more beats and bars... Doesn't seem to be the right way to go.

Thanks for your attention.

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #8 on: February 20, 2017, 11:56:56 pm »
Quote
The higher bpm is, more unsynchronized it gets

I suppose this appends when sound1 is played after a "tick" and sound2 is not yet finished.

In that case, when the sound is still playing only one player should be used.

And at timer.ontime, only this:
Code: Pascal  [Select][+][-]
  1.  uos_Seek(0, input, 0)

Like metis explained about loops.

But for this, the length of each sound must >= of the timer interval (you may add silence).

Other thing, do you synchronize some graphic into the loop ?
Some widgetsets have a huge impact on latency.

A other solution if you need fast synchro is to use the synthesizer uos_AddFromSynth( ) to produce sound.

Fre;D

« Last Edit: February 21, 2017, 12:00:08 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #9 on: February 21, 2017, 01:28:16 am »
Even doing that, I'm still face the same problem. It seems that uos_PlayNoFree has a kind of restriction, which didn't happen creating a new player in each passage, using uos_Play.
I imagine it's not very complex what I'm looking for: calling a "play" function, and it automatically plays the same sound stored, canceling the previous execution. Thanks anyway.
« Last Edit: February 21, 2017, 01:30:12 am by fauri »

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #10 on: February 21, 2017, 12:39:23 pm »
Hello fauri.

I try it here and it works very fast.
But for this the buffer must be the smallest possible:.
FrameCount should be the smallest that your sound card accept.
You may try with 1024 as FrameCount (or less if it works).

Code: Pascal  [Select][+][-]
  1. uos_AddFromFile(PlayerIndex1, pchar(filename), -1,  -1 ,1024);
  2. uos_AddIntoDevOut(PlayerIndex1, -1, -1, -1, -1, -1, 1024);

[EDIT] By default, uos_AddFromFile(PlayerIndex, pchar(filename)) uses (65536 div channels) as FrameCount.
It is confortable for playing with DSPs but too big for fast synchro.
You should then change the default value (-1) into (1024).

Fre;D

« Last Edit: February 21, 2017, 06:38:32 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #11 on: February 21, 2017, 08:21:02 pm »
Unfortunately, it doesn't works, even using 3 players for each song (as buffers), with 128 of framecount. It keeps coming out of sync, with intervals of 100 - 125 miliseconds.

The stranger thing is that even creating a new player for each song (with the same id used) in every OnTimer execution, it was perfectly synchronized (with uos_Play). But, with uos_PlayNoFree, that mess happens. But it's probably not just a UOS problem, since I saw similary issue in tests with SDL and SDL Mixer.

But, using uos_Play, occurs a gradual increase in memory... It looks the function didn't actually free the player after the sound was stopped. I noticed this in the task manager (Windows 10, 64-bit). Maybe a bug?

Thanks for your attention e dedication, Fred.

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #12 on: February 21, 2017, 09:44:17 pm »
Hello fauri.

I am sorry and sad for you ;-(

Quote
But, with uos_PlayNoFree, that mess happens.
Ok, I will see what appends there.

Quote
But, using uos_Play, occurs a gradual increase in memory... It looks the function didn't actually free the player after the sound was stopped
Ok, I will jump into uos code and see what wrong (strange because I did not find any memory leaks).

Thanks to report it.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

fauri

  • New Member
  • *
  • Posts: 15
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #13 on: February 21, 2017, 10:10:15 pm »
Ok, I will jump into uos code and see what wrong (strange because I did not find any memory leaks).
I realized that when I was testing my beta software in a live performance. Creating a player in each OnTimer execution works perfectly, even with volume and effects... But, in a certain moment, it stopped... Looking into task manager, and the software was using 1,45GB (It's started with 23,8 MB).  :D

Cheers!

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: UOS: Store a sound in memory and only use uos_Play inside a OnTimer event
« Reply #14 on: February 21, 2017, 10:16:36 pm »
Quote
I realized that when I was testing my beta software in a live performance. Creating a player in each OnTimer execution works perfectly, even with volume and effects... But, in a certain moment, it stopped... Looking into task manager, and the software was using 1,45GB (It's started with 23,8 MB).  :D

Huh, indeed it is strange.
I just tested uos_SimplePlayer demo with Linux 64 bit and did not see any increase in memory.

I think you are using Windows, I will test it with wine.

When you close your application, did you use uos_unloadlib() + uos_free() ?

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

 

TinyPortal © 2005-2018