unit UMusic; interface {$IFDEF FPC} {$MODE Delphi} {$ENDIF} {$I switches.inc} uses Classes; type TNoteType = (ntFreestyle, ntNormal, ntGolden); PLine = ^TLine; TLine = record Start: integer; Lyric: string; LyricWidth: real; End_: integer; BaseNote: integer; HighNote: integer; IlNut: integer; // (TODO: Il = tone, Nut(a) = Note) TotalNotes: integer; LastLine: boolean; Note: array of record Color: integer; Start: integer; Length: integer; Tone: integer; // full range tone Text: string; NoteType: TNoteType; end; end; ALine = array of TLine; // (TODO: rename to TLineArray) // (TCzesci = TSentences) TCzesci changed to TLines because TSentences exist elseware in incompatible form TLines = record Current: integer; // for drawing of current line High: integer; Number: integer; Resolution: integer; NotesGAP: integer; ScoreValue: integer; Line: ALine; end; // (TODO: rename TCzas to something like T(Line/Sentence)Time/TLinePosition/TLineState) // (Czas = time) TLineState = record // all that concerns the current frames OldBeat: integer; // previous discovered beat CurrentBeat: integer; MidBeat: real; // like CurrentBeat // now we use this for super synchronization! // only used when analyzing voice OldBeatD: integer; // previous discovered beat CurrentBeatD: integer; MidBeatD: real; // like CurrentBeatD FracBeatD: real; // fractional part of MidBeatD // we use this for audible clicks OldBeatC: integer; // previous discovered beat CurrentBeatC: integer; MidBeatC: real; // like CurrentBeatC FracBeatC: real; // fractional part of MidBeatC OldLine: integer; // previous displayed sentence CurrentTime: real; TotalTime: real; end; const FFTSize = 512; // size of FFT data (output: FFTSize/2 values) type TFFTData = array[0..(FFTSize div 2)-1] of Single; type TPCMStereoSample = array[0..1] of SmallInt; TPCMData = array[0..511] of TPCMStereoSample; type TStreamStatus = (ssStopped, ssPlaying, ssPaused, ssBlocked, ssUnknown); const StreamStatusStr: array[TStreamStatus] of string = ('Stopped', 'Playing', 'Paused', 'Blocked', 'Unknown'); type TAudioSampleFormat = ( asfU8, asfS8, // unsigned/signed 8 bits asfU16LSB, asfS16LSB, // unsigned/signed 16 bits (endianness: LSB) asfU16MSB, asfS16MSB, // unsigned/signed 16 bits (endianness: MSB) asfU16, asfS16, // unsigned/signed 16 bits (endianness: System) asfS24, // signed 24 bits (endianness: System) asfS32, // signed 32 bits (endianness: System) asfFloat // float ); const // Size of one sample (one channel only) in bytes AudioSampleSize: array[TAudioSampleFormat] of integer = ( 1, 1, // asfU8, asfS8 2, 2, // asfU16LSB, asfS16LSB 2, 2, // asfU16MSB, asfS16MSB 2, 2, // asfU16, asfS16 3, // asfS24 4, // asfS32 4 // asfFloat ); type TAudioFormatInfo = class public Channels : byte; SampleRate : double; Format : TAudioSampleFormat; FrameSize : integer; // calculated on construction constructor Create(Channels: byte; SampleRate: double; Format: TAudioSampleFormat); end; type TAudioProcessingStream = class public procedure Close(); virtual; abstract; end; TAudioPlaybackStream = class(TAudioProcessingStream) protected function GetLoop(): boolean; virtual; abstract; procedure SetLoop(Enabled: boolean); virtual; abstract; function GetLength(): real; virtual; abstract; function GetStatus(): TStreamStatus; virtual; abstract; function GetVolume(): integer; virtual; abstract; procedure SetVolume(volume: integer); virtual; abstract; public procedure Play(); virtual; abstract; procedure Pause(); virtual; abstract; procedure Stop(); virtual; abstract; property Loop: boolean READ GetLoop WRITE SetLoop; property Length: real READ GetLength; property Status: TStreamStatus READ GetStatus; property Volume: integer READ GetVolume WRITE SetVolume; end; (* TAudioMixerStream = class(TAudioProcessingStream) procedure AddStream(stream: TAudioProcessingStream); procedure RemoveStream(stream: TAudioProcessingStream); procedure SetMasterVolume(volume: cardinal); function GetMasterVolume(): cardinal; procedure SetStreamVolume(stream: TAudioProcessingStream; volume: cardinal); function GetStreamVolume(stream: TAudioProcessingStream): cardinal; end; *) TAudioDecodeStream = class(TAudioProcessingStream) protected function GetLength(): real; virtual; abstract; function GetPosition(): real; virtual; abstract; procedure SetPosition(Time: real); virtual; abstract; function IsEOF(): boolean; virtual; abstract; public function ReadData(Buffer: PChar; BufSize: integer): integer; virtual; abstract; function GetAudioFormatInfo(): TAudioFormatInfo; virtual; abstract; property Length: real READ GetLength; property Position: real READ GetPosition WRITE SetPosition; property EOF: boolean READ IsEOF; end; type IGenericPlayback = Interface ['{63A5EBC3-3F4D-4F23-8DFB-B5165FCE33DD}'] function GetName: String; function Open(const Filename: string): boolean; // true if succeed procedure Close; procedure Play; procedure Pause; procedure Stop; procedure SetPosition(Time: real); function GetPosition: real; property Position : real READ GetPosition WRITE SetPosition; end; IVideoPlayback = Interface( IGenericPlayback ) ['{3574C40C-28AE-4201-B3D1-3D1F0759B131}'] procedure init(); procedure GetFrame(Time: Extended); // WANT TO RENAME THESE TO BE MORE GENERIC procedure DrawGL(Screen: integer); // WANT TO RENAME THESE TO BE MORE GENERIC end; IVideoVisualization = Interface( IVideoPlayback ) ['{5AC17D60-B34D-478D-B632-EB00D4078017}'] end; IAudioPlayback = Interface( IGenericPlayback ) ['{E4AE0B40-3C21-4DC5-847C-20A87E0DFB96}'] function InitializePlayback: boolean; procedure SetVolume(Volume: integer); procedure SetMusicVolume(Volume: integer); procedure SetLoop(Enabled: boolean); procedure Rewind; function Finished: boolean; function Length: real; // Sounds function OpenSound(const Filename: String): TAudioPlaybackStream; procedure PlaySound(stream: TAudioPlaybackStream); procedure StopSound(stream: TAudioPlaybackStream); // Equalizer procedure GetFFTData(var data: TFFTData); // Interface for Visualizer function GetPCMData(var data: TPCMData): Cardinal; end; IGenericDecoder = Interface ['{557B0E9A-604D-47E4-B826-13769F3E10B7}'] function GetName(): String; function InitializeDecoder(): boolean; //function IsSupported(const Filename: string): boolean; end; (* IVideoDecoder = Interface( IGenericDecoder ) ['{2F184B2B-FE69-44D5-9031-0A2462391DCA}'] function Open(const Filename: string): TVideoDecodeStream; end; *) IAudioDecoder = Interface( IGenericDecoder ) ['{AB47B1B6-2AA9-4410-BF8C-EC79561B5478}'] function Open(const Filename: string): TAudioDecodeStream; end; IAudioInput = Interface ['{A5C8DA92-2A0C-4AB2-849B-2F7448C6003A}'] function GetName: String; function InitializeRecord: boolean; procedure CaptureStart; procedure CaptureStop; end; type TSoundLibrary = class public Start: TAudioPlaybackStream; Back: TAudioPlaybackStream; Swoosh: TAudioPlaybackStream; Change: TAudioPlaybackStream; Option: TAudioPlaybackStream; Click: TAudioPlaybackStream; Drum: TAudioPlaybackStream; Hihat: TAudioPlaybackStream; Clap: TAudioPlaybackStream; Shuffle: TAudioPlaybackStream; constructor Create(); destructor Destroy(); override; procedure LoadSounds(); procedure UnloadSounds(); end; var // TODO : JB --- THESE SHOULD NOT BE GLOBAL // czesci z nutami; Lines: array of TLines; // LineState LineState: TLineState; SoundLib: TSoundLibrary; procedure InitializeSound; function Visualization(): IVideoPlayback; function VideoPlayback(): IVideoPlayback; function AudioPlayback(): IAudioPlayback; function AudioInput(): IAudioInput; function AudioDecoder(): IAudioDecoder; function AudioManager: TInterfaceList; implementation uses sysutils, UMain, UCommandLine, URecord, ULog; var singleton_VideoPlayback : IVideoPlayback = nil; singleton_Visualization : IVideoPlayback = nil; singleton_AudioPlayback : IAudioPlayback = nil; singleton_AudioInput : IAudioInput = nil; singleton_AudioDecoder : IAudioDecoder = nil; singleton_AudioManager : TInterfaceList = nil; constructor TAudioFormatInfo.Create(Channels: byte; SampleRate: double; Format: TAudioSampleFormat); begin Self.Channels := Channels; Self.SampleRate := SampleRate; Self.Format := Format; Self.FrameSize := AudioSampleSize[Format] * Channels; end; function AudioManager: TInterfaceList; begin if singleton_AudioManager = nil then singleton_AudioManager := TInterfaceList.Create(); Result := singleton_AudioManager; end; //CompressionPluginManager function VideoPlayback(): IVideoPlayback; begin result := singleton_VideoPlayback; end; function Visualization(): IVideoPlayback; begin result := singleton_Visualization; end; function AudioPlayback(): IAudioPlayback; begin result := singleton_AudioPlayback; end; function AudioInput(): IAudioInput; begin result := singleton_AudioInput; end; function AudioDecoder(): IAudioDecoder; begin result := singleton_AudioDecoder; end; procedure AssignSingletonObjects(); var lTmpInterface : IInterface; iCount : Integer; begin lTmpInterface := nil; for iCount := 0 to AudioManager.Count - 1 do begin if assigned( AudioManager[iCount] ) then begin // if this interface is a Playback, then set it as the default used if ( AudioManager[iCount].QueryInterface( IAudioPlayback, lTmpInterface ) = 0 ) AND ( true ) then //not assigned( singleton_AudioPlayback ) ) then begin singleton_AudioPlayback := IAudioPlayback( lTmpInterface ); end; // if this interface is a Input, then set it as the default used if ( AudioManager[iCount].QueryInterface( IAudioInput, lTmpInterface ) = 0 ) AND ( true ) then //not assigned( singleton_AudioInput ) ) then begin singleton_AudioInput := IAudioInput( lTmpInterface ); end; // if this interface is a Decoder, then set it as the default used if ( AudioManager[iCount].QueryInterface( IAudioDecoder, lTmpInterface ) = 0 ) AND ( true ) then //not assigned( singleton_AudioDecoder ) ) then begin singleton_AudioDecoder := IAudioDecoder( lTmpInterface ); end; // if this interface is a Input, then set it as the default used if ( AudioManager[iCount].QueryInterface( IVideoPlayback, lTmpInterface ) = 0 ) AND ( true ) then //not assigned( singleton_VideoPlayback ) ) then begin singleton_VideoPlayback := IVideoPlayback( lTmpInterface ); end; if ( AudioManager[iCount].QueryInterface( IVideoVisualization, lTmpInterface ) = 0 ) AND ( true ) then //not assigned( singleton_Visualization ) ) then begin singleton_Visualization := IVideoPlayback( lTmpInterface ); end; end; end; end; procedure InitializeSound; begin singleton_AudioPlayback := nil; singleton_AudioInput := nil; singleton_AudioDecoder := nil; singleton_VideoPlayback := nil; singleton_Visualization := nil; AssignSingletonObjects(); if VideoPlayback <> nil then begin end; if AudioDecoder <> nil then begin while not AudioDecoder.InitializeDecoder do begin Log.LogError('Initialize failed, Removing - '+ AudioDecoder.GetName); AudioManager.remove( AudioDecoder ); singleton_AudioDecoder := nil; AssignSingletonObjects(); end; end; if AudioPlayback <> nil then begin while not AudioPlayback.InitializePlayback do begin Log.LogError('Initialize failed, Removing - '+ AudioPlayback.GetName); AudioManager.remove( AudioPlayback ); singleton_AudioPlayback := nil; AssignSingletonObjects(); end; end; if AudioInput <> nil then begin while not AudioInput.InitializeRecord do begin Log.LogError('Initialize failed, Removing - '+ AudioInput.GetName); AudioManager.remove( AudioInput ); singleton_AudioInput := nil; AssignSingletonObjects(); end; end; // Load in-game sounds SoundLib := TSoundLibrary.Create; if FindCmdLineSwitch( cMediaInterfaces ) then begin writeln( '' ); writeln( '--------------------------------------------------------------' ); writeln( ' In-use Media Interfaces ' ); writeln( '--------------------------------------------------------------' ); writeln( 'Registered Audio Playback Interface : ' + AudioPlayback.GetName ); writeln( 'Registered Audio Input Interface : ' + AudioInput.GetName ); writeln( 'Registered Video Playback Interface : ' + VideoPlayback.GetName ); writeln( 'Registered Visualization Interface : ' + Visualization.GetName ); writeln( '--------------------------------------------------------------' ); writeln( '' ); halt; end; end; { TSoundLibrary } constructor TSoundLibrary.Create(); begin LoadSounds(); end; destructor TSoundLibrary.Destroy(); begin UnloadSounds(); end; procedure TSoundLibrary.LoadSounds(); begin //Log.LogStatus('Loading Sounds', 'Music Initialize'); //Log.BenchmarkStart(4); UnloadSounds(); Start := AudioPlayback.OpenSound(SoundPath + 'Common start.mp3'); Back := AudioPlayback.OpenSound(SoundPath + 'Common back.mp3'); Swoosh := AudioPlayback.OpenSound(SoundPath + 'menu swoosh.mp3'); Change := AudioPlayback.OpenSound(SoundPath + 'select music change music 50.mp3'); Option := AudioPlayback.OpenSound(SoundPath + 'option change col.mp3'); Click := AudioPlayback.OpenSound(SoundPath + 'rimshot022b.mp3'); //Drum := AudioPlayback.OpenSound(SoundPath + 'bassdrumhard076b.mp3'); //Hihat := AudioPlayback.OpenSound(SoundPath + 'hihatclosed068b.mp3'); //Clap := AudioPlayback.OpenSound(SoundPath + 'claps050b.mp3'); //Shuffle := AudioPlayback.OpenSound(SoundPath + 'Shuffle.mp3'); //Log.BenchmarkEnd(4); //Log.LogBenchmark('--> Loading Sounds', 4); end; procedure TSoundLibrary.UnloadSounds(); begin Start.Free; Back.Free; Swoosh.Free; Change.Free; Option.Free; Click.Free; //Drum.Free; //Hihat.Free; //Clap.Free; //Shuffle.Free; end; initialization begin singleton_AudioManager := TInterfaceList.Create(); end; finalization singleton_AudioManager.clear; FreeAndNil( singleton_AudioManager ); end.