19 Jun '13 - 07:30 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Support for AIFF files > 4 gb  (Read 2249 times)
The Mask
Posts: 97


« on: 29 Jun '10 - 21:55 »
Reply with quoteQuote

I have a AIFF file > 4 gb (12.3 gb exactly) with a playing time of 1:58 minutes (96000 hz 24 bit). Most of the tools I use will get the correct duration of the file (MediaInfo, SoundForge etc.) but Bass.dll gives a duration of 35 min which I think is because of the 4 gb limit.

I'm using decoding channels and when I use BASS_ChannelIsActive for the manual writing of the samples to file the output is only 35 min.

Is there a way arround the 4 gb limit?

Can bass read the duration from the numsampleframes field in the aiff header and take the file size in consideration with it. I know the aiff header is limited to unsigned 32 bit but the numsampleframes are correct in the header when the filesize > 4 gb, because you divide the filesize with (channels * (bitpersample/8)).

Does anyone know how to decode the whole 12.3 gb aiff file to wav with bass.dll?
Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #1 on: 30 Jun '10 - 14:40 »
Reply with quoteQuote

Please upload the 1st few KB of the file to have a look at here...

   ftp.un4seen.com/incoming/
Logged
The Mask
Posts: 97


« Reply #2 on: 30 Jun '10 - 19:14 »
Reply with quoteQuote

Hi Ian,

I uploaded a 512 kb Test.aif.header file.
Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #3 on: 1 Jul '10 - 16:27 »
Reply with quoteQuote

Thanks. Here's an update to try, which will use the "numsampleframes" value rather than the SSND chunk size so long as the low 32 bits match (I found a file where "numsampleframes" was inaccurate)...

   www.un4seen.com/stuff/bass.dll
Logged
The Mask
Posts: 97


« Reply #4 on: 1 Jul '10 - 20:00 »
Reply with quoteQuote

Thanks Ian  Wink

Works great.

One more question: Are there plans to implement support for reading W64 files (Sony Wave64)? I can create them with my own code but I don't now how to read them with Bass.dll.
Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #5 on: 2 Jul '10 - 14:12 »
Reply with quoteQuote

There are no immediate plans for W64 support (RF64 support is available as an alternative), but if you would like to add support for it in your app, you could parse the file and feed the sample data to a STREAMPROC. If you want, you could take it a step further and create an add-on Smiley
Logged
The Mask
Posts: 97


« Reply #6 on: 14 Jul '10 - 09:02 »
Reply with quoteQuote

Hi Ian,

I would like to create an add-on but do you also have a delphi version of the raw.c example in de add-on API. Because c++ is not my strongest thing  Wink.
Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #7 on: 14 Jul '10 - 16:49 »
Reply with quoteQuote

No, I'm afraid not. You could have a look at the BassWinamp source (which is in Delphi), but it may well increase the level of confusion Smiley

   www.un4seen.com/filez/1/BassWinamp-src.zip
Logged
The Mask
Posts: 97


« Reply #8 on: 15 Jul '10 - 23:23 »
Reply with quoteQuote

Ok, thanks, I will take a look at it.

I have now implemented your first suggestion with STREAMPROC but I can't figure out something. Almost everything works, only the conversion from 24 bit audio to 32 bit floats doesn't work.

What do I want to do. I always want the BASS_StreamCreate function to get floating point data from the STREAMPROC callback function. So in the STREAMPROC I read the raw audio after I read the W64 header in another function. The raw data that is read I will convert to 32 bit float to give it back to the BASS_ChannelGetData function. All conversions (except the 24 bit to float) are done correctly. Also the files that are created (8, 16 and 32 bit to float conversions) are correct with timing and filesize. So what am I doing wrong with the 24 to float conversion? Also the final output with the 24 to float conversion gives wrong channels in the final output. Here is some of my code:

type
  rWave64 = record
    HeaderSize : integer;
    Bitrate     : DWord;
    WavType     : TWavType;
    SampleRate : DWORD;        // default playback rate
    Channels   : DWORD;       // channels
    DataPos     : Int64;
  end;

  T24BitSample =  packed record
    a0 : Byte;
    a1 : Byte;
    a2 : ShortInt;
  end;

  PByteArray = ^TByteArray;
  TByteArray = array [0..255] of Byte;
  PSmallIntArray = ^TSmallIntArray;
  TSmallIntArray = array [0..255] of SmallInt;
  PInteger24Array = ^TInteger24Array;
  TInteger24Array = array[0..255] of T24BitSample;
  PIntegerArray = ^TIntegerArray;
  TIntegerArray = array[0..255] of integer;
  PFloatArray = ^TFloatArray;
  TFloatArray = array [0..255] of Single;

