Author Topic: [Done]BASS_StreamPutFileData play sound will be many small noises  (Read 149 times)

qfsoft

  • Posts: 6
My native language is not English, the following are sentences translated using Google:
I get a lot of small sound clips from the web server. The data format of these clips is MP3. When I spliced and saved these sound clips to a file, the sounds sounded very continuous and perfect. But if I don't generate mp3 files, but directly use BASS_StreamPutFileData to play sound in BASS, although the sound sounds continuous, there will be many small noises, is there any way to avoid this? Thanks!
Here is some code:

 
Code: [Select]


         FLock.Enter;
         try
            got := Data.Size - iPos - 12;
            done:= 0;
            while true do
            begin
               Data.Position:= got + done;
               space := BASS_StreamGetFilePosition(Fhs, BASS_FILEPOS_END) - BASS_StreamGetFilePosition(Fhs, BASS_FILEPOS_BUFFER);
               if space>0 then
               begin
                 done:= done +  BASS_StreamPutFileData(Fhs, Data.Memory, got - done);
               end;
               ConsoleLog('got='+got.ToString+'  done='+done.ToString);
               if got=done then  break;
               Application.ProcessMessages;
            end;
            if BASS_ChannelIsActive(Fhs)=1 then sleep(100);
         finally
            FLock.Exit();
         end;
« Last Edit: 18 Jun '22 - 09:44 by qfsoft »

Ian @ un4seen

  • Administrator
  • Posts: 24495
It looks like the BASS_StreamPutFileData call's "buffer" parameter is always the same, ie. it isn't advancing, so each call will be repeating data. I'm not a Delphi user myself, but perhaps change it something like this:

Code: [Select]
                 done:= done +  BASS_StreamPutFileData(Fhs, Data.Memory + done, got - done);

I would also recommend checking the BASS_StreamPutFileData return value before adding it to "done", to make sure the call didn't fail (return -1).

qfsoft

  • Posts: 6
he movement of the data pointer is implemented here: Data.Position:= got + done;
I can understand the content of the voice played, so the pointer movement is correct, but the continuity of the voice is not perfect, there is a little noise

Ian @ un4seen

  • Administrator
  • Posts: 24495
he movement of the data pointer is implemented here: Data.Position:= got + done;

Does that definitely advance the Data.Memory value, ie. you can see it change? And if so, shouldn't it be set to just "done"? "got" and "done" will be the same at the end of the data, so: got + done = 2x got (or 2x done)

Are you also sure the following line is correct?

Code: [Select]
            got := Data.Size - iPos - 12;

Perhaps it's dropping some data? That would result in a discontinuity.

qfsoft

  • Posts: 6
This is indeed discarding some non-sound data, mainly some identifiers, I am sure this is the correct processing, because after I put these sound clips together and save them as mp3, the playback sound is very clear and perfect(Sound Format :audio-24khz-160kbitrate-mono-mp3)
Code: [Select]

procedure TForm1.sgcWebSocketClient1Binary(Connection: TsgcWSConnection;
  const Data: TMemoryStream);
var iPos,got,done,space:integer;
begin
  StrTempStream.Clear;
  StrTempStream.Position:= 0;
  StrTempStream.CopyFrom(Data,0);
  iPos:= pos('Path:audio',  StrTempStream.DataString );
  if Data.Size - iPos - 12 >0 then
  begin
    try
      begin
         FLock.Enter;
         try
            got := Data.Size - iPos - 12;
            done:= 0;
            while true do
            begin
               Data.Position:= got + done;
               space := BASS_StreamGetFilePosition(Fhs, BASS_FILEPOS_END) - BASS_StreamGetFilePosition(Fhs, BASS_FILEPOS_BUFFER);
               if space>0 then
               begin
                 done:= done +  BASS_StreamPutFileData(Fhs, Data.Memory, got - done);
               end;
               ConsoleLog('got='+got.ToString+'  done='+done.ToString);
               if got=done then  break;
               Application.ProcessMessages;
            end;
            if BASS_ChannelIsActive(Fhs)=1 then sleep(100);
         finally
            FLock.Exit();
         end;
      end;

      if IsReady and (Fhs>0) then
      begin
         BASS_channelplay(Fhs, false);
         IsReady:= false;
      end;
    finally

    end;
  end;
