aboutsummaryrefslogblamecommitdiffstats
path: root/Game/Code/Classes/UAudioPlayback_Bass.pas
blob: 87ff183dfbcbdb75f1e3774610e160d00435d12e (plain) (tree)
































                         














                                                     




















































































                                                                             






















































                                                      










































































































































                                                                                                                                         







                                                          


















































































































































































                                                                                           
unit UAudioPlayback_Bass;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}


uses Classes,
     {$IFDEF win32}
     windows,
     {$ENDIF}
     SysUtils,
     bass,
     ULog,
     UMusic;

implementation

uses
     {$IFDEF LAZARUS}
     lclintf,
     {$ENDIF}
     URecord,
     UIni,
     UMain,
     UCommon,
     UThemes;

type
  TBassOutputStream = class(TAudioPlaybackStream)
    private
      Handle: HSTREAM;
    public
      constructor Create(); overload;
      constructor Create(stream: HSTREAM); overload;

      procedure Play();                     override;
      procedure Pause();                    override;
      procedure Stop();                     override;
      procedure Close();                    override;
      function GetLoop(): boolean;          override;
      procedure SetLoop(Enabled: boolean);  override;
      function GetLength(): real;           override;
      function GetStatus(): TStreamStatus;  override;
  end;

type
  TAudioPlayback_Bass = class( TInterfacedObject, IAudioPlayback)
    private
      MusicStream:        HSTREAM;
      
      StartSoundStream:   HSTREAM;
      BackSoundStream:    HSTREAM;
      SwooshSoundStream:  HSTREAM;
      ChangeSoundStream:  HSTREAM;
      OptionSoundStream:  HSTREAM;
      ClickSoundStream:   HSTREAM;
      DrumSoundStream:    HSTREAM;
      HihatSoundStream:   HSTREAM;
      ClapSoundStream:    HSTREAM;
      ShuffleSoundStream: HSTREAM;

      //Custom Sounds
      CustomSounds: array of TCustomSoundEntry;
      Loaded:   boolean;
      Loop:     boolean;

    public
      function  GetName: String;

      {IAudioOutput interface}

      procedure InitializePlayback;
      procedure SetVolume(Volume: integer);
      procedure SetMusicVolume(Volume: integer);
      procedure SetLoop(Enabled: boolean);

      function Open(Name: string): boolean; // true if succeed
      
      procedure Rewind;
      procedure Play;
      procedure Pause; //Pause Mod
      procedure Stop;
      procedure Close;
      function Finished: boolean;
      function Length: real;
      function GetPosition: real;
      procedure SetPosition(Time: real);

      procedure PlayStart;
      procedure PlayBack;
      procedure PlaySwoosh;
      procedure PlayChange;
      procedure PlayOption;
      procedure PlayClick;
      procedure PlayDrum;
      procedure PlayHihat;
      procedure PlayClap;
      procedure PlayShuffle;
      procedure StopShuffle;

      function LoadSoundFromFile(var stream: HSTREAM; Name: string): boolean;

      //Equalizer
      function GetFFTData: TFFTData;

      // Interface for Visualizer
      function GetPCMData(var data: TPCMData): Cardinal;

      //Custom Sounds
      function LoadCustomSound(const Filename: String): Cardinal;
      procedure PlayCustomSound(const Index: Cardinal );
  end;

var
  singleton_AudioPlaybackBass : IAudioPlayback;


constructor TBassOutputStream.Create();
begin
  inherited;
end;

constructor TBassOutputStream.Create(stream: HSTREAM);
begin
  Create();
  Handle := stream;
end;

procedure TBassOutputStream.Play();
begin
  BASS_ChannelPlay(Handle, True);
end;

procedure TBassOutputStream.Pause();
begin
  //if (Loaded) then
  BASS_ChannelPause(Handle);
end;

procedure TBassOutputStream.Stop();
begin
  BASS_ChannelStop(Handle);
end;

procedure TBassOutputStream.Close();
begin
  Bass_StreamFree(Handle);
end;

function TBassOutputStream.GetLoop(): boolean;
begin
  // TODO
  result := false;
end;

procedure TBassOutputStream.SetLoop(Enabled: boolean);
begin
  // TODO
end;

function TBassOutputStream.GetLength(): real;
var
  bytes:    integer;
begin
  bytes  := BASS_ChannelGetLength(Handle);
  Result := BASS_ChannelBytes2Seconds(Handle, bytes);
end;

function TBassOutputStream.GetStatus(): TStreamStatus;
var
  state: DWORD;