function Cvt24BitTo32(Sample : T24BitSample) : integer;
begin
  Result := Sample.a0 + (Sample.a1 shl 8) + (Sample.a2 shl 16);
end;



function ReadWave64(handle: DWord; buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
var
  Buf8 : PByteArray;
  Buf16 : PSmallIntArray;
  Buf24 : PInteger24Array;
  Buf32i : PIntegerArray;
  Buf32 : PFloatArray;
  c : DWORD;
  i : integer;
  NumSamples: integer;
begin
  Buf32 := PFloatArray(Buffer);

  case TBassDecoder(user).FWave64.Bitrate of
    8   : begin
            Buf8 := PByteArray(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf8^[0], Length); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div (TBassDecoder(user).FWave64.Bitrate div 8);
                for i := NumSamples -1 downto 0 do Buf32^[i] := (integer(Buf8^[i]) - 128) / 128;
                result := c * 32 div TBassDecoder(user).FWave64.Bitrate;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
    16  : begin
            Buf16 := PSmallIntArray(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf16^[0], Length); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div (TBassDecoder(user).FWave64.Bitrate div 8);
                for i := NumSamples -1 downto 0 do Buf32^[i] := Buf16^[i] / 32768;
                result := c * 32 div TBassDecoder(user).FWave64.Bitrate;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
    24  : begin
          Buf24 := PInteger24Array(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf24^[0], Length); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div (TBassDecoder(user).FWave64.Bitrate div 8);
                for i := NumSamples -1 downto 0 do Buf32^[i] := Cvt24BitTo32(Buf24^[i]) / 8388608;
                result := c * 32 div TBassDecoder(user).FWave64.Bitrate;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
    32  : begin
            if TBassDecoder(user).FWave64.WavType in [wtIEEEFloat, wtExtIEEEFloat] then
              begin
                c := TBassDecoder(user).FCustomStream.read(Buf32^[0], Length); // read the file into the buffer
                if c <> DWORD(-1) then  // check for EOF
                  begin
                    result := c;
                  end
                else
                  result := BASS_STREAMPROC_END;
              end
            else
              begin
            Buf32i := PIntegerArray(Buffer);
                c := TBassDecoder(user).FCustomStream.read(Buf32i^[0], Length); // read the file into the buffer
                if c <> DWORD(-1) then  // check for EOF
                  begin
                    // convert data to float!!
                    NumSamples := c div (TBassDecoder(user).FWave64.Bitrate div 8);
                    for i := 0 to NumSamples -1 do Buf32^[i] := Buf32i^[i] / 2147483648;
                    result := c;
                  end
                else
                  result := BASS_STREAMPROC_END;
              end;
          end;
  end;
end;


function TBassDecoder.Load(AFileName: String): Boolean;
begin
  Close;

  if (FLibrary = 0) then
  begin
    Result := False;
    Exit;
  end;

  FStream := BASS_StreamCreateFile(False, PWideChar(AFileName), 0, 0, BASS_STREAM_DECODE or BASS_SAMPLE_FLOAT or BASS_UNICODE);
  if (FStream = 0) then
  begin
    // check if it is a Wave64 file and fill Fwave64 with some header properties
    fIsItWave64 := IsWave64(AFileName);
   
    if fIsItWave64 then
      begin
      FStream := BASS_StreamCreate(FWave64.SampleRate, FWave64.Channels, BASS_STREAM_DECODE or BASS_SAMPLE_FLOAT, @ReadWave64, Self);
        if (FStream = 0) then
          begin
            Result := False;
          Exit;
        end;
      end;
  end;

  Result := True;
end;

procedure TBassDecoder.Close;
begin
  if FStream = 0
    then Exit;

  BASS_StreamFree(FStream);
  if FIsItWave64 then
    begin
      FCustomStream.Free;
      fWave64.HeaderSize := 0;
      fWave64.Bitrate := 0;
      fWave64.WavType := wtUnsupported;
      fWave64.SampleRate := 0;
      fWave64.Channels := 0;
      fWave64.DataPos := 0;
    end;
end;

function TBassDecoder.GetData(ABuffer: Pointer; ASize: Integer): integer;
begin
  Result := BASS_ChannelGetData(FStream, ABuffer, ASize);
end;

And here is a screen of the input file and output file (24 bit to float conversion):


Logged
Xire
Posts: 241


« Reply #9 on: 16 Jul '10 - 07:50 »
Reply with quoteQuote

Ok, thanks, I will take a look at it.

I have now implemented your first suggestion with STREAMPROC but I can't figure out something. Almost everything works, only the conversion from 24 bit audio to 32 bit floats doesn't work.

You're producing 32bit integers, not floats.
Divide the result by $80000000 and you'll get a float value.
« Last Edit: 16 Jul '10 - 07:55 by Xire » Logged
The Mask
Posts: 97


« Reply #10 on: 16 Jul '10 - 09:00 »
Reply with quoteQuote

Are you talking about the line:

for i := NumSamples -1 downto 0 do Buf32^[i] := Cvt24BitTo32(Buf24^[i]) / 8388608;

so it should be

for i := NumSamples -1 downto 0 do Buf32^[i] := (Cvt24BitTo32(Buf24^[i]) / 8388608) / $80000000;

Logged
Xire
Posts: 241


« Reply #11 on: 16 Jul '10 - 12:49 »
Reply with quoteQuote

Oops, I missed that you're already dividing Wink

Try to divide by $80000000 instead of 8388608 (which is $800000).
Logged
The Mask
Posts: 97


« Reply #12 on: 16 Jul '10 - 13:07 »
Reply with quoteQuote

Oops, I missed that you're already dividing Wink

Try to divide by $80000000 instead of 8388608 (which is $800000).


But I thought that you have to do that when you convert 32 bit integer to 32 bit float (and not 24 bit integer to float) like I have done in the code:

for i := 0 to NumSamples -1 do Buf32^[i] := Buf32i^[i] / 2147483648;

Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #13 on: 16 Jul '10 - 15:35 »
Reply with quoteQuote

            c := TBassDecoder(user).FCustomStream.read(Buf8^[0], Length); // read the file into the buffer
...
            c := TBassDecoder(user).FCustomStream.read(Buf16^[0], Length); // read the file into the buffer
...
            c := TBassDecoder(user).FCustomStream.read(Buf24^[0], Length); // read the file into the buffer

That code looks a bit troublesome. The problem is that it isn't considering that it will need less source data to produce the requested amount ("Length" bytes) of output data, due to the lower resolution of the source data, eg. 16-bit data will double in size once converted to 32-bit. The code should probably look something like this...

  Buf32 := PFloatArray(Buffer);
  NumSamples := Length div 4

  case TBassDecoder(user).FWave64.Bitrate of
    8   : begin
            Buf8 := PByteArray(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf8^[0], NumSamples); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c;
                for i := NumSamples -1 downto 0 do Buf32^[i] := (integer(Buf8^[i]) - 128) / 128;
                result := NumSamples * 4;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
    16  : begin
            Buf16 := PSmallIntArray(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf16^[0], NumSamples * 2); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div 2;
                for i := NumSamples -1 downto 0 do Buf32^[i] := Buf16^[i] / 32768;
                result := NumSamples * 4;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
    24  : begin
          Buf24 := PInteger24Array(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf24^[0], NumSamples * 3); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div 3;
                for i := NumSamples -1 downto 0 do Buf32^[i] := Cvt24BitTo32(Buf24^[i]) / 8388608;
                result := NumSamples * 4;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
Logged
The Mask
Posts: 97


« Reply #14 on: 16 Jul '10 - 15:53 »
Reply with quoteQuote

So for conversion from 32 bit integer to 32 bit float I don't have to do anything?

I will try it.
Logged
Ian @ un4seen
Administrator
Posts: 15363


« Reply #15 on: 16 Jul '10 - 17:21 »
Reply with quoteQuote

No, you would have to do something for 32-bit integer data too Smiley

            Buf32i := PIntegerArray(Buffer);
            c := TBassDecoder(user).FCustomStream.read(Buf32^[0], NumSamples * 4); // read the file into the buffer
            if c <> DWORD(-1) then  // check for EOF
              begin
                // convert data to float!!
                NumSamples := c div 4;
                for i := NumSamples -1 downto 0 do Buf32^[i] := Buf32i^[i] / 2147483648;
                result := NumSamples * 4;
              end
            else
              result := BASS_STREAMPROC_END;
          end;
Logged
The Mask
Posts: 97


« Reply #16 on: 16 Jul '10 - 19:41 »
Reply with quoteQuote

Thanks a lot Ian,

That did it.  Smiley
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines