{* UltraStar Deluxe - Karaoke Game * * UltraStar Deluxe is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * $URL$ * $Id$ *} unit UMenuEqualizer; interface {$IFDEF FPC} {$MODE Delphi} {$ENDIF} {$I switches.inc} uses UMusic, UThemes; type //---------------- //Tms_Equalizer //Class displaying an equalizer (Songscreen) //---------------- Tms_Equalizer = class(TObject) private FFTData: TFFTData; // moved here to avoid stack overflows BandData: array of Byte; RefreshTime: Cardinal; Source: IAudioPlayback; Procedure Analyse; public X: Integer; Y: Integer; Z: Real; W: Integer; H: Integer; Space: Integer; Visible: Boolean; Alpha: real; Color: TRGB; Direction: Boolean; BandLength: Integer; Reflection: boolean; Reflectionspacing: Real; constructor Create(Source: IAudioPlayback; mySkin: TThemeEqualizer); procedure Draw; Procedure SetBands(Value: Byte); Function GetBands: Byte; Property Bands: Byte read GetBands write SetBands; procedure SetSource(newSource: IAudioPlayback); end; implementation uses math, SDL, gl, glext; constructor Tms_Equalizer.Create(Source: IAudioPlayback; mySkin: TThemeEqualizer); var I: Integer; begin If (Source <> nil) then begin X := mySkin.X; Y := mySkin.Y; W := mySkin.W; H := mySkin.H; Z := mySkin.Z; Space := mySkin.Space; Visible := mySkin.Visible; Alpha := mySkin.Alpha; Color.R := mySkin.ColR; Color.G := mySkin.ColG; Color.B := mySkin.ColB; Direction := mySkin.Direction; Bands := mySkin.Bands; BandLength := mySkin.Length; Reflection := mySkin.Reflection; Reflectionspacing := mySkin.Reflectionspacing; Self.Source := Source; //Check if Visible If (Bands <= 0) OR (BandLength <= 0) OR (W <= 0) OR (H <= 0) OR (Alpha <= 0) then Visible := False; //ClearArray For I := low(BandData) to high(BandData) do BandData[I] := 3; end else Visible := False; end; //-------- // evaluate FFT-Data //-------- Procedure Tms_Equalizer.Analyse; var I: Integer; ChansPerBand: byte; // channels per band MaxChannel: Integer; Pos: Real; CurBand: Integer; begin Source.GetFFTData(FFTData); Pos := 0; // use only the first approx. 92 of 256 FFT-channels (approx. up to 8kHz ChansPerBand := ceil(92 / Bands); // How much channels are used for one Band MaxChannel := ChansPerBand * Bands - 1; // Change Lengths for i := 0 to MaxChannel do begin // Gain higher freq. data so that the bars are visible if i > 35 then FFTData[i] := FFTData[i] * 8 else if i > 11 then FFTData[i] := FFTData[i] * 4.5 else FFTData[i] := FFTData[i] * 1.1; // clamp data if (FFTData[i] > 1) then FFTData[i] := 1; // Get max. pos if (FFTData[i] * BandLength > Pos) then Pos := FFTData[i] * BandLength; // Check if this is the last channel in the band if ((i+1) mod ChansPerBand = 0) then begin CurBand := i div ChansPerBand; // Smooth delay if new equalizer is lower than the old one if ((BandData[CurBand] > Pos) and (BandData[CurBand] > 1)) then BandData[CurBand] := BandData[CurBand] - 1 else BandData[CurBand] := Round(Pos); Pos := 0; end; end; end; //-------- // Draw SpectrumAnalyser, Call Analyse //-------- procedure Tms_Equalizer.Draw; var CurTime: Cardinal; PosX, PosY: Real; I, J: Integer; Diff: Real; Function GetAlpha(H: Single): Single; begin Result := (Alpha * 0.3) *(1 - H/(Bands * (W + Space))); end; begin If (Visible) AND not (AudioPlayback.Finished) then begin //Call Analyse if necessary CurTime := SDL_GetTicks(); If (CurTime > RefreshTime) then begin Analyse; RefreshTime := CurTime + 44; end; //Draw Equalizer Bands // Setup OpenGL glColorRGB(Color, Alpha); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); // Set position of the first equalizer bar PosY := Y; PosX := X; // Draw bars for each band for I := 0 to High(BandData) do begin // Reset to lower or left position depending on the drawing-direction if Direction then // Vertical bars // FIXME: Is Y the upper or lower coordinate? PosY := Y //+ (H + Space) * BandLength else // Horizontal bars PosX := X; // Draw the bar as a stack of blocks for J := 1 to BandData[I] do begin // Draw block glBegin(GL_QUADS); glVertex3f(PosX, PosY, Z); glVertex3f(PosX, PosY+H, Z); glVertex3f(PosX+W, PosY+H, Z); glVertex3f(PosX+W, PosY, Z); glEnd; If (Reflection) AND (J < BandLength div 2) then begin Diff := (Y-PosY) + H; //Draw Reflection If Direction then begin glBegin(GL_QUADS); glColorRGB(Color, GetAlpha(Diff)); glVertex3f(PosX, Diff + Y + ReflectionSpacing, Z); glVertex3f(PosX, Diff + Y+H + ReflectionSpacing, Z); glVertex3f(PosX+W, Diff + Y+H + ReflectionSpacing, Z); glVertex3f(PosX+W, Diff + Y + ReflectionSpacing, Z); glColorRGB(Color, GetAlpha(Diff + H)); glEnd; end else begin glBegin(GL_QUADS); glColorRGB(Color, GetAlpha(Diff)); glVertex3f(PosX, Diff + Y + (H + Space)*Bands + ReflectionSpacing, Z); glVertex3f(PosX, Diff + Y+H + (H + Space)*Bands + ReflectionSpacing, Z); glVertex3f(PosX+W, Diff + Y+H + (H + Space)*Bands + ReflectionSpacing, Z); glVertex3f(PosX+W, Diff + Y + (H + Space)*Bands + ReflectionSpacing, Z); glColorRGB(Color, GetAlpha(Diff + H)); glEnd; end; glColorRGB(Color, Alpha); end; // Calc position of the bar's next block if Direction then // Vertical bars PosY := PosY - H - Space else // Horizontal bars PosX := PosX + W + Space; end; // Calc position of the next bar if Direction then // Vertical bars PosX := PosX + W + Space else // Horizontal bars PosY := PosY + H + Space; end; end; end; Procedure Tms_Equalizer.SetBands(Value: Byte); begin SetLength(BandData, Value); end; Function Tms_Equalizer.GetBands: Byte; begin Result := Length(BandData); end; Procedure Tms_Equalizer.SetSource(newSource: IAudioPlayback); begin If (newSource <> nil) then Source := newSource; end; end.