Recording a network stream in blocks of x minutes

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

Recording a network stream in blocks of x minutes

msavigo1
Hello,

let's say I want to break up the recordings into blocks of x minutes.
I could use the following code and use a uos_Stop(PlayerIndex); after x minutes. Then do the same thing again.
But it takes a while to start a new recording and i would loose some input.

  uos_LoadLib(PChar(PortAudioPath), nil, PChar(Mpg123Path), nil, nil, nil);

  PlayerIndex := 0;
  uos_CreatePlayer(PlayerIndex);
  InputIndex := uos_AddFromURL(PlayerIndex, PChar(URL), -1, -1, -1, -1, True);
  OutputIndex := uos_AddIntoDevOut(PlayerIndex);

  uos_OutputAddDSPVolume(PlayerIndex, OutputIndex, 1, 1);
  uos_OutputSetDSPVolume(PlayerIndex, OutputIndex, 1, 1, True);

  uos_AddIntoFile(PlayerIndex, PChar(Filename));

  uos_Play(PlayerIndex);

What would be the best way to break up a continuous recodring into several wave files?
Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
Hello.

> But it takes a while to start a new recording and i would loose some input.

Maybe use 2 players, like in uos_morseTL demo, switching form player1 to player2 ?

You first run rec-player1, prepare rec-player2 while player 1 is recording.
When rec-player1 stop, run rec-player2 (and re-prepare rec-player1 for next rec),
When rec-player2 stop, run rec-player21(and re-prepare rec-player2 for next rec),... etc.

Fre;D



Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
Re-hello.

> ..., prepare player2 while player1 is recording.
I mean load all and pause player2.

> ... run rec-player2 (and re-prepare rec-player1 for next rec),
I mean resume player2.

Fre;D
Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

msavigo1
Hello,

doing so the second player will save a wav file that starts long befor the first player stops (when uos_AddFromURL was called). See code below.

Is where a way to append the recorded data to a TMemoryStream for each new block?
So the player could play the stream continuously while creating a new TMemoryStream for each new block.
If a TMemoryStream is completed it could be written to a wav file.


procedure TForm1.btStartClick(Sender: TObject);
var
  URL: string;
  Filename1: string;
  Filename2: string;
  Filename3: string;
  Mpg123Path: string;
  PortAudioPath: string;
begin
  URL := 'http://mp3.harmonyfm.de/harmonyfm/hqlivestream.mp3';
  Filename1 := application.Location + PathDelim + 'Recording_1.wav';
  Filename2 := application.Location + PathDelim + 'Recording_2.wav';
  Filename3 := application.Location + PathDelim + 'Recording_3.wav';

  {$IFDEF Windows}
    {$if defined(cpu64)}
  PortAudioPath := application.Location + 'lib\Windows\64bit\LibPortaudio-64.dll';
  Mpg123Path := application.Location + 'lib\Windows\64bit\LibMpg123-64.dll';
    {$else}
  PortAudioPath := application.Location + 'lib\Windows\32bit\LibPortaudio-32.dll';
  Mpg123Path := application.Location + 'lib\Windows\32bit\LibMpg123-32.dll';
    {$endif}
  {$ENDIF}

  {$if defined(cpu64) and defined(linux) }
  PortAudioPath := application.Location + 'lib/Linux/64bit/LibPortaudio-64.so';
  Mpg123Path := application.Location + 'lib/Linux/64bit/LibMpg123-64.so';
  {$ENDIF}
  {$if defined(cpu86) and defined(linux)}
  PortAudioPath := application.Location + 'lib/Linux/32bit/LibPortaudio-32.so';
  Mpg123Path := application.Location + 'lib/Linux/32bit/LibMpg123-32.so';
  {$ENDIF}

  uos_LoadLib(PChar(PortAudioPath), nil, PChar(Mpg123Path), nil, nil, nil);

  // Prepair 1. recording
  uos_CreatePlayer(0);
  InputIndex := uos_AddFromURL(0, PChar(URL), -1, -1, -1, -1, True);
  uos_AddIntoFile(0, PChar(Filename1));
  uos_PlayPaused(0);

  // Prepair 2. recording
  uos_CreatePlayer(1);
  InputIndex := uos_AddFromURL(1, PChar(URL), -1, -1, -1, -1, True);
  uos_AddIntoFile(1, PChar(Filename2));
  uos_PlayPaused(1);

  // Wait 10 seconds
  SysUtils.sleep(10000);

  // Start 1. recording for a while
  uos_RePlay(0);
  SysUtils.sleep(30000);

  // Stop 1. recording
  uos_Stop(0);

  // Start 2. recording and...
  uos_RePlay(1);
  // ...prepair 3. recording
  uos_CreatePlayer(0);
  InputIndex := uos_AddFromURL(0, PChar(URL), -1, -1, -1, -1, True);
  uos_AddIntoFile(0, PChar(Filename3));
  uos_PlayPaused(0);

  // Continue 2. recording for a while
  SysUtils.sleep(15000);

  // Stop all recordings
  uos_Stop(0);
  uos_Stop(1);
