aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Screens
diff options
context:
space:
mode:
authortobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2008-05-09 19:19:28 +0000
committertobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2008-05-09 19:19:28 +0000
commitb5a738fa52c8b0f2212deb5febd2d7f0b8f6544f (patch)
tree3c2812cffdd035b385d5b0f0f8f5ea0702973739 /Game/Code/Screens
parent37744cee627605db0675efd3a6e0c42bd51c48d6 (diff)
downloadusdx-b5a738fa52c8b0f2212deb5febd2d7f0b8f6544f.tar.gz
usdx-b5a738fa52c8b0f2212deb5febd2d7f0b8f6544f.tar.xz
usdx-b5a738fa52c8b0f2212deb5febd2d7f0b8f6544f.zip
- input-source selection works now (with bass or portaudio with portmixer)
- audio-effects (DSP) interface for audio-playback plus a simple voice removal example (does not sound that good) - FFMpeg support for BASS - audio-clock for FFMpeg for GetPosition and synchronisation - more compatible seeking in FFMpeg - clean termination of the audio interfaces/streams (especially ffmpeg) - Audio output device enumeration (selection will be added later to the sounds option screen) - display of threshold and volume in the record-options screen - threshold and volume can be changed with the 'T' (threshold) and '+'/'-' (source volume) keys - added a FadeIn() method to the IAudioPlayback interface - some minor changes to the audio classes/screens - new base-class for audio-playback classes (used by bass, portaudio and sdl) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1078 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'Game/Code/Screens')
-rw-r--r--Game/Code/Screens/UScreenOptionsRecord.pas532
-rw-r--r--Game/Code/Screens/UScreenOptionsSound.pas2
-rw-r--r--Game/Code/Screens/UScreenSong.pas95
3 files changed, 438 insertions, 191 deletions
diff --git a/Game/Code/Screens/UScreenOptionsRecord.pas b/Game/Code/Screens/UScreenOptionsRecord.pas
index b9000991..8e3d0f67 100644
--- a/Game/Code/Screens/UScreenOptionsRecord.pas
+++ b/Game/Code/Screens/UScreenOptionsRecord.pas
@@ -15,6 +15,17 @@ uses
UMenu;
type
+ TDrawState = record
+ ChannelIndex: integer;
+ R, G, B: real; // mapped player color (normal)
+ RD, GD, BD: real; // mapped player color (dark)
+ end;
+
+ TPeakInfo = record
+ Volume: single;
+ Time: cardinal;
+ end;
+
TScreenOptionsRecord = class(TMenu)
private
// max. count of input-channels determined for all devices
@@ -32,11 +43,11 @@ type
SelectSlideChannelTheme: array of TThemeSelectSlide;
// indices for widget-updates
- SelectSlideInputID: integer;
+ SelectInputSourceID: integer;
SelectSlideChannelID: array of integer;
TextPitchID: array of integer;
- // interaction IDs
+ // interaction IDs
ExitButtonIID: integer;
// dummy data for non-available channels
@@ -44,10 +55,19 @@ type
// preview channel-buffers
PreviewChannel: array of TCaptureBuffer;
+ ChannelPeak: array of TPeakInfo;
+
+ // Device source volume
+ SourceVolume: single;
+ NextVolumePollTime: cardinal;
procedure StartPreview;
procedure StopPreview;
- procedure UpdateCard;
+ procedure UpdateInputDevice;
+ procedure ChangeVolume(VolumeChange: integer);
+ procedure DrawVolume(x, y, Width, Height: single);
+ procedure DrawVUMeter(const State: TDrawState; x, y, Width, Height: single);
+ procedure DrawPitch(const State: TDrawState; x, y, Width, Height: single);
public
constructor Create; override;
function Draw: boolean; override;
@@ -56,10 +76,21 @@ type
procedure onHide; override;
end;
+const
+ PeakDecay = 0.2; // strength of peak-decay (reduction after one sec)
+
+const
+ BarHeight = 11; // height of each bar (volume/vu-meter/pitch)
+ BarUpperSpacing = 1; // spacing between a bar-area and the previous widget
+ BarLowerSpacing = 3; // spacing between a bar-area and the next widget
+ SourceBarsTotalHeight = BarHeight + BarUpperSpacing + BarLowerSpacing;
+ ChannelBarsTotalHeight = 2*BarHeight + BarUpperSpacing + BarLowerSpacing;
+
implementation
uses
SysUtils,
+ Math,
SDL,
gl,
UGraphic,
@@ -84,8 +115,27 @@ begin
Result := false;
Exit;
end;
+ '+':
+ begin
+ // FIXME: add a nice volume-slider instead
+ // or at least provide visualization and acceleration if the user holds the key pressed.
+ ChangeVolume(2);
+ end;
+ '-':
+ begin
+ // FIXME: add a nice volume-slider instead
+ // or at least provide visualization and acceleration if the user holds the key pressed.
+ ChangeVolume(-2);
+ end;
+ 'T':
+ begin
+ if ((SDL_GetModState() and KMOD_SHIFT) <> 0) then
+ Ini.ThresholdIndex := (Ini.ThresholdIndex + Length(IThresholdVals) - 1) mod Length(IThresholdVals)
+ else
+ Ini.ThresholdIndex := (Ini.ThresholdIndex + 1) mod Length(IThresholdVals);
+ end;
end;
-
+
// check special keys
case PressedKey of
SDLK_ESCAPE,
@@ -115,7 +165,7 @@ begin
AudioPlayback.PlaySound(SoundLib.Option);
InteractInc;
end;
- UpdateCard;
+ UpdateInputDevice;
end;
SDLK_LEFT:
begin
@@ -124,7 +174,7 @@ begin
AudioPlayback.PlaySound(SoundLib.Option);
InteractDec;
end;
- UpdateCard;
+ UpdateInputDevice;
end;
end;
end;
@@ -139,13 +189,14 @@ var
InputDeviceCfg: PInputDeviceConfig;
ChannelTheme: ^TThemeSelectSlide;
ButtonTheme: TThemeButton;
+ WidgetYPos: integer;
begin
inherited Create;
LoadFromTheme(Theme.OptionsRecord);
// set CurrentDeviceIndex to a valid device
- if (Length(AudioInputProcessor.Device) > 0) then
+ if (Length(AudioInputProcessor.DeviceList) > 0) then
CurrentDeviceIndex := 0
else
CurrentDeviceIndex := -1;
@@ -153,16 +204,16 @@ begin
PreviewDeviceIndex := -1;
// init sliders if at least one device was detected
- if (Length(AudioInputProcessor.Device) > 0) then
+ if (Length(AudioInputProcessor.DeviceList) > 0) then
begin
- InputDevice := AudioInputProcessor.Device[CurrentDeviceIndex];
+ InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex];
InputDeviceCfg := @Ini.InputDeviceConfig[InputDevice.CfgIndex];
// init device-selection slider
- SetLength(InputDeviceNames, Length(AudioInputProcessor.Device));
- for DeviceIndex := 0 to High(AudioInputProcessor.Device) do
+ SetLength(InputDeviceNames, Length(AudioInputProcessor.DeviceList));
+ for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do
begin
- InputDeviceNames[DeviceIndex] := AudioInputProcessor.Device[DeviceIndex].Description;
+ InputDeviceNames[DeviceIndex] := AudioInputProcessor.DeviceList[DeviceIndex].Name;
end;
// add device-selection slider (InteractionID: 0)
AddSelectSlide(Theme.OptionsRecord.SelectSlideCard, CurrentDeviceIndex, InputDeviceNames);
@@ -174,15 +225,20 @@ begin
InputSourceNames[SourceIndex] := InputDevice.Source[SourceIndex].Name;
end;
// add source-selection slider (InteractionID: 1)
- SelectSlideInputID := AddSelectSlide(Theme.OptionsRecord.SelectSlideInput,
+ SelectInputSourceID := AddSelectSlide(Theme.OptionsRecord.SelectSlideInput,
InputDeviceCfg.Input, InputSourceNames);
+ // add space for source volume bar
+ WidgetYPos := Theme.OptionsRecord.SelectSlideInput.Y +
+ Theme.OptionsRecord.SelectSlideInput.H +
+ SourceBarsTotalHeight;
+
// find max. channel count of all devices
MaxChannelCount := 0;
- for DeviceIndex := 0 to High(AudioInputProcessor.Device) do
+ for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do
begin
- if (AudioInputProcessor.Device[DeviceIndex].AudioFormat.Channels > MaxChannelCount) then
- MaxChannelCount := AudioInputProcessor.Device[DeviceIndex].AudioFormat.Channels;
+ if (AudioInputProcessor.DeviceList[DeviceIndex].AudioFormat.Channels > MaxChannelCount) then
+ MaxChannelCount := AudioInputProcessor.DeviceList[DeviceIndex].AudioFormat.Channels;
end;
// init channel-to-player mapping sliders
@@ -198,7 +254,9 @@ begin
// set current channel-theme
ChannelTheme := @SelectSlideChannelTheme[ChannelIndex];
// adjust vertical position
- ChannelTheme.Y := ChannelTheme.Y + ChannelIndex * ChannelTheme.H;
+ ChannelTheme.Y := WidgetYPos;
+ // calc size of next slide (add space for bars)
+ WidgetYPos := WidgetYPos + ChannelTheme.H + ChannelBarsTotalHeight;
// append channel index to name
ChannelTheme.Text := ChannelTheme.Text + IntToStr(ChannelIndex+1);
@@ -215,7 +273,7 @@ begin
// add slider
SelectSlideChannelID[ChannelIndex] := AddSelectSlide(ChannelTheme^,
- InputDeviceCfg.ChannelToPlayerMap[ChannelIndex], IChannel);
+ InputDeviceCfg.ChannelToPlayerMap[ChannelIndex], IChannelPlayer);
end
else
begin
@@ -223,52 +281,50 @@ begin
// add slider but hide it and assign a dummy variable to it
SelectSlideChannelID[ChannelIndex] := AddSelectSlide(ChannelTheme^,
- ChannelToPlayerMapDummy, IChannel);
+ ChannelToPlayerMapDummy, IChannelPlayer);
SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := false;
// hide pitch label
Text[TextPitchID[ChannelIndex]].Visible := false;
end;
end;
-
- // TODO: move from sound-options to record-options (Themes must be changed first)
- //AddSelect(Theme.OptionsSound.SelectMicBoost, Ini.MicBoost, IMicBoost);
end;
// add Exit-button
ButtonTheme := Theme.OptionsRecord.ButtonExit;
- ButtonTheme.Y := Theme.OptionsRecord.SelectSlideChannel.Y +
- MaxChannelCount *
- Theme.OptionsRecord.SelectSlideChannel.H;
+ ButtonTheme.Y := WidgetYPos;
AddButton(ButtonTheme);
if (Length(Button[0].Text) = 0) then
AddButtonText(14, 20, Theme.Options.Description[7]);
// store InteractionID
- ExitButtonIID := MaxChannelCount + 2;
+ if (Length(AudioInputProcessor.DeviceList) > 0) then
+ ExitButtonIID := MaxChannelCount + 2
+ else
+ ExitButtonIID := 0;
// set focus
Interaction := 0;
end;
-procedure TScreenOptionsRecord.UpdateCard;
+procedure TScreenOptionsRecord.UpdateInputDevice;
var
SourceIndex: integer;
InputDevice: TAudioInputDevice;
InputDeviceCfg: PInputDeviceConfig;
ChannelIndex: integer;
begin
- Log.LogStatus('Update input-device', 'TScreenOptionsRecord.UpdateCard') ;
+ //Log.LogStatus('Update input-device', 'TScreenOptionsRecord.UpdateCard') ;
StopPreview();
// set CurrentDeviceIndex to a valid device
- if (CurrentDeviceIndex > High(AudioInputProcessor.Device)) then
+ if (CurrentDeviceIndex > High(AudioInputProcessor.DeviceList)) then
CurrentDeviceIndex := 0;
// update sliders if at least one device was detected
- if (Length(AudioInputProcessor.Device) > 0) then
+ if (Length(AudioInputProcessor.DeviceList) > 0) then
begin
- InputDevice := AudioInputProcessor.Device[CurrentDeviceIndex];
+ InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex];
InputDeviceCfg := @Ini.InputDeviceConfig[InputDevice.CfgIndex];
// update source-selection slider
@@ -277,7 +333,7 @@ begin
begin
InputSourceNames[SourceIndex] := InputDevice.Source[SourceIndex].Name;
end;
- UpdateSelectSlideOptions(Theme.OptionsRecord.SelectSlideInput, SelectSlideInputID,
+ UpdateSelectSlideOptions(Theme.OptionsRecord.SelectSlideInput, SelectInputSourceID,
InputSourceNames, InputDeviceCfg.Input);
// update channel-to-player mapping sliders
@@ -290,7 +346,7 @@ begin
// show slider
UpdateSelectSlideOptions(SelectSlideChannelTheme[ChannelIndex],
- SelectSlideChannelID[ChannelIndex], IChannel,
+ SelectSlideChannelID[ChannelIndex], IChannelPlayer,
InputDeviceCfg.ChannelToPlayerMap[ChannelIndex]);
SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := true;
@@ -303,7 +359,7 @@ begin
// hide slider and assign a dummy variable to it
UpdateSelectSlideOptions(SelectSlideChannelTheme[ChannelIndex],
- SelectSlideChannelID[ChannelIndex], IChannel,
+ SelectSlideChannelID[ChannelIndex], IChannelPlayer,
ChannelToPlayerMapDummy);
SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := false;
@@ -316,6 +372,31 @@ begin
StartPreview();
end;
+procedure TScreenOptionsRecord.ChangeVolume(VolumeChange: integer);
+var
+ InputDevice: TAudioInputDevice;
+ Volume: integer;
+begin
+ // validate CurrentDeviceIndex
+ if ((CurrentDeviceIndex < 0) or
+ (CurrentDeviceIndex > High(AudioInputProcessor.DeviceList))) then
+ begin
+ Exit;
+ end;
+
+ InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex];
+ if not assigned(InputDevice) then
+ Exit;
+
+ // set new volume
+ Volume := InputDevice.GetVolume() + VolumeChange;
+ InputDevice.SetVolume(Volume);
+ //DebugWriteln('Volume: ' + inttostr(InputDevice.GetVolume));
+
+ // volume must be polled again
+ NextVolumePollTime := 0;
+end;
+
procedure TScreenOptionsRecord.onShow;
var
ChannelIndex: integer;
@@ -329,6 +410,8 @@ begin
for ChannelIndex := 0 to High(PreviewChannel) do
PreviewChannel[ChannelIndex] := TCaptureBuffer.Create();
+ SetLength(ChannelPeak, MaxChannelCount);
+
StartPreview();
end;
@@ -342,6 +425,7 @@ begin
for ChannelIndex := 0 to High(PreviewChannel) do
PreviewChannel[ChannelIndex].Free;
SetLength(PreviewChannel, 0);
+ SetLength(ChannelPeak, 0);
end;
procedure TScreenOptionsRecord.StartPreview;
@@ -350,17 +434,21 @@ var
Device: TAudioInputDevice;
begin
if ((CurrentDeviceIndex >= 0) and
- (CurrentDeviceIndex <= High(AudioInputProcessor.Device))) then
+ (CurrentDeviceIndex <= High(AudioInputProcessor.DeviceList))) then
begin
- Device := AudioInputProcessor.Device[CurrentDeviceIndex];
+ Device := AudioInputProcessor.DeviceList[CurrentDeviceIndex];
// set preview channel as active capture channel
for ChannelIndex := 0 to High(Device.CaptureChannel) do
begin
PreviewChannel[ChannelIndex].Clear();
Device.LinkCaptureBuffer(ChannelIndex, PreviewChannel[ChannelIndex]);
+ FillChar(ChannelPeak[ChannelIndex], SizeOf(TPeakInfo), 0);
end;
Device.Start();
PreviewDeviceIndex := CurrentDeviceIndex;
+
+ // volume must be polled again
+ NextVolumePollTime := 0;
end;
end;
@@ -370,9 +458,9 @@ var
Device: TAudioInputDevice;
begin
if ((PreviewDeviceIndex >= 0) and
- (PreviewDeviceIndex <= High(AudioInputProcessor.Device))) then
+ (PreviewDeviceIndex <= High(AudioInputProcessor.DeviceList))) then
begin
- Device := AudioInputProcessor.Device[PreviewDeviceIndex];
+ Device := AudioInputProcessor.DeviceList[PreviewDeviceIndex];
Device.Stop;
for ChannelIndex := 0 to High(Device.CaptureChannel) do
Device.CaptureChannel[ChannelIndex] := nil;
@@ -380,137 +468,281 @@ begin
PreviewDeviceIndex := -1;
end;
+
+procedure TScreenOptionsRecord.DrawVolume(x, y, Width, Height: single);
+var
+ x1, y1, x2, y2: single;
+ VolBarInnerWidth: integer;
+const
+ VolBarInnerHSpacing = 2;
+ VolBarInnerVSpacing = 1;
+begin
+ // coordinates for black rect
+ x1 := x;
+ y1 := y;
+ x2 := x1 + Width;
+ y2 := y1 + Height;
+
+ // draw black background-rect
+ glColor4f(0, 0, 0, 0.8);
+ glBegin(GL_QUADS);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+
+ VolBarInnerWidth := Trunc(Width - 2*VolBarInnerHSpacing);
+
+ // coordinates for first half of the volume bar
+ x1 := x + VolBarInnerHSpacing;
+ x2 := x1 + VolBarInnerWidth * SourceVolume;
+ y1 := y1 + VolBarInnerVSpacing;
+ y2 := y2 - VolBarInnerVSpacing;
+
+ // draw volume-bar
+ glBegin(GL_QUADS);
+ // draw volume bar
+ glColor3f(0.4, 0.3, 0.3);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glColor3f(1, 0.1, 0.1);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
+ glEnd();
+
+ { not needed anymore
+ // coordinates for separator
+ x1 := x + VolBarInnerHSpacing;
+ x2 := x1 + VolBarInnerWidth;
+
+ // draw separator
+ glBegin(GL_LINE_STRIP);
+ glColor4f(0.1, 0.1, 0.1, 0.2);
+ glVertex2f(x1, y2);
+ glColor4f(0.4, 0.4, 0.4, 0.2);
+ glVertex2f((x1+x2)/2, y2);
+ glColor4f(0.1, 0.1, 0.1, 0.2);
+ glVertex2f(x2, y2);
+ glEnd();
+ }
+end;
+
+procedure TScreenOptionsRecord.DrawVUMeter(const State: TDrawState; x, y, Width, Height: single);
+var
+ x1, y1, x2, y2: single;
+ Volume, PeakVolume: single;
+ Delta: single;
+ VolBarInnerWidth: integer;
+const
+ VolBarInnerHSpacing = 2;
+ VolBarInnerVSpacing = 1;
+begin
+ // coordinates for black rect
+ x1 := x;
+ y1 := y;
+ x2 := x1 + Width;
+ y2 := y1 + Height;
+
+ // draw black background-rect
+ glColor4f(0, 0, 0, 0.8);
+ glBegin(GL_QUADS);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+
+ VolBarInnerWidth := Trunc(Width - 2*VolBarInnerHSpacing);
+
+ // vertical positions
+ y1 := y1 + VolBarInnerVSpacing;
+ y2 := y2 - VolBarInnerVSpacing;
+
+ // coordinates for bevel
+ x1 := x + VolBarInnerHSpacing;
+ x2 := x1 + VolBarInnerWidth;
+
+ glBegin(GL_QUADS);
+ Volume := PreviewChannel[State.ChannelIndex].MaxSampleVolume();
+
+ // coordinates for volume bar
+ x1 := x + VolBarInnerHSpacing;
+ x2 := x1 + VolBarInnerWidth * Volume;
+
+ // draw volume bar
+ glColor3f(State.RD, State.GD, State.BD);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glColor3f(State.R, State.G, State.B);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
+
+ Delta := (SDL_GetTicks() - ChannelPeak[State.ChannelIndex].Time)/1000;
+ PeakVolume := ChannelPeak[State.ChannelIndex].Volume - Delta*Delta*PeakDecay;
+
+ // determine new peak-volume
+ if (Volume > PeakVolume) then
+ begin
+ PeakVolume := Volume;
+ ChannelPeak[State.ChannelIndex].Volume := Volume;
+ ChannelPeak[State.ChannelIndex].Time := SDL_GetTicks();
+ end;
+
+ x1 := x + VolBarInnerHSpacing + VolBarInnerWidth * PeakVolume;
+ x2 := x1 + 2;
+
+ // draw peak
+ glColor3f(0.8, 0.8, 0.8);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
+
+ // draw threshold
+ x1 := x + VolBarInnerHSpacing;
+ x2 := x1 + VolBarInnerWidth * IThresholdVals[Ini.ThresholdIndex];
+
+ glColor4f(0.3, 0.3, 0.3, 0.6);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
+ glEnd();
+end;
+
+procedure TScreenOptionsRecord.DrawPitch(const State: TDrawState; x, y, Width, Height: single);
+var
+ x1, y1, x2, y2: single;
+ i: integer;
+ ToneBoxWidth: real;
+const
+ PitchBarInnerHSpacing = 2;
+ PitchBarInnerVSpacing = 1;
+begin
+ // calc tone pitch
+ PreviewChannel[State.ChannelIndex].AnalyzeBuffer();
+
+ // coordinates for black rect
+ x1 := x;
+ y1 := y;
+ x2 := x + Width;
+ y2 := y + Height;
+
+ // draw black background-rect
+ glColor4f(0, 0, 0, 0.8);
+ glBegin(GL_QUADS);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+
+ // coordinates for tone boxes
+ ToneBoxWidth := Width / NumHalftones;
+ y1 := y1 + PitchBarInnerVSpacing;
+ y2 := y2 - PitchBarInnerVSpacing;
+
+ glBegin(GL_QUADS);
+ // draw tone boxes
+ for i := 0 to NumHalftones-1 do
+ begin
+ x1 := x + i * ToneBoxWidth + PitchBarInnerHSpacing;
+ x2 := x1 + ToneBoxWidth - 2*PitchBarInnerHSpacing;
+
+ if ((PreviewChannel[State.ChannelIndex].ToneValid) and
+ (PreviewChannel[State.ChannelIndex].ToneAbs = i)) then
+ begin
+ // highlight current tone-pitch
+ glColor3f(1, i / (NumHalftones-1), 0)
+ end
+ else
+ begin
+ // grey other tone-pitches
+ glColor3f(0.3, i / (NumHalftones-1) * 0.3, 0);
+ end;
+
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ end;
+ glEnd();
+
+ // update tone-pitch label
+ Text[TextPitchID[State.ChannelIndex]].Text :=
+ PreviewChannel[State.ChannelIndex].ToneString;
+end;
+
function TScreenOptionsRecord.Draw: boolean;
var
i: integer;
- x1, x2, y1, y2: real;
- R, G, B, RD, GD, BD: real;
- ChannelIndex: integer;
Device: TAudioInputDevice;
DeviceCfg: PInputDeviceConfig;
SelectSlide: TSelectSlide;
- ToneBoxWidth: real;
- Volume: single;
+ BarXOffset, BarYOffset, BarWidth: real;
+ ChannelIndex: integer;
+ State: TDrawState;
begin
DrawBG;
DrawFG;
if ((PreviewDeviceIndex >= 0) and
- (PreviewDeviceIndex <= High(AudioInputProcessor.Device))) then
+ (PreviewDeviceIndex <= High(AudioInputProcessor.DeviceList))) then
begin
- Device := AudioInputProcessor.Device[PreviewDeviceIndex];
+ Device := AudioInputProcessor.DeviceList[PreviewDeviceIndex];
DeviceCfg := @Ini.InputDeviceConfig[Device.CfgIndex];
- glBegin(GL_QUADS);
- for ChannelIndex := 0 to High(Device.CaptureChannel) do
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // update source volume
+ if (SDL_GetTicks() >= NextVolumePollTime) then
+ begin
+ NextVolumePollTime := SDL_GetTicks() + 500; // next poll in 500ms
+ SourceVolume := Device.GetVolume()/100;
+ end;
+
+ // get source select slide
+ SelectSlide := SelectsS[SelectInputSourceID];
+ BarXOffset := SelectSlide.TextureSBG.X;
+ BarYOffset := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H + BarUpperSpacing;
+ BarWidth := SelectSlide.TextureSBG.W;
+ DrawVolume(SelectSlide.TextureSBG.X, BarYOffset, BarWidth, BarHeight);
+
+ for ChannelIndex := 0 to High(Device.CaptureChannel) do
+ begin
+ // load player color mapped to current input channel
+ if (DeviceCfg.ChannelToPlayerMap[ChannelIndex] > 0) then
begin
- // load player color mapped to current input channel
- if (DeviceCfg.ChannelToPlayerMap[ChannelIndex] > 0) then
- begin
- // set mapped channel to corresponding player-color
- LoadColor(R, G, B, 'P'+ IntToStr(DeviceCfg.ChannelToPlayerMap[ChannelIndex]) + 'Dark');
- end
- else
- begin
- // set non-mapped channel to white
- R := 1; G := 1; B := 1;
- end;
+ // set mapped channel to corresponding player-color
+ LoadColor(State.R, State.G, State.B, 'P'+ IntToStr(DeviceCfg.ChannelToPlayerMap[ChannelIndex]) + 'Dark');
+ end
+ else
+ begin
+ // set non-mapped channel to white
+ State.R := 1; State.G := 1; State.B := 1;
+ end;
- // dark player colors
- RD := 0.2 * R;
- GD := 0.2 * G;
- BD := 0.2 * B;
-
- // channel select slide
- SelectSlide := SelectsS[SelectSlideChannelID[ChannelIndex]];
-
- //////////
- // draw Volume
- //
-
- // coordinates for black rect
- x1 := SelectSlide.TextureSBG.X;
- x2 := x1 + SelectSlide.TextureSBG.W;
- y2 := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H;
- y1 := y2 - 11;
-
- // draw black background-rect
- glColor3f(0, 0, 0);
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
- glVertex2f(x2, y2);
- glVertex2f(x1, y2);
-
- Volume := PreviewChannel[ChannelIndex].MaxSampleVolume();
-
- // coordinates for volume bar
- x1 := x1 + 1;
- x2 := x1 + Trunc((SelectSlide.TextureSBG.W-4) * Volume) + 1;
- y1 := y1 + 1;
- y2 := y2 - 1;
-
- // draw volume bar
- glColor3f(RD, GD, BD);
- glVertex2f(x1, y1);
- glVertex2f(x1, y2);
- glColor3f(R, G, B);
- glVertex2f(x2, y2);
- glVertex2f(x2, y1);
-
- //////////
- // draw Pitch
- //
-
- // calc tone pitch
- PreviewChannel[ChannelIndex].AnalyzeBuffer();
-
- // coordinates for black rect
- x1 := SelectSlide.TextureSBG.X;
- x2 := x1 + SelectSlide.TextureSBG.W;
- y1 := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H;
- y2 := y1 + 11;
-
- // draw black background-rect
- glColor3f(0, 0, 0);
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
- glVertex2f(x2, y2);
- glVertex2f(x1, y2);
-
- // coordinates for tone boxes
- ToneBoxWidth := SelectSlide.TextureSBG.W / NumHalftones;
- y1 := y1 + 1;
- y2 := y2 - 1;
-
- // draw tone boxes
- for i := 0 to NumHalftones-1 do
- begin
- x1 := SelectSlide.TextureSBG.X + i * ToneBoxWidth + 2;
- x2 := x1 + ToneBoxWidth - 4;
+ // dark player colors
+ State.RD := 0.2 * State.R;
+ State.GD := 0.2 * State.G;
+ State.BD := 0.2 * State.B;
- if ((PreviewChannel[ChannelIndex].ToneValid) and
- (PreviewChannel[ChannelIndex].ToneAbs = i)) then
- begin
- // highlight current tone-pitch
- glColor3f(1, i / (NumHalftones-1), 0)
- end
- else
- begin
- // grey other tone-pitches
- glColor3f(0.3, i / (NumHalftones-1) * 0.3, 0);
- end;
+ // channel select slide
+ SelectSlide := SelectsS[SelectSlideChannelID[ChannelIndex]];
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
- glVertex2f(x2, y2);
- glVertex2f(x1, y2);
- end;
+ BarXOffset := SelectSlide.TextureSBG.X;
+ BarYOffset := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H + BarUpperSpacing;
+ BarWidth := SelectSlide.TextureSBG.W;
- // update tone-pitch label
- Text[TextPitchID[ChannelIndex]].Text :=
- PreviewChannel[ChannelIndex].ToneString;
- end;
- glEnd;
+ State.ChannelIndex := ChannelIndex;
+
+ DrawVUMeter(State, BarXOffset, BarYOffset, BarWidth, BarHeight);
+ DrawPitch(State, BarXOffset, BarYOffset+BarHeight, BarWidth, BarHeight);
+ end;
+
+ glDisable(GL_BLEND);
end;
Result := True;
diff --git a/Game/Code/Screens/UScreenOptionsSound.pas b/Game/Code/Screens/UScreenOptionsSound.pas
index c3ef523b..2d807d02 100644
--- a/Game/Code/Screens/UScreenOptionsSound.pas
+++ b/Game/Code/Screens/UScreenOptionsSound.pas
@@ -87,7 +87,7 @@ begin
AddSelect(Theme.OptionsSound.SelectMicBoost, Ini.MicBoost, IMicBoost); // TODO - This need moving to ScreenOptionsRecord
AddSelect(Theme.OptionsSound.SelectClickAssist, Ini.ClickAssist, IClickAssist);
AddSelect(Theme.OptionsSound.SelectBeatClick, Ini.BeatClick, IBeatClick);
- AddSelect(Theme.OptionsSound.SelectThreshold, Ini.Threshold, IThreshold);
+ AddSelect(Theme.OptionsSound.SelectThreshold, Ini.ThresholdIndex, IThreshold);
//Song Preview
AddSelectSlide(Theme.OptionsSound.SelectSlidePreviewVolume, Ini.PreviewVolume, IPreviewVolume);
diff --git a/Game/Code/Screens/UScreenSong.pas b/Game/Code/Screens/UScreenSong.pas
index e52b4c98..82d5100a 100644
--- a/Game/Code/Screens/UScreenSong.pas
+++ b/Game/Code/Screens/UScreenSong.pas
@@ -34,6 +34,8 @@ type
EqualizerData: TFFTData; // moved here to avoid stack overflows
EqualizerBands: array of Byte;
EqualizerTime: Cardinal;
+
+ procedure StartMusicPreview(Song: TSong);
public
TextArtist: integer;
TextTitle: integer;
@@ -51,6 +53,8 @@ type
HighSpeed: boolean;
CoverFull: boolean;
CoverTime: real;
+ MusicStartTime: cardinal;
+
CoverX: integer;
CoverY: integer;
CoverW: integer;
@@ -1454,19 +1458,8 @@ begin
if Length(CatSongs.Song) > 0 then begin
//Load Music only when Song Preview is activated
if ( Ini.PreviewVolume <> 0 ) then
- begin
- if(AudioPlayback.Open(CatSongs.Song[Interaction].Path + CatSongs.Song[Interaction].Mp3)) then
- begin
- AudioPlayback.SetLoop(false);
- AudioPlayback.Position := AudioPlayback.Length / 4;
- AudioPlayback.Play;
-
- //Set Preview Volume
- AudioPlayback.SetMusicVolume (Ini.PreviewVolume * 10);
- {//if Music Fade is activated, Set Volume to 0 %
- if (Ini.PreviewFading <> 0) then
- Music.SetMusicVolume(0);}
- end;
+ begin // to - do : new Song management
+ StartMusicPreview(CatSongs.Song[Interaction]);
end;
SetScroll;
@@ -1506,7 +1499,7 @@ procedure TScreenSong.onHide;
begin
//When Music Fading is activated, Turn Music to 100 %
If (Ini.PreviewVolume <> 100) or (Ini.PreviewFading <> 0) then
- AudioPlayback.SetMusicVolume(100);
+ AudioPlayback.SetVolume(100);
//If Preview is deactivated: Load MUsicfile now
If (Ini.PreviewVolume = 0) then
@@ -1557,7 +1550,7 @@ begin
//Fading Functions, Only if Covertime is under 5 Seconds
If (CoverTime < 5) then
begin
- // 0.5.0: cover fade
+ // cover fade
if (CoverTime < 1) and (CoverTime + TimeSkip >= 1) then
begin
// load new texture
@@ -1568,18 +1561,17 @@ begin
end;
//Song Fade
- if (CatSongs.VisibleSongs > 0) AND (Ini.PreviewVolume <> 0) AND (Not CatSongs.Song[Interaction].Main) AND (Ini.PreviewFading <> 0) then
+ if (CatSongs.VisibleSongs > 0) and
+ (not CatSongs.Song[Interaction].Main) and
+ (Ini.PreviewVolume <> 0) and
+ (Ini.PreviewFading <> 0) then
begin
//Start Song Fade after a little Time, to prevent Song to be Played on Scrolling
- if (CoverTime < 0.2) and (CoverTime + TimeSkip >= 0.2) then
- AudioPlayback.Play;
-
- //Update Song Volume
- if (CoverTime < Ini.PreviewFading) then
- AudioPlayback.SetMusicVolume(Round (CoverTime * Ini.PreviewVolume / Ini.PreviewFading * 10))
- else
- AudioPlayback.SetMusicVolume(Ini.PreviewVolume * 10);
-
+ if ((MusicStartTime > 0) and (SDL_GetTicks() >= MusicStartTime)) then
+ begin
+ MusicStartTime := 0;
+ StartMusicPreview(CatSongs.Song[Interaction]);
+ end;
end;
@@ -1588,7 +1580,8 @@ begin
//Update Fading Texture
Button[Interaction].Texture2.Alpha := (CoverTime - 1) * 1.5;
- if Button[Interaction].Texture2.Alpha > 1 then Button[Interaction].Texture2.Alpha := 1;
+ if Button[Interaction].Texture2.Alpha > 1 then
+ Button[Interaction].Texture2.Alpha := 1;
end;
@@ -1694,30 +1687,52 @@ begin
end;
*)
+procedure TScreenSong.StartMusicPreview(Song: TSong);
+begin
+ AudioPlayback.Close();
+
+ if not assigned(Song) then
+ Exit;
+
+ if AudioPlayback.Open(Song.Path + Song.Mp3) then
+ begin
+ AudioPlayback.Position := AudioPlayback.Length / 4;
+ // set preview volume
+ if (Ini.PreviewFading = 0) then
+ begin
+ // music fade disabled: start with full volume
+ AudioPlayback.SetVolume(Ini.PreviewVolume * 10);
+ AudioPlayback.Play()
+ end
+ else
+ begin
+ // music fade enabled: start muted and fade-in
+ AudioPlayback.SetVolume(0);
+ AudioPlayback.FadeIn(Ini.PreviewFading, Ini.PreviewVolume * 10);
+ end;
+ end;
+end;
+
//Procedure Change current played Preview
procedure TScreenSong.ChangeMusic;
begin
//When Music Preview is avtivated -> then Change Music
if (Ini.PreviewVolume <> 0) then
begin
- if (NOT CatSongs.Song[Interaction].Main) AND(CatSongs.VisibleSongs > 0) then
+ // Stop previous song
+ AudioPlayback.Stop;
+ // Disable music start delay
+ MusicStartTime := 0;
+
+ if (CatSongs.VisibleSongs > 0) then
begin
- AudioPlayback.Close;
- if AudioPlayback.Open(CatSongs.Song[Interaction].Path + CatSongs.Song[Interaction].Mp3) then begin
- AudioPlayback.Position := AudioPlayback.Length / 4;
- //If Song Fading is activated then don't Play directly, and Set Volume to Null, else Play normal
- if (Ini.PreviewFading = 0) then
- AudioPlayback.Play
- else
- AudioPlayback.SetMusicVolume(0);
- end;
- end
- else
- AudioPlayback.Stop;
+ // delay start of music for 200ms (see Draw())
+ MusicStartTime := SDL_GetTicks() + 200;
+ end;
end;
end;
-procedure TScreenSong.SkipTo(Target: Cardinal); // 0.5.0
+procedure TScreenSong.SkipTo(Target: Cardinal);
var
// Skip: integer; // Auto Removed, Unused Variable
I: integer;