Hello to the forum !
I managed to make an encoder that can also encode only a portion of input file (wav ogg opus mp3) The procedure has three operations *CutEnd *CutStart *Encode The demo works with libsndfile library and portaudio The only problem that i do not know why works like this is the following portion I had to add a multiplier in the case of encoding ogg or mp3 The multiplier is equal to 1 on the wav encoding ![]() if RadioButtonWav.Checked then begin outformatst := '.wav'; outformat := 0; multiplier:=1; end else if RadioButtonOgg.Checked then begin outformatst := '.ogg'; outformat := 3; multiplier:=numchan; end else if RadioButtonMp3.Checked then begin outformatst := '.mp3'; outformat := 4; multiplier:=numchan; end; //FramesCount : default: -1 (65536) 64chunks*1024 - max 32*multikier InputIndex1 := uos_AddFromFile(PlayerIndex1, PChar(songIn),-1,sampleformat,32*1024*multiplier); numchan := uos_InputGetChannels(PlayerIndex1, InputIndex1); samplerate:=uos_InputGetSampleRate(PlayerIndex1, InputIndex1); if RadioButtonWav.Checked then begin uos_AddIntoFile(PlayerIndex1, PChar('out_final'+outformatst),samplerate,numchan,sampleformat,32*1024, outformat); //-1 end else begin //ogg or mp3 uos_AddIntoFile(PlayerIndex1, PChar('out_final'+outformatst),samplerate,numchan,sampleformat,32*1024, outformat,FloatSpinEditVBREncoding.Value,FloatSpinEditCompressionLevel.Value); //-1 end; https://trim.uk.to/my-simple-encoder.zip The file is large since has demo audios Hope someone explain the multiplier issue Thanks |
Administrator
|
This post was updated on .
Hello.
Is it working with your "multiplier" workaround? In uos it uses also a "ratio" for libmpg123 to be compatible with code used for libsndfile. One needs the length of the buffer, the other the length of the frame (size of the buffer div channels). And libsndfile uses the code of libmpg123 to decode/encode mp3 format (see their readme.txt). Decoding of mp3 is recent in libsndfile, so it seems that they did not adapt it to use the same way as previous other format, like ogg, flac, wav (and now in trunk opus). Sorry I can not explain that "multiplier" but if it works for you, better to be happy and maybe somebody will explain why one day. |
Hello yes the demo is fully functional
If the multiplier is removed the generated tracks (mp3,ogg) are twice long and say track 1 and not track2 Notice that the multiplier is applied only at InputIndex1 := uos_AddFromFile(PlayerIndex1, PChar(songIn),-1,sampleformat,32*1024*multiplier); and NOT at uos_AddIntoFile(PlayerIndex1, PChar('out_final'+outformatst),samplerate,numchan,sampleformat,32*1024, outformat,FloatSpinEditVBREncoding.Value,FloatSpinEditCompressionLevel.Value); //-1 Now i am thinking how to do a join of two files ![]() |
Administrator
|
But you are using only libsndfile to decode ogg and mp3 files, dont you?
So uos threat the input files the same way depending of the library used, no matter if it is a ogg, flac, wav and mp3 if only libsndfile is used. Now if libsndfile needs different parameters depending of the format, it is sad (but it seems to be the case). |
yes this might be the case
|
In reply to this post by trustfm
Hello !
Here is a function that can join two or more audiofiles into one single file based on this example https://github.com/libsndfile/libsndfile/blob/ea9ff560b4c2086c2f1cae3f02287768a0de4673/programs/sndfile-concat.c The joined files must have the same samplerate and number of channels ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// uos_libsndfile_aux.pas //Made By TrustFm //https://github.com/libsndfile/libsndfile/blob/ea9ff560b4c2086c2f1cae3f02287768a0de4673/programs/sndfile-concat.c unit uos_libsndfile_aux; {$mode objfpc}{$H+} interface uses classes,sysutils, uos, uos_flat, uos_libsndfile, Dialogs, Buttons, Forms, ctypes; const BUFFER_LEN = 65536; function JoinAudioFiles(var FilesInStringList:TStringList; FileOutString:string; StartObj: TObject=nil; AbortObj: TObject=nil):string; implementation //////////////////////////////////////////////////// //////////////////////////////////////////////////// { static void concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels) static int data [BUFFER_LEN] ; //declare an array of BUFFER_LEN integers int frames, readcount ; frames = BUFFER_LEN / channels ; readcount = frames ; sf_seek (wfile, 0, SEEK_END) ; while (readcount > 0) { readcount = (int) sf_readf_int (rofile, data, frames) ; sf_writef_int (wfile, data, readcount) ; } ; return ; /* concat_data_int */ } procedure concat_data_int(wfile: TSNDFILE_HANDLE; rofile: TSNDFILE_HANDLE; channels: ctypes.cint; AbortObj: TObject=nil); var //buffer: array of ctypes.cint; //data: ctypes.pcint; buffer: TDArFloat; frames,readcount: Tuos_count_t; begin //SetLength(buffer, BUFFER_LEN); //data := @buffer; SetLength(buffer, BUFFER_LEN); frames := BUFFER_LEN div channels; readcount:= frames; sf_seek (wfile, 0, SEEK_END) ; while (readcount > 0) do begin readcount := sf_readf_int(rofile, @buffer[0], frames); //data[0] sf_writef_int(wfile, @buffer[0], readcount); if AbortObj is TBitBtn then begin if (not TBitBtn(AbortObj).Enabled) then begin break; end; end; end; end; { static void concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels) { static double data [BUFFER_LEN] ; int frames, readcount ; frames = BUFFER_LEN / channels ; readcount = frames ; sf_seek (wfile, 0, SEEK_END) ; while (readcount > 0) { readcount = (int) sf_readf_double (rofile, data, frames) ; sf_writef_double (wfile, data, readcount) ; } ; return ; } /* concat_data_fp */ } procedure concat_data_fp(wfile: TSNDFILE_HANDLE; rofile: TSNDFILE_HANDLE; channels: ctypes.cint; AbortObj: TObject=nil); var //buffer: array of ctypes.cdouble; //data : ctypes.pcdouble; buffer: TDArFloat; frames,readcount: Tuos_count_t; begin //SetLength(buffer, BUFFER_LEN); //data := @buffer; SetLength(buffer, BUFFER_LEN); frames := BUFFER_LEN div channels; readcount:= frames; sf_seek (wfile, 0, SEEK_END) ; while (readcount > 0) do begin readcount := sf_readf_double(rofile, @buffer[0], frames); sf_writef_double(wfile, @buffer[0], readcount); if (not TBitBtn(AbortObj).Enabled) then begin break; end; end; end; { int main (int argc, char *argv []) { const char *progname, *outfilename ; SNDFILE *outfile, **infiles ; SF_INFO sfinfo_out, sfinfo_in ; void (*func) (SNDFILE*, SNDFILE*, int) ; int k ; progname = program_name (argv [0]) ; if (argc < 4) usage_exit (progname) ; argv ++ ; argc -- ; argc -- ; outfilename = argv [argc] ; if ((infiles = calloc (argc, sizeof (SNDFILE*))) == NULL) { printf ("\nError : Malloc failed.\n\n") ; exit (1) ; } ; memset (&sfinfo_in, 0, sizeof (sfinfo_in)) ; if ((infiles [0] = sf_open (argv [0], SFM_READ, &sfinfo_in)) == NULL) { printf ("\nError : failed to open file '%s'.\n\n", argv [0]) ; exit (1) ; } ; sfinfo_out = sfinfo_in ; for (k = 1 ; k < argc ; k++) { if ((infiles [k] = sf_open (argv [k], SFM_READ, &sfinfo_in)) == NULL) { printf ("\nError : failed to open file '%s'.\n\n", argv [k]) ; exit (1) ; } ; if (sfinfo_in.channels != sfinfo_out.channels) { printf ("\nError : File '%s' has %d channels (should have %d).\n\n", argv [k], sfinfo_in.channels, sfinfo_out.channels) ; exit (1) ; } ; } ; if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo_out)) == NULL) { printf ("\nError : Not able to open input file %s.\n", outfilename) ; puts (sf_strerror (NULL)) ; exit (1) ; } ; if ((sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE || (sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) func = concat_data_fp ; else func = concat_data_int ; for (k = 0 ; k < argc ; k++) { func (outfile, infiles [k], sfinfo_out.channels) ; sf_close (infiles [k]) ; } ; sf_close (outfile) ; free (infiles) ; return 0 ; } /* main */ } function JoinAudioFiles(var FilesInStringList:TStringList; FileOutString:string; StartObj: TObject=nil; AbortObj: TObject=nil):string; var k:integer; infiles: array of TSNDFILE_HANDLE; outfile: TSNDFILE_HANDLE; sfinfo_in, sfinfo_out : TSF_INFO; begin SetLength(infiles, FilesInStringList.Count-1); result:=''; infiles[0] := sf_open (FilesInStringList[0], SFM_READ, sfinfo_in); if infiles[0]=nil then begin result:='Error: failed to open file 1'; end else begin // infiles[0] opened sfinfo_out:=sfinfo_in; for k:=1 to FilesInStringList.Count-1 do begin infiles[k] := sf_open(FilesInStringList[k], SFM_READ, sfinfo_in); if infiles[k]=nil then begin result:='Error: failed to open file ' + IntToStr(k+1); break; end else begin if (sfinfo_in.channels <> sfinfo_out.channels) then begin result:='Error: Chanels missmatch at file ' + IntToStr(k+1); break; end; end; end; //for if result = '' then begin outfile := sf_open (FileOutString, SFM_WRITE, sfinfo_out); if outfile=nil then begin result:='Error : failed to create the out file'; end else begin //outfile opened successfully --> everything is ok if StartObj is TBitBtn then begin TBitBtn(StartObj).Enabled:=false; end; if AbortObj is TBitBtn then begin TBitBtn(AbortObj).Enabled:=true; end; for k:=0 to FilesInStringList.Count-1 do begin if StartObj is TBitBtn then begin TBitBtn(StartObj).Caption:='Joining ' + IntToStr(k+1) + '/' + IntToStr(FilesInStringList.Count); end; if AbortObj is TBitBtn then begin if (not TBitBtn(AbortObj).Enabled) then begin break; end; end; sleep(10); Application.Processmessages; if ( (sfinfo_out.format and SF_FORMAT_SUBMASK) = SF_FORMAT_DOUBLE ) or ( (sfinfo_out.format and SF_FORMAT_SUBMASK) = SF_FORMAT_FLOAT ) then begin concat_data_fp(outfile, infiles[k], sfinfo_out.channels,AbortObj) ; end else begin concat_data_int(outfile, infiles[k], sfinfo_out.channels,AbortObj) ; end; sf_close(infiles[k]) ; end; //for k if StartObj is TBitBtn then begin TBitBtn(StartObj).Caption:='Join Audio Files'; TBitBtn(StartObj).Enabled:=true; end; if AbortObj is TBitBtn then begin TBitBtn(AbortObj).Enabled:=false; end; end; sf_close (outfile) ; end; end; //infile1 end; end. ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// usage procedure TFormMain.BitBtnJoinAudioFilesClick(Sender: TObject); var InputFileList : TStringList; error:string; begin InputFileList := TStringList.Create; InputFileList.Add('input.mp3'); InputFileList.Add('input.ogg'); InputFileList.Add('input2.mp3'); error:=JoinAudioFiles(InputFileList,'out.mp3',BitBtnJoinAudioFiles,BitBtnJoinAudioFilesAbort); if error<>'' then begin ShowMessage(error); end; InputFileList.Free; end; procedure TFormMain.BitBtnJoinAudioFilesAbortClick(Sender: TObject); begin BitBtnJoinAudioFilesAbort.Enabled:= not BitBtnJoinAudioFilesAbort.Enabled; if not BitBtnJoinAudioFilesAbort.Enabled then begin ShowMessage('aborted'); BitBtnJoinAudioFiles.Enabled:=true; end; end; |
Small request . Would be nice to have at the AddFromFile function a starting delay . Would be useful at the multiinput example
![]() |
Administrator
|
Hello.
Sorry for late answer, I am super busy... Please for request, use https://github.com/fredvs/uos/issues or better do a pull-request https://github.com/fredvs/uos/pulls |
Free forum by Nabble | Edit this page |