end;
« Last Edit: 17 Jun '22 - 18:33 by qfsoft »

qfsoft

  • Posts: 6
The effect of these two methods is the same. I also rewrote the code according to your suggestion. The test voice effect still has noise, which is the same as the effect of the old code.
Code: [Select]
done := done + BASS_StreamPutFileData(Fhs, Pointer( Longint( Data.Memory) + done),  got - done);
Code: [Select]
Data.Position:= got + done;
done:= done +  BASS_StreamPutFileData(Fhs, Data.Memory, got - done);

qfsoft

  • Posts: 6
I decided not to use the BASS_StreamCreateFileUser vs. BASS_StreamPutFileData scheme. Because the noise problem could not be solved for the time being, but soon I found another way to solve the problem: Since these sound data are AI voice data, there must be a pause in the middle of the sentence, so I searched for the silent data in the MP3 data frame. , and soon found the data tag "FFF3E4C400000003", so when I receive these data, I save all fragmented data in a complete data stream, and use a list to save the start position and end position of different sentences, when the list When the number of buffers in the memory is suitable, a timer event is triggered, and the playback memory stream is controlled in the timer event. This only needs to use the conventional method:
Code: [Select]
procedure TForm1.Timer1Timer(Sender: TObject);
var iLen,i:integer;
begin
    if Mp3treamFull=nil then exit;
    FLock.Enter;
    iLen:= Length(List);
    if iLen=0 then exit;
    if BASS_ChannelIsActive(Fhs)<> BASS_ACTIVE_PLAYING then
    begin
       for I := 0 to iLen-1 do
       begin
          if (List[i].start>-1) and (List[i].end>-1) and (not List[i].IsPlayed) then
          begin
             List[i].IsPlayed:= true;
             BASS_StreamFree(Fhs);
             if mem=nil then mem:= TMemoryStream.Create;
             mem.Clear;
             Mp3treamFull.Position:= List[i].start;
             mem.CopyFrom(Mp3treamFull, List[i].end-List[i].start);
             Fhs := BASS_StreamCreateFile(True, mem.Memory , 0, mem.Size, 0);
             BASS_ChannelPlay(Fhs, false);
             if (I = iLen-1) then Timer1.Enabled:= false;
             break;
          end;
       end;
    end;
    FLock.Exit();
    Application.ProcessMessages;
end;
now, you can hear clear sound, perfect, don't have to worry about too many other technical details, all manage the cache data by yourself.

Summarizing experience: BASS_StreamCreateFileUser and BASS_StreamPutFileData are based on data frame push streaming, and there are many technical difficulties. The solution I am using now is to synthesize the fragmented data frame into a sentence, cache the corresponding location information, and then play it with a timer
« Last Edit: 18 Jun '22 - 08:28 by qfsoft »

Ian @ un4seen

  • Administrator
  • Posts: 24495
This is indeed discarding some non-sound data, mainly some identifiers, I am sure this is the correct processing, because after I put these sound clips together and save them as mp3, the playback sound is very clear and perfect(Sound Format :audio-24khz-160kbitrate-mono-mp3)

I guess you didn't have the "while" loop when you saved the clips in the MP3 file? If so, it looks like that loop is where the problem is - my guess is still that it's the data pointer. As an example, it could look something like this in C/C++:

Code: [Select]
int PutFileData(HSTREAM handle, BYTE *data, int size)
{
int done = 0;
while (true) {
int r = BASS_StreamPutFileData(handle, data + done, size - done);
if (r == -1) break; // error
if (r > 0) {
done += r;
if (done == size) break;
} else
Sleep(50); // wait for space
}
return done;
}