New Simple recorder with MP3 recording support

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

New Simple recorder with MP3 recording support

trustfm
This post was updated on .
Hello to the forum i made a new demo for uos that can record in MP3 and OGG/vorbis using libsndfile library with quality settings
https://trim.uk.to/my-simple-recorder.zip
The mp3 recording is only VBR.
I could not make CBR AVR possible
the command SFC_SET_BITRATE_MODE  seems to not work
but
SFC_SET_VBR_ENCODING_QUALITY
SFC_SET_COMPRESSION_LEVEL  
work for both OGG and MP3


**********************

The new function added

function Tuos_Player.AddIntoFile (Filenamepath: PChar; SampleRate: CDouble;
                                 Channels: cint32; SampleFormat: cint32; FramesCount: cint32;
                                 FileFormat: cint32; vbr_encoding_quality:ctypes.cdouble; compression_level:ctypes.cdouble): cint32;
// Add an Output into audio wav file with custom parameters
// FileName : filename of saved audio wav file
// SampleRate : default: -1 (44100)
// Channels : default: -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// SampleFormat : default: -1 (2:Int16) ( 1:Int32, 2:Int16)
// FramesCount : default: -1 (= 4096)
// FileFormat : default: -1 (wav) (0:wav, 1:pcm, 2:custom, 3:ogg, 4:mp3);
//vbr_encoding_quality:ctypes.cdouble ; c
//compression_level:ctypes.cdouble
//  result : Output Index in array  -1 = error
// example : OutputIndex1 := AddIntoFile (edit5.Text,-1,-1, 0, -1, -1);
var
  x: cint32;
  wChunkSize: cint32;
  wFileSize: cint32;
  IDwav: array[0..3] of char;
  Header: Tuos_WaveHeaderChunk;
  {$IF DEFINED (sndfile)}
  sfInfo: TSF_INFO;
  {$endif}

  //TrustFm
  bitrate_mode: ctypes.cint;
  res_sf_command: ctypes.cint;


begin




  result := -1;
  x := 0;
  SetLength (StreamOut, Length (StreamOut) + 1);
  StreamOut[Length (StreamOut) - 1] := Tuos_OutStream.Create ();
  x := Length (StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;
  StreamOut[x].FileBuffer.ERROR := 0;
  StreamOut[x].Data.Filename := filenamepath;
  if (FileFormat = -1) or (FileFormat = 0) then
    StreamOut[x].FileBuffer.FileFormat := 0
  else StreamOut[x].FileBuffer.FileFormat := FileFormat;

  FillChar (StreamOut[x].FileBuffer, sizeof (StreamOut[x].FileBuffer), 0);

  result := x;

  if (Channels = -1) then
    StreamOut[x].FileBuffer.wChannels := 2
  else
    StreamOut[x].FileBuffer.wChannels := Channels;

  StreamOut[x].Data.Channels := StreamOut[x].FileBuffer.wChannels;

  if FramesCount = -1 then StreamOut[x].Data.Wantframes := 65536 Div StreamOut[x].Data.Channels
  else
    StreamOut[x].Data.Wantframes := FramesCount;

  SetLength (StreamOut[x].Data.Buffer, StreamOut[x].Data.Wantframes*StreamOut[x].Data.Channels);

  if (SampleFormat = -1) or (SampleFormat = 2) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 16;
      StreamOut[x].Data.SampleFormat := 2;
    end;

  if (SampleFormat = 1) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 32;
      StreamOut[x].Data.SampleFormat := 1;
    end;

  if (SampleFormat = 0) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 32;
      StreamOut[x].Data.SampleFormat := 0;
    end;

  if SampleRate = -1 then
    StreamOut[x].FileBuffer.wSamplesPerSec := 44100 //8000 11025 16000  22050 was 44100
  else
    StreamOut[x].FileBuffer.wSamplesPerSec := roundmath (samplerate);

  StreamOut[x].Data.Samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
  StreamOut[x].LoopProc := Nil;

  if fileformat = 3 then begin
      // ogg file
  {$IF DEFINED (sndfile)}



      StreamOut[x].FileBuffer.FileFormat := 3;
      StreamOut[x].Data.TypePut := 6;
      sfInfo.format :=  SF_FORMAT_OGG Or SF_FORMAT_VORBIS;  //SF_FORMAT_OGG Or SF_FORMAT_VORBIS;
      sfInfo.channels := StreamOut[x].Data.Channels;
      sfInfo.frames :=  streamOut[x].Data.Wantframes;
      sfinfo.samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
      sfinfo.seekable := 0; //seekable was 0
      StreamOut[x].Data.Enabled := true;

      StreamOut[x].Data.HandleSt := sf_open (pchar(FileNamepath), SFM_WRITE, sfInfo);


      //TrustFm
      //https://github.com/libsndfile/libsndfile/issues/788

      //Set the Variable Bit Rate encoding quality.
      //The encoding quality value should be between 0.0 (lowest quality) and 1.0 (highest quality).
      //Currently this command is only implemented for FLAC and Ogg/Vorbis files.
      //It has no effect on un-compressed file formats.
      //vbr_encoding_quality:=0.1;
      res_sf_command:=-1;
      res_sf_command := sf_command_pointer(StreamOut[x].Data.HandleSt, SFC_SET_VBR_ENCODING_QUALITY, @vbr_encoding_quality, sizeof(vbr_encoding_quality) );
      if res_sf_command = SF_TRUE  then begin
      //  compression_level:=1.0;
      end else if  res_sf_command = SF_FALSE then begin
      //  compression_level:=1.0;
      end;


      //Set the compression level.
      //The compression level should be between 0.0 (minimum compression level) and 1.0 (highest compression level).
      //Currently this command is only implemented for FLAC and Ogg/Vorbis files.
      //It has no effect on uncompressed file formats.
      //compression_level:=1.0;

      {
      Compression Level 0.0->500kb/s
      Compression Level 0.1->320kb/s
      Compression Level 0.2->256kb/s
      Compression Level 0.3->224kb/s
      Compression Level 0.4->192kb/s
      Compression Level 0.5->160kb/s
      Compression Level 0.6->128kb/s
      Compression Level 0.7->112kb/s
      Compression Level 0.8->96kb/s
      Compression Level 0.9->80kb/s
      Compression Level 1.0->64kb/s
      }

      res_sf_command:=-1;
      res_sf_command := sf_command_pointer(StreamOut[x].Data.HandleSt, SFC_SET_COMPRESSION_LEVEL, @compression_level, sizeof(compression_level) );
      if res_sf_command = SF_TRUE  then begin //SF_TRUE
      //  compression_level:=1.0;
      end else if  res_sf_command = SF_FALSE  then begin //SF_FALSE
      //  compression_level:=1.0;
      end;


  {$endif}

  end else if fileformat = 4 then begin //by trustfm

      // mp3 file
  {$IF DEFINED (sndfile)}
      StreamOut[x].FileBuffer.FileFormat := 4;
      StreamOut[x].Data.TypePut := 6;
      sfInfo.format := SF_FORMAT_MPEG Or SF_FORMAT_MPEG_LAYER_III;
      sfInfo.channels := StreamOut[x].Data.Channels;
      sfInfo.frames :=  streamOut[x].Data.Wantframes;
      SFinfo.samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
      SFinfo.seekable := 0;
      StreamOut[x].Data.Enabled := True;
      StreamOut[x].Data.HandleSt := sf_open (pchar (FileNamepath), SFM_WRITE, sfInfo);


      {
      https://github.com/libsndfile/libsndfile/issues/1008
      Sample rate mode can be changed using
      SFC_SET_BITRATE_MODE
      Default is variable (constant quality),
      but average and constant bitrate are also supported for MP3.

      Sample rate value can be changed indirectly using
      SFC_SET_COMPRESSION_LEVEL
      (https://github.com/libsndfile/libsndfile/blob/c81375f070f3c6764969a738eacded64f53a076e/docs/command.md#sfc_set_compression_level).
      (The comment in the documentation about only supporting Voribs/Flac should be updated)

      For setting the compression, pass a value between
      0.0 (max bitrate, min compression) and
      1.0 (min bitrate, max compression).
      How the value is interpreted depends on the bitrate mode.

      For VBR, it translates to lame_set_VBR_qaulity().
      0.0 -> 0.0 (highest quality), 1.0 -> 10.0 (lowest quality)

      I'd recommend using VBR and just tweaking the quality as required.
      This is similar to other lossy formats.

      For ABR and CBR, it translates to
      [0.0, 1.0] to the bitrate values of [highest bitrate possible, lowest bitrate possible].
      The possible bitrates depending on the MPEG spec version.

      For 32000Hz and higher (MPEG 1.0), [0.0, 1.0] -> [320kbps, 32kbps]
      For 16000Hz up to 32000Hz (MPEG 2.0), [0.0, 1.0] -> [160kbps, 8kbps]
      For under 16000Hz (MPEG "2.5") [0.0, 1.0] -> [64kbps, 8kbps]

      (See https://github.com/libsndfile/libsndfile/blob/master/src/mpeg_l3_encode.c#L194)

      You can retrieve the current bitrate using sf_get_byterate(), multiplying the result by 8.

      }

      {
      //This setting does not work currently it is always SF_BITRATE_MODE_VARIABLE
      //Set bitrate mode. SFC_GET_BITRATE_MODE was added for MP3 support
      //The bitrate mode is one of:
      //SF_BITRATE_MODE_CONSTANT 800 Constant bitrate.
      //SF_BITRATE_MODE_AVERAGE 801 Average bitrate.
      //SF_BITRATE_MODE_VARIABLE 802 Variable bitrate.
      bitrate_mode:=SF_BITRATE_MODE_VARIABLE;
      res_sf_command:=-1;
      res_sf_command := sf_command_pointer(StreamOut[x].Data.HandleSt, SFC_SET_BITRATE_MODE, @bitrate_mode, SizeOf(bitrate_mode) );
      if res_sf_command = SF_TRUE  then begin //SF_TRUE
        compression_level:=1.0;
      end else if  res_sf_command = SF_FALSE  then begin //SF_FALSE
        compression_level:=1.0;
      end;
      }


      //Set the Variable Bit Rate encoding quality.
      //The encoding quality value should be between 0.0 (lowest quality) and 1.0 (highest quality).
      //Currently this command is only implemented for FLAC and Ogg/Vorbis files.
      //It has no effect on un-compressed file formats.
      //vbr_encoding_quality:=1.0;
      res_sf_command:=-1;
      res_sf_command := sf_command_pointer(StreamOut[x].Data.HandleSt, SFC_SET_VBR_ENCODING_QUALITY, @vbr_encoding_quality, sizeof(vbr_encoding_quality) );
      if res_sf_command = SF_TRUE  then begin
        //compression_level:=1.0;
      end else if  res_sf_command = SF_FALSE then begin
        //compression_level:=1.0;
      end;


      //Set the compression level.
      //The compression level should be between 0.0 (minimum compression level) and 1.0 (highest compression level).
      //Currently this command is only implemented for MP3 , FLAC and Ogg/Vorbis files.
      //It has no effect on uncompressed file formats.
      // [0.0, 1.0] -> [320kbps, 32kbps]
      {
      Compression Level 0.0->320kb/s
      Compression Level 0.1->256kb/s
      Compression Level 0.2->200kb/s
      Compression Level 0.3->180kb/s
      Compression Level 0.4->165kb/s
      Compression Level 0.5->128kb/s
      Compression Level 0.6->112kb/s
      Compression Level 0.7->100kb/s
      Compression Level 0.8->96kb/s
      Compression Level 0.9->80kb/s
      Compression Level 1.0->64kb/s
      }
      //compression_level:=0.9;
      res_sf_command:=-1;
      res_sf_command := sf_command_pointer(StreamOut[x].Data.HandleSt, SFC_SET_COMPRESSION_LEVEL, @compression_level, sizeof(compression_level) );
      if res_sf_command = SF_TRUE  then begin //SF_TRUE
        //compression_level:=1.0;
      end else if  res_sf_command = SF_FALSE  then begin //SF_FALSE
        //compression_level:=1.0;
      end;


  {$endif}

    end else begin
      // wav file
      StreamOut[x].FileBuffer.Data := TFileStream.Create (filenamepath,fmCreate);
      StreamOut[x].FileBuffer.Data.Seek (0, soFromBeginning);
      StreamOut[x].Data.TypePut := 0;
      IDwav := 'RIFF';
      StreamOut[x].FileBuffer.Data.WriteBuffer (IDwav, 4);
      wFileSize := 0;
      StreamOut[x].FileBuffer.Data.WriteBuffer (wFileSize, 4);
      IDwav := 'WAVE';
      StreamOut[x].FileBuffer.Data.WriteBuffer (IDwav, 4);
      IDwav := 'fmt ';
      StreamOut[x].FileBuffer.Data.WriteBuffer (IDwav, 4);
      wChunkSize := SizeOf (Header);
      StreamOut[x].FileBuffer.Data.WriteBuffer (wChunkSize, 4);

      case SampleFormat of
        0:   Header.wFormatTag      := 3;
        else Header.wFormatTag      := 1;
      end;

      //Header.wFormatTag      := 1;
      Header.wChannels       := StreamOut[x].FileBuffer.wChannels;
      Header.wSamplesPerSec  := StreamOut[x].FileBuffer.wSamplesPerSec;
      Header.wBitsPerSample  := StreamOut[x].FileBuffer.wBitsPerSample;
      Header.wBlockAlign     := StreamOut[x].FileBuffer.wChannels * Header.wBitsPerSample Div 8;
      Header.wAvgBytesPerSec := StreamOut[x].FileBuffer.wSamplesPerSec * Header.wBlockAlign;
      Header.wcbSize         := 0;

      StreamOut[x].FileBuffer.Data.WriteBuffer (Header, SizeOf (Header));
      IDwav := 'data';
      StreamOut[x].FileBuffer.Data.WriteBuffer (IDwav, 4);
      wChunkSize := 0;
      StreamOut[x].FileBuffer.Data.WriteBuffer (wChunkSize, 4);
      StreamOut[x].Data.Enabled := True;

    end;
end;
Reply | Threaded
Open this post in threaded view
|

Re: New Simple recorder with MP3 recording support

fredvs
Administrator
Hello.

WoW

I will study it deeply.
Do you have a github account?
If so, please do a pull-request.
Reply | Threaded
Open this post in threaded view
|

Re: New Simple recorder with MP3 recording support

trustfm
Hello unfortunately right now i do not have a github .

I can confirm that the Broadcaster Demo published here
http://uos-forum.108.s1.nabble.com/Installing-IceCast-audio-web-server-td184.html#a1274
also works with the mp3 produced by this demo ,
so we can record and then broadcast in mp3 and ogg/vorbis tested on caster.fm server
Reply | Threaded
Open this post in threaded view
|

Re: New Simple recorder with MP3 recording support

fredvs
Administrator
Very nice.

If you do not like github, there are mirrors on gitlab and codeberg and you may do pull-request also there:
https://gitlab.com/fredvs/uos
https://codeberg.org/fredvs/uos