Search code examples
delphidelphi-xe3oggbass

Am I loading this Music correctly with Bass.dll?


Based on Bass's documentation, I'm trying to load an ogg file with the code that follows:

var
  FFile : string;
  Music: HSAMPLE; 
  ch: HCHANNEL;
  OpenDialog1 : TOpenDialog;
begin
  Dynamic_Bass.Load_BASSDLL('Library/Bass.dll');
  Dynamic_Bass.BASS_Init(1,44000,Bass_DEVICE_SPEAKERS,0,nil);  
  OpenDialog1 := TOpenDialog.Create(nil);
  if not OpenDialog1.Execute then
    Exit;
  ffile := OpenDialog1.FileName;
  Music := BASS_SampleLoad(FALSE, PChar(ffile), 0, 0, 3, BASS_SAMPLE_OVER_POS);
  ch := BASS_SampleGetChannel(Music, False);
  BASS_ChannelSetAttribute(ch, BASS_ATTRIB_PAN, 0);
  BASS_ChannelSetAttribute(ch, BASS_ATTRIB_VOL, 1);
  BASS_ChannelPlay(ch, False);
  ShowMessage(IntToStr(BASS_ErrorGetCode));
end;

ShowMessage returns 5. Acording to documentation this is Handle error, what means that the error is in the music var. If I comment the lines below BASS_SampleLoad I get error 2. Means the file could not be loaded. So it is an ordinary OGG file. So my question: Am I doing something wrong?

Thanks in advance.


Solution

  • Your code seems to be correct, just make sure you check for errors on each call.

    Fixed code:

    var
      ffile : string;
      music: HSAMPLE; 
      ch: HCHANNEL;
      opendialog1 : topendialog;
    
    begin 
     if not Dynamic_Bass.Load_BASSDLL('Library/Bass.dll') then
      Exit;
     // change device to -1 which is the default device
     if Dynamic_Bass.BASS_Init(-1,44000,Bass_DEVICE_SPEAKERS,0,nil) then
      begin
       opendialog1 := topendialog.Create(nil);
       try
        if OpenDialog1.Execute then
         begin
          ffile := OpenDialog1.FileName;
          music := BASS_SampleLoad(FALSE, PChar(ffile), 0, 0, 3, BASS_SAMPLE_OVER_POS);
          if music <> 0 then
           begin
            ch := BASS_SampleGetChannel(music, False);
            if ch <> 0 then
             begin
              // omitted, see if the basics work   
              // BASS_ChannelSetAttribute(ch, BASS_ATTRIB_PAN, 0);
              // BASS_ChannelSetAttribute(ch, BASS_ATTRIB_VOL, 1);
              if not BASS_ChannelPlay(ch, False) then
               ShowMessage(inttostr(bass_errorgetcode));
             end
            else
             ShowMessage(inttostr(bass_errorgetcode));
           end
          else
           ShowMessage(inttostr(bass_errorgetcode));
         end;
       finally  
        OpenDialog1.Free;
       end;
      end
     else
      ShowMessage(inttostr(bass_errorgetcode));
    end;
    

    UPDATE

    I should have seen this sooner, your code fails because BASS_SampleLoad expects the filename in ANSI format, the documentation clearly mentions this, since you have Delphi XE3 and Strings are Unicode, you must supply the BASS_UNICODE flag to indicate this.

    so the Bass_SampleLoad line becomes:

    music := BASS_SampleLoad(FALSE, PChar(ffile), 0, 0, 3, BASS_SAMPLE_OVER_POS 
              or BASS_UNICODE);
    

    UPDATE2

    Per Sir Rufo's request: I added an exception based error checking routine to make the code cleaner and debugging more straightforward.

    function BASS_ErrorToString(BASS_ErrorCode : Integer) : String;
    
    begin
    
     case BASS_ErrorCode of :
      0: Result := 'BASS_OK';
      1: Result := 'BASS_ERROR_MEM';
      2: Result := 'BASS_ERROR_FILEOPEN';
      3: Result := 'BASS_ERROR_DRIVER';
      4: Result := 'BASS_ERROR_BUFLOST';
      5: Result := 'BASS_ERROR_HANDLE';
      6: Result := 'BASS_ERROR_FORMAT';
      7: Result := 'BASS_ERROR_POSITION';
      8: Result := 'BASS_ERROR_INIT';
      9: Result := 'BASS_ERROR_START';
      14: Result := 'BASS_ERROR_ALREADY';
      18: Result := 'BASS_ERROR_NOCHAN';
      19: Result := 'BASS_ERROR_ILLTYPE';
      20: Result := 'BASS_ERROR_ILLPARAM';
      21: Result := 'BASS_ERROR_NO3D';
      22: Result := 'BASS_ERROR_NOEAX';
      23: Result := 'BASS_ERROR_DEVICE';
      24: Result := 'BASS_ERROR_NOPLAY';
      25: Result := 'BASS_ERROR_FREQ';
      27: Result := 'BASS_ERROR_NOTFILE';
      29: Result := 'BASS_ERROR_NOHW';
      31: Result := 'BASS_ERROR_EMPTY';
      32: Result := 'BASS_ERROR_NONET';
      33: Result := 'BASS_ERROR_CREATE';
      34: Result := 'BASS_ERROR_NOFX';
      37: Result := 'BASS_ERROR_NOTAVAIL';
      38: Result := 'BASS_ERROR_DECODE';
      39: Result := 'BASS_ERROR_DX';
      40: Result := 'BASS_ERROR_TIMEOUT';
      41: Result := 'BASS_ERROR_FILEFORM';
      42: Result := 'BASS_ERROR_SPEAKER';
      43: Result := 'BASS_ERROR_VERSION';
      44: Result := 'BASS_ERROR_CODEC';
      45: Result := 'BASS_ERROR_ENDED';
      46: Result := 'BASS_ERROR_BUSY';
     else
      Result := 'BASS_ERROR_UNKNOWN';
     end;
    end;
    
    procedure BassResultCheck(ResultCode : Integer);
    begin
     if ResultCode = 0 then
      begin
       ResultCode := BASS_ErrorGetCode;
       raise Exception.CreateFmt('BASS error : %s(%d)', [BASS_ErrorToString(ResultCode), ResultCode]);
      end;
    end;
    
    procedure BassBoolCheck(const BoolResult : Boolean);
    begin
     BassResultCheck(Integer(BoolResult));
    end;
    
    procedure PlaySample(const SampleFilename : String);
    
    var
      Sample : HSAMPLE; 
      Channel: HCHANNEL;
    
    
    begin 
     if not Dynamic_Bass.Load_BASSDLL('Library/Bass.dll') then
      raise Exception.Create('Could not load BASS DLL');
     // change device to -1 which is the default device
     BassBoolCheck(Dynamic_Bass.BASS_Init(-1,44000,Bass_DEVICE_SPEAKERS,0,nil);
     Sample := BASS_SampleLoad(FALSE, PChar(SampleFilename), 0, 0, 3, BASS_SAMPLE_OVER_POS OR BASS_UNICODE);
     BassResultCheck(Sample);
     Channel := BASS_SampleGetChannel(Sample, False);
     BassResultCheck(Channel);
     BassBoolCheck(BASS_ChannelPlay(Channel, False));
    end;