end;
Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
> doing so the second player will save a wav file that starts long befor the first player stops (when uos_AddFromURL was called).

Sorry, I do not understand.

In your code you do:

 // Start 1. recording for a while
  uos_RePlay(0);
  SysUtils.sleep(30000);

  // Stop 1. recording
  uos_Stop(0);

  // Start 2. recording and...
  uos_RePlay(1);
  // ...prepair 3. recording
  uos_CreatePlayer(0);
  InputIndex := uos_AddFromURL(0, PChar(URL), -1, -1, -1, -1, True);
  uos_AddIntoFile(0, PChar(Filename3));
  uos_PlayPaused(0);

.............

How could it be possible  "the second player will save a wav file that starts long befor the first player stops?
If it is the case (but I doubt) maybe you may use a player  EndProc  (In EndProc ---> uos_RePlay(1)), then prepare player0 (after some sleep for example).

Fre;D

Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
In reply to this post by msavigo1
> Is where a way to append the recorded data to a TMemoryStream for each new block?

Ha, you will use always the the same URL and record some blocks into file.
(I was thinking that you want a kind of URL-zapping).

If so, I would only use one PlayerURL an 2 memory streams TMem1/TMem2.

With uos_LoopProcIn(PlayerURL, InputIndex, @ProcBlock);

ProcBlock() will add the buffer of PlayerURL into TMem1/TMem2.

With a check when to save TMem1 into file and use TMem2 to store the new block (and switch from TMem1/TMem2) .

About how to use the uos_loop methods, please take a look at SimplePlayer demo (how to do custom DSP, like play-reverse).

Fre;D
Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
This post was updated on .
In reply to this post by msavigo1
Re-hello.

Here pseudo code how I would do it:

var
begintime, intervaltime :TTime ;
AMemorystream : TMemorystream ; // maybe only one stream would be fast enough.
...

AMemorystream := TMemoryStream.Create;
begintime := now;
intervaltime := atime; // define what you want
...

uos_CreatePlayer(PlayerURL);
...
uos_InputAddDSP(PlayerURL, InputIndex1, nil, @BlockCheck, nil, nil); // add this
...
uos_Play(PlayerIndex1);
....

function BlockCheck(var Data: TuosF_Data; var fft: TuosF_FFT): TDArFloat;
  var
  rat: integer = 1;
  begin

 case Data.SampleFormat of
  0: rat := 2 ;
  1: rat := 2 ;
  2: rat := 1 ;
  end;

 AMemorystream.WriteBuffer(Data.Buffer[0],  Data.channels * Data.outframes * rat);

if   now - begintime > intervaltime then
 begin
   uos_MemStream2Wavfile(Filename, AMemorystream, 16 * rat , Data.channels, Data.samplerate);
   begintime := now;
   // free buffer of AMemorystream if wanted.
end;

 Result := Data.Buffer; // nothing was done to original buffer

  end;

------------------------

PS: To use uos_MemStream2Wavfile(...) you will need last commit of uos.

Fre;D
Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

msavigo1
Thank you for the pseudo code and the new method. Now everything works as expected.

I added the channels to get the right recoding speed:
AMemorystream.WriteBuffer(Data.Buffer[0], Data.channels * Data.outframes * rat);

Great work ;-)


Reply | Threaded
Open this post in threaded view
|

Re: Recording a network stream in blocks of x minutes

fredvs
Administrator
> I added the channels to get the right recoding speed

Oops, indeed, it was needed.

> Now everything works as expected.

Ha, great and have fun.

Fre;D