aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--game/languages/English.ini3
-rw-r--r--game/languages/German.ini3
-rw-r--r--src/base/URecord.pas93
-rw-r--r--src/screens/UScreenSing.pas10
4 files changed, 94 insertions, 15 deletions
diff --git a/game/languages/English.ini b/game/languages/English.ini
index c03294b5..d9828b45 100644
--- a/game/languages/English.ini
+++ b/game/languages/English.ini
@@ -430,4 +430,5 @@ ERROR_CORRUPT_SONG_NO_NOTES=Song could not be loaded: Can''t find any notes
ERROR_CORRUPT_SONG_NO_BREAKS=Song could not be loaded: Can''t find any linebreaks
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Song could not be loaded: Error parsing line %0:d
ERROR_NO_EDITOR=This feature is not available on Linux/Mac
-ERROR_PLAYER_DEVICE_ASSIGNMENT=Player %d was assigned to multiple microphones. Please check your record options
+ERROR_PLAYER_DEVICE_ASSIGNMENT=Player %d is assigned to multiple microphones. Please check your record options
+ERROR_PLAYER_NO_DEVICE_ASSIGNMENT=Player %d is not assigned to a microphones. Please check your record options
diff --git a/game/languages/German.ini b/game/languages/German.ini
index 346e03de..6e614c7c 100644
--- a/game/languages/German.ini
+++ b/game/languages/German.ini
@@ -429,4 +429,5 @@ ERROR_CORRUPT_SONG_NO_NOTES=Song konnte nicht geladen werden: Es wurden keine No
ERROR_CORRUPT_SONG_NO_BREAKS=Song konnte nicht geladen werden: Es wurden keine Satzwechsel gefunden.
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Song konnte nicht geladen werden: Fehler beim parsen der Zeile %0:d
ERROR_NO_EDITOR=Diese Funktion ist unter Linux/Mac noch nicht verfügbar
-ERROR_PLAYER_DEVICE_ASSIGNMENT=Mehrere Mikrofone für Spieler %d gewählt.\nAufnahmeoptionen überprüfen. \ No newline at end of file
+ERROR_PLAYER_DEVICE_ASSIGNMENT=Mehrere Mikrofone für Spieler %d gewählt.\nAufnahmeoptionen überprüfen.
+ERROR_PLAYER_NO_DEVICE_ASSIGNMENT=Kein Mikrofon für Spieler %d gewählt.\nAufnahmeoptionen überprüfen.
diff --git a/src/base/URecord.pas b/src/base/URecord.pas
index c183875c..5d2b4666 100644
--- a/src/base/URecord.pas
+++ b/src/base/URecord.pas
@@ -124,6 +124,8 @@ type
procedure SetVolume(Volume: single); virtual; abstract;
end;
+ TBooleanDynArray = array of boolean;
+
TAudioInputProcessor = class
public
Sound: array of TCaptureBuffer; // sound-buffers for every player
@@ -133,9 +135,29 @@ type
destructor Destroy; override;
procedure UpdateInputDeviceConfig;
+
+ {**
+ * Validates the mic settings.
+ * If a player was assigned to multiple mics a popup will be displayed
+ * with the ID of the player and the return value will be false.
+ *}
function ValidateSettings: boolean;
- // handle microphone input
+ {**
+ * Checks if players 1 to PlayerCount are configured correctly.
+ * A player is configured if a device's channel is assigned to him.
+ * For each player (up to PlayerCount) the state will be in PlayerState.
+ * If a player's state is true the player is configured, otherwise not.
+ * The return value is the player number of the first player that is not
+ * configured correctly or 0 if all players are correct.
+ * The PlayerState array is zero based (index 0 for player 1).
+ *}
+ function CheckPlayersConfig(PlayerCount: cardinal;
+ var PlayerState: TBooleanDynArray): integer;
+
+ {**
+ * Handle microphone input
+ *}
procedure HandleMicrophoneData(Buffer: PByteArray; Size: integer;
InputDevice: TAudioInputDevice);
end;
@@ -555,10 +577,10 @@ begin
channelIndex := High(deviceCfg.ChannelToPlayerMap);
// add missing channels or remove non-existing ones
SetLength(deviceCfg.ChannelToPlayerMap, device.AudioFormat.Channels);
- // initialize added channels to 0
+ // assign added channels to no player
for i := channelIndex+1 to High(deviceCfg.ChannelToPlayerMap) do
begin
- deviceCfg.ChannelToPlayerMap[i] := 0;
+ deviceCfg.ChannelToPlayerMap[i] := CHANNEL_OFF;
end;
// associate ini-index with device
@@ -587,11 +609,11 @@ begin
for channelIndex := 0 to channelCount-1 do
begin
- // set default at first start of USDX (1st device, 1st channel -> player1)
- if ((channelIndex = 0) and (device.CfgIndex = 0)) then
- deviceCfg.ChannelToPlayerMap[0] := 1
- else
- deviceCfg.ChannelToPlayerMap[channelIndex] := 0;
+ // Do not set any default on first start of USDX.
+ // Otherwise most probably the wrong device (internal sound card)
+ // will be selected.
+ // It is better to force the user to configure the mics himself.
+ deviceCfg.ChannelToPlayerMap[channelIndex] := CHANNEL_OFF;
end;
end;
end;
@@ -603,7 +625,7 @@ const
var
I, J: integer;
PlayerID: integer;
- PlayerMap: array [0 .. MAX_PLAYER_COUNT] of boolean;
+ PlayerMap: array [0 .. MAX_PLAYER_COUNT - 1] of boolean;
InputDevice: TAudioInputDevice;
InputDeviceCfg: PInputDeviceConfig;
begin
@@ -621,10 +643,10 @@ begin
begin
// get player that was mapped to the current device channel
PlayerID := InputDeviceCfg.ChannelToPlayerMap[J];
- if (PlayerID <> 0) then
+ if (PlayerID <> CHANNEL_OFF) then
begin
// check if player is already assigned to another device/channel
- if (PlayerMap[PlayerID]) then
+ if (PlayerMap[PlayerID - 1]) then
begin
ScreenPopupError.ShowPopup(
Format(Language.Translate('ERROR_PLAYER_DEVICE_ASSIGNMENT'),
@@ -634,13 +656,58 @@ begin
end;
// mark player as assigned to a device
- PlayerMap[PlayerID] := true;
+ PlayerMap[PlayerID - 1] := true;
end;
end;
end;
Result := true;
end;
+function TAudioInputProcessor.CheckPlayersConfig(PlayerCount: cardinal;
+ var PlayerState: TBooleanDynArray): integer;
+var
+ DeviceIndex: integer;
+ ChannelIndex: integer;
+ Device: TAudioInputDevice;
+ DeviceCfg: PInputDeviceConfig;
+ PlayerIndex: integer;
+ I: integer;
+begin
+ SetLength(PlayerState, PlayerCount);
+ // set all entries to "not configured"
+ for I := 0 to High(PlayerState) do
+ begin
+ PlayerState[I] := false;
+ end;
+
+ // check each used device
+ for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do
+ begin
+ Device := AudioInputProcessor.DeviceList[DeviceIndex];
+ if not assigned(Device) then
+ continue;
+ DeviceCfg := @Ini.InputDeviceConfig[Device.CfgIndex];
+
+ // check if device is used
+ for ChannelIndex := 0 to High(DeviceCfg.ChannelToPlayerMap) do
+ begin
+ PlayerIndex := DeviceCfg.ChannelToPlayerMap[ChannelIndex] - 1;
+ if (PlayerIndex >= 0) and (PlayerIndex < PlayerCount) then
+ PlayerState[PlayerIndex] := true;
+ end;
+ end;
+
+ Result := 0;
+ for I := 0 to High(PlayerState) do
+ begin
+ if (PlayerState[I] = false) then
+ begin
+ Result := I + 1;
+ Break;
+ end;
+ end;
+end;
+
{*
* Handles captured microphone input data.
* Params:
@@ -737,7 +804,7 @@ begin
// check if device is used
for ChannelIndex := 0 to High(DeviceCfg.ChannelToPlayerMap) do
begin
- Player := DeviceCfg.ChannelToPlayerMap[ChannelIndex]-1;
+ Player := DeviceCfg.ChannelToPlayerMap[ChannelIndex] - 1;
if (Player < 0) or (Player >= PlayersPlay) then
begin
Device.LinkCaptureBuffer(ChannelIndex, nil);
diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas
index 67855e77..aa32dd4a 100644
--- a/src/screens/UScreenSing.pas
+++ b/src/screens/UScreenSing.pas
@@ -370,6 +370,8 @@ var
Color: TRGB;
VideoFile, BgFile: IPath;
success: boolean;
+ PlayerState: TBooleanDynArray;
+ BadPlayer: integer;
begin
inherited;
@@ -585,6 +587,14 @@ begin
LyricsState.TotalTime := AudioPlayback.Length;
LyricsState.UpdateBeats();
+ BadPlayer := AudioInputProcessor.CheckPlayersConfig(PlayersPlay, PlayerState);
+ if (BadPlayer <> 0) then
+ begin
+ ScreenPopupError.ShowPopup(
+ Format(Language.Translate('ERROR_PLAYER_NO_DEVICE_ASSIGNMENT'),
+ [BadPlayer]));
+ end;
+
// prepare and start voice-capture
AudioInput.CaptureStart;