Author Topic: next zero volume point  (Read 226 times)

mikeanders

  • Guest
next zero volume point
« on: 29 Jul '17 - 18:26 »
Goto next zero volume point. As in, the stream position will then be a part of waveform where L and R channels amplitude is, say, -40db or lower. Each button press moves to next 0 volume from current pos. Can this be done?

Ian @ un4seen

  • Administrator
  • Posts: 20210
Re: next zero volume point
« Reply #1 on: 31 Jul '17 - 17:56 »
You could achieve that by also having a "decoding channel" (using BASS_STREAM_DECODE flag) for the same file that's being played, which you can use to scan for the next near zero sample when seeking. For example, something like this:

Code: [Select]
playstream = BASS_StreamCreateFile(false, filename, 0, 0, BASS_SAMPLE_FLOAT); // create playback stream
scanstream = BASS_StreamCreateFile(false, filename, 0, 0, BASS_SAMPLE_FLOAT|BASS_STREAM_DECODE); // create scanning stream

...

bool SeekToNextQuietSample()
{
QWORD pos = BASS_ChannelGetPosition(playstream, BASS_POS_BYTE); // get playback position
BASS_ChannelSetPosition(scanstream, pos, BASS_POS_BYTE); // set the scanner there (a bit ahead may be better)
while (1) {
float data[4000];
int r = BASS_ChannelGetData(scanstream, data, sizeof(data)); // get data from the scanner
if (r <= 0) break; // done
for (int a; a < r/sizeof(float)/2; a++) {
if (fabs(data[a*2]) < 0.01 && fabs(data[a*2+1]) < 0.01) { // left and right below -40 dB
BASS_ChannelSetPosition(playstream, pos + a*sizeof(float)*2, BASS_POS_BYTE); // set playback there
return true;
}
}
pos += r;
}
return false; // failed to find near zero sample
}

Please see the documentation for details on the mentioned functions.

mikeanders

  • Guest
Re: next zero volume point
« Reply #2 on: 4 Aug '17 - 17:33 »
Thanks.  I am a bit confused, though:

1.

if (fabs(data[a*2]) < 0.01 && fabs(data[a*2+1]) < 0.01) { // left and right below -40 dB

Shouldn't that mean that the BASS_DATA_FFT_INDIVIDUAL be used?  If not, how is the 4 byte float data used?

I assume 4 bytes = mono 32 bit.  If that's so, why do we need 2 checks for left and right?

So this should be correct?

float data[4000];
BASS_ChannelGetData(scanstream, data, sizeof(data));

data[0] = LeftRight Mono Sample 1
data[1] = LeftRight Mono Sample 2.


2. Why is using 32 bit float preferable? This could be done as easily using 16 bit non float?


mikeanders

  • Guest
Re: next zero volume point
« Reply #3 on: 6 Aug '17 - 17:38 »
OK, I understand now- that the FFT flags are just that...  totally different data.  But something is still wrong here.

Even when I use this:

Code: [Select]
procedure getamp;
var
  Bpos : longword;
  Bdata : array[0..1] of Single;
begin

  Bpos := BASS_ChannelGetPosition(BassStreamFX, BASS_POS_BYTE);
  BASS_ChannelSetPosition(BassStream, Bpos, BASS_POS_BYTE);

    BASS_ChannelGetData(BassStream, @Bdata[0], sizeof(BData));
    BASS_ChannelGetData(BassStream, @Bdata[1], sizeof(BData));

    showmessage(floattostr(bdata[0]));
    showmessage(floattostr(bdata[1]));
end;

The resulting amplitudes for L R are wrong. I can check in Adobe Audition at the amplitudes and they aren't matching (for example -0.01 is way too far away from -40db. I have set Bass_sample_float on both BassStream and BassStreamFX - and it's reporting 8 bytes per sample.

mikeanders

  • Guest
Re: next zero volume point
« Reply #4 on: 6 Aug '17 - 17:40 »
Sorry, the code above should read

BASS_ChannelGetData(BStream, @Bdata[0], sizeof(BData));

only.

mikeanders

  • Guest
Re: next zero volume point
« Reply #5 on: 6 Aug '17 - 17:49 »
It was my fault.  Still, my attempt at setting the correct point is failing.  I'll have a proper look at it and get back to you if I can't find out why.


mikeanders

  • Guest
Re: next zero volume point
« Reply #6 on: 8 Aug '17 - 01:28 »
I have amended this for use with Delphi and corrected for the "-1" issue.  Thanks, Ian.

// When using 32 bit floating point sample, or flag: Bass_Sample_Float. If not using Bass_FX, you will still need to use decoding channel, as per Ian's post.
Code: [Select]
Function SeekToNextQuietSample:Boolean;
var
  Bpos : Int64;
  Bdata : array[0..8191] of Single;
  i : LongInt;
  r: LongWord; // This is the Delphi version of Dword. BASS_ChannelGetData returns an unsigned 32 bit value.

begin
Result:= False;

  BASS_ChannelSetPosition(BStreamFX, BASS_ChannelGetPosition(BStreamFX, BASS_POS_BYTE) + 8, BASS_POS_BYTE);

  Bpos := BASS_ChannelGetPosition(BStreamFX, BASS_POS_BYTE);
  BASS_ChannelSetPosition(BStream, Bpos, BASS_POS_BYTE);

  while true do
  begin
  r:= BASS_ChannelGetData(BStream, @Bdata[0], Sizeof(BData));

    if (r = $FFFFFFFF) or (r = 0) then // error is unsigned maximum value, NOT -1.
    begin
    Showmessage ('No Zero point found');
    exit;
    end;

      for i := 0 to (r div 8) -1 do
      if (abs(bdata[i * 2]) < 0.001) and (abs(bdata[(i * 2) + 1]) < 0.001) then  // Make sure L/R amplitudes are very small.
      begin
      BASS_ChannelSetPosition(BStreamFX, Bpos + (i*8), BASS_POS_BYTE);
      Result:= True;
      exit;
      end;
     
  Bpos:= Bpos + r;
  end;

end;

mikeanders

  • Guest
Re: next zero volume point
« Reply #7 on: 8 Aug '17 - 01:30 »
I don't think Bpos needs to be Int64 though :P  I accidentally left that in.  Should prob be LongWord since that seems to exceed the max value for file data?

Chris

  • Posts: 1804
Re: next zero volume point
« Reply #8 on: 8 Aug '17 - 12:48 »
int64 is correct because
the pos value in Bass_ChannelSetPosition  btw the The Return of Bass_ChannelGetPosition is a QWord (int64)