begin
  state := BASS_ChannelIsActive(Handle);
  case state of
    BASS_ACTIVE_PLAYING:
      result := sPlaying;
    BASS_ACTIVE_PAUSED:
      result := sPaused;
    else
      result := sStopped;
  end;
end;


function  TAudioPlayback_Bass.GetName: String;
begin
  result := 'BASS_Playback';
end;

procedure TAudioPlayback_Bass.InitializePlayback;
var
  Pet:  integer;
  S:    integer;
begin
//  Log.BenchmarkStart(4);
//  Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize');

  Loaded := false;
  Loop   := false;

  if not BASS_Init(1, 44100, 0, 0, nil) then
  begin
    Log.LogError('Could not initialize BASS', 'Error');
    Exit;
  end;

//  Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4);

  // config playing buffer
//  BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10);
//  BASS_SetConfig(BASS_CONFIG_BUFFER, 100);

//  Log.LogStatus('Loading Sounds', 'Music Initialize');

//  Log.BenchmarkStart(4);
  LoadSoundFromFile(StartSoundStream,  SoundPath + 'Common Start.mp3');
  LoadSoundFromFile(BackSoundStream,   SoundPath + 'Common Back.mp3');
  LoadSoundFromFile(SwooshSoundStream, SoundPath + 'menu swoosh.mp3');
  LoadSoundFromFile(ChangeSoundStream, SoundPath + 'select music change music 50.mp3');
  LoadSoundFromFile(OptionSoundStream, SoundPath + 'option change col.mp3');
  LoadSoundFromFile(ClickSoundStream,  SoundPath + 'rimshot022b.mp3');

//  LoadSoundFromFile(DrumSoundStream,   SoundPath + 'bassdrumhard076b.mp3');
//  LoadSoundFromFile(HihatSoundStream,  SoundPath + 'hihatclosed068b.mp3');
//  LoadSoundFromFile(ClapSoundStream,   SoundPath + 'claps050b.mp3');

//  LoadSoundFromFile(ShuffleSoundStream, SoundPath + 'Shuffle.mp3');

//  Log.BenchmarkEnd(4);
//  Log.LogBenchmark('--> Loading Sounds', 4);
end;

procedure TAudioPlayback_Bass.SetVolume(Volume: integer);
begin
  //Old Sets Wave Volume
  //BASS_SetVolume(Volume);
  //New: Sets Volume only for this Application

  BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume);
  BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume);
  BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume);
end;

procedure TAudioPlayback_Bass.SetMusicVolume(Volume: Integer);
begin
  //Max Volume Prevention
  if Volume > 100 then
    Volume := 100;

  if Volume < 0 then
    Volume := 0;

  //Set Volume
  BASS_ChannelSetAttributes (MusicStream, -1, Volume, -101);
end;

procedure TAudioPlayback_Bass.SetLoop(Enabled: boolean);
begin
  Loop := Enabled;
end;

function TAudioPlayback_Bass.Open(Name: string): boolean;
begin
  Loaded := false;
  if FileExists(Name) then
  begin
    MusicStream := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0);

    Loaded := true;
    //Set Max Volume
    SetMusicVolume (100);
  end;

  Result := Loaded;
end;

procedure TAudioPlayback_Bass.Rewind;
begin
  if Loaded then begin
  end;
end;

procedure TAudioPlayback_Bass.SetPosition(Time: real);
var
  bytes:    integer;
begin
  bytes := BASS_ChannelSeconds2Bytes(MusicStream, Time);
  BASS_ChannelSetPosition(MusicStream, bytes);
end;

procedure TAudioPlayback_Bass.Play;
begin
  if Loaded then
  begin
    if Loop then
      BASS_ChannelPlay(MusicStream, True); // start from beginning... actually bass itself does not loop, nor does this TAudio_bass Class

    BASS_ChannelPlay(MusicStream, False); // for setting position before playing
  end;
end;

procedure TAudioPlayback_Bass.Pause; //Pause Mod
begin
  if Loaded then begin
    BASS_ChannelPause(MusicStream); // Pauses Song
  end;
end;

procedure TAudioPlayback_Bass.Stop;
begin
  Bass_ChannelStop(MusicStream);
end;

procedure TAudioPlayback_Bass.Close;
begin
  Bass_StreamFree(MusicStream);
end;

function TAudioPlayback_Bass.Length: real;
var
  bytes:    integer;
begin
  bytes  := BASS_ChannelGetLength(MusicStream);
  Result := BASS_ChannelBytes2Seconds(MusicStream, bytes);
end;

function TAudioPlayback_Bass.getPosition: real;
var
  bytes:    integer;
begin
  bytes  := BASS_ChannelGetPosition(MusicStream);
  Result := BASS_ChannelBytes2Seconds(MusicStream, bytes);
end;

function TAudioPlayback_Bass.Finished: boolean;
begin
  Result := false;

  if BASS_ChannelIsActive(MusicStream) = BASS_ACTIVE_STOPPED then
  begin
    Result := true;
  end;
end;

procedure TAudioPlayback_Bass.PlayStart;
begin
  BASS_ChannelPlay(StartSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayBack;
begin
  BASS_ChannelPlay(BackSoundStream, True);// then
end;

procedure TAudioPlayback_Bass.PlaySwoosh;
begin
  BASS_ChannelPlay(SwooshSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayChange;
begin
  BASS_ChannelPlay(ChangeSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayOption;
begin
  BASS_ChannelPlay(OptionSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayClick;
begin
  BASS_ChannelPlay(ClickSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayDrum;
begin
  BASS_ChannelPlay(DrumSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayHihat;
begin
  BASS_ChannelPlay(HihatSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayClap;
begin
  BASS_ChannelPlay(ClapSoundStream, True);
end;

procedure TAudioPlayback_Bass.PlayShuffle;
begin
  BASS_ChannelPlay(ShuffleSoundStream, True);
end;

procedure TAudioPlayback_Bass.StopShuffle;
begin
  BASS_ChannelStop(ShuffleSoundStream);
end;

function TAudioPlayback_Bass.LoadSoundFromFile(var stream: HSTREAM; Name: string): boolean;
var
  L: Integer;
begin
  if FileExists(Name) then
  begin
    Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadSoundFromFile');
    try
      stream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0);

      //Add CustomSound
      L := High(CustomSounds) + 1;
      SetLength (CustomSounds, L + 1);
      CustomSounds[L].Filename := Name;
      CustomSounds[L].Stream := TBassOutputStream.Create(stream);
    except
      Log.LogError('Failed to open using BASS', 'LoadSoundFromFile');
    end;
  end
  else
  begin
    Log.LogError('Sound not found: "' + Name + '"', 'LoadSoundFromFile');
    exit;
  end;
end;

//Equalizer
function TAudioPlayback_Bass.GetFFTData: TFFTData;
var
  Data: TFFTData;
begin
  //Get Channel Data Mono and 256 Values
  BASS_ChannelGetData(MusicStream, @Result, BASS_DATA_FFT512);
end;

{*
 * Copies interleaved PCM 16bit uint (maybe fake) stereo samples into data.
 * Returns the number of frames (= stereo/mono sample)
 *}
function TAudioPlayback_Bass.GetPCMData(var data: TPCMData): Cardinal;
var
  info: BASS_CHANNELINFO;
  nBytes: DWORD;
begin
  //Get Channel Data Mono and 256 Values
  BASS_ChannelGetInfo(MusicStream, info);
  ZeroMemory(@data, sizeof(TPCMData));
  
  if (info.chans = 1) then
  begin
    // mono file -> add stereo channel
    {
    nBytes := BASS_ChannelGetData(Bass, @data[0], samples*sizeof(Smallint));
    // interleave data
    //CopyMemory(@data[1], @data[0], samples*sizeof(Smallint));
    }
    result := 0;
  end
  else
  begin
    // stereo file
    nBytes := BASS_ChannelGetData(MusicStream, @data, sizeof(TPCMData));
  end;
  if(nBytes <= 0) then
    result := 0
  else
    result := nBytes div sizeof(TPCMStereoSample);
end;

function TAudioPlayback_Bass.LoadCustomSound(const Filename: String): Cardinal;
var
  S: hStream;
  I: Integer;
  F: String;
begin
  //Search for Sound in already loaded Sounds
  F := UpperCase(SoundPath + FileName);
  For I := 0 to High(CustomSounds) do
  begin
    if (UpperCase(CustomSounds[I].Filename) = F) then
    begin
      Result := I;
      Exit;
    end;
  end;

  if LoadSoundFromFile(S, SoundPath + Filename) then
    Result := High(CustomSounds)
  else
    Result := 0;
end;

procedure TAudioPlayback_Bass.PlayCustomSound(const Index: Cardinal );
begin
  if Index <= High(CustomSounds) then
  with CustomSounds[Index].Stream as TBassOutputStream do
  begin
    BASS_ChannelPlay(Handle, True);
  end;
end;


initialization
  singleton_AudioPlaybackBass := TAudioPlayback_Bass.create();
  AudioManager.add( singleton_AudioPlaybackBass );

finalization
  AudioManager.Remove( singleton_AudioPlaybackBass );

end.