diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 02ad6565..c7ba4df4 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -215,7 +215,7 @@ namespace Vocaluxe.Base // Record public static SMicConfig[] MicConfig; - public static int MicDelay = 200; //[ms] + public static int MicDelay = 300; //[ms] //Lists to save parameters and values private static List _Params = new List(); diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index 25d8ac8f..ad7e490d 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -16,6 +16,8 @@ namespace Vocaluxe.Base public string Name; public EGameDifficulty Difficulty; public double Points; + public double PointsLineBonus; + public double PointsGoldenNotes; public int NoteDiff; public int LineNr; public List SingLine; @@ -213,6 +215,8 @@ namespace Vocaluxe.Base for (int i = 0; i < _Player.Length; i++) { _Player[i].Points = 0f; + _Player[i].PointsLineBonus = 0f; + _Player[i].PointsGoldenNotes = 0f; _Player[i].LineNr = 0; _Player[i].NoteDiff = 0; _Player[i].SingLine = new List(); @@ -247,7 +251,7 @@ namespace Vocaluxe.Base CSound.AnalyzeBuffer(p); } - if (_OldBeatD == _CurrentBeatD) + if (_OldBeatD >= _CurrentBeatD) return; for (int p = 0; p < _NumPlayer; p++) @@ -321,8 +325,12 @@ namespace Vocaluxe.Base if (_Player[p].NoteDiff <= (2 - (int)_Player[p].Difficulty)) { // valid - CSound.RecordSetTone(p, Tone); - _Player[p].Points += (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[Note].PointsForBeat / (double)song.Notes.GetLines(_Player[p].LineNr).Points; + //CSound.RecordSetTone(p, Tone); + double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[Note].PointsForBeat / (double)song.Notes.GetLines(_Player[p].LineNr).Points; + if (notes[Note].NoteType == ENoteType.Golden) + _Player[p].PointsGoldenNotes += points; + + _Player[p].Points += points; // update player notes (sung notes) if (_Player[p].SingLine[Line].NoteCount > 0) @@ -342,11 +350,6 @@ namespace Vocaluxe.Base _Player[p].SingLine[Line].LastNote.IsPerfect(notes[Note]); _Player[p].SingLine[Line].IsPerfect(lines[Line]); - - if (_Player[p].SingLine[Line].PerfectLine) - { - _Player[p].Points += CSettings.LinebonusScore * (double)lines[Line].Points / (double)song.Notes.GetPoints(_Player[p].LineNr); - } } else { @@ -354,7 +357,7 @@ namespace Vocaluxe.Base { CNote nt = _Player[p].SingLine[Line].LastNote; if (nt.EndBeat + 1 != beat || nt.Hit) - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); else { if (nt.Tone == TonePlayer && nt.EndBeat + 1 == beat) @@ -363,17 +366,40 @@ namespace Vocaluxe.Base } else { - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); } } } else { - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, notes[Note].NoteType)); + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); } } } + + // Line Bonus + if (Note == lines[Line].NoteCount - 1) + { + if (notes[Note].EndBeat == beat) + { + double factor = (double)_Player[p].SingLine[Line].Points / (double)song.Notes.GetPoints(_Player[p].LineNr); + if (factor < 0.4) + factor = 0.0; + else if (factor > 0.9) + factor = 1.0; + else + { + factor -= 0.4; + factor *= 2; + factor *= factor; + } + + double points = CSettings.LinebonusScore * factor; + _Player[p].Points += points; + _Player[p].PointsLineBonus += points; + } + } } } diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 440d405d..4268cb57 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -237,6 +237,16 @@ namespace Vocaluxe.Base return _Record.GetMaxVolume(Player); } + public static int NumHalfTones(int Player) + { + return _Record.NumHalfTones(Player); + } + + public static float[] ToneWeigth(int Player) + { + return _Record.ToneWeigth(Player); + } + public static SRecordDevice[] RecordGetDevices() { SRecordDevice[] devices = _Record.RecordDevices(); @@ -281,10 +291,11 @@ namespace Vocaluxe.Base class CBuffer { - private const double BaseToneFreq = 65.4064; - private const int NumHalfTones = 47; + private const double _BaseToneFreq = 65.4064; + private const int _NumHalfTones = 47; - private Int16[] _AnalysisBuffer = new Int16[4096]; + private float[] _ToneWeigth; + private Int16[] _AnalysisBuffer = new Int16[4096 * 4]; private Object _AnalysisBufferLock = new Object(); private bool _ToneValid = false; @@ -295,6 +306,17 @@ namespace Vocaluxe.Base private MemoryStream _Stream; // full buffer + public CBuffer() + { + _ToneWeigth = new float[_NumHalfTones]; + _Stream = new MemoryStream(); + } + + public int NumHalfTones + { + get { return _NumHalfTones; } + } + public int ToneAbs { get @@ -346,11 +368,6 @@ namespace Vocaluxe.Base } } - public CBuffer() - { - _Stream = new MemoryStream(); - } - public long Length { get { return _Stream.Length; } @@ -361,6 +378,17 @@ namespace Vocaluxe.Base get { return _Stream.ToArray(); } } + public float[] ToneWeigth + { + get + { + lock (_AnalysisBufferLock) + { + return _ToneWeigth; + } + } + } + public void Reset() { _Stream.SetLength(0L); @@ -397,30 +425,25 @@ namespace Vocaluxe.Base lock (_AnalysisBufferLock) { - try - { - // move old samples to the beginning of the array (if necessary) - for (int i = 0; i < _AnalysisBuffer.Length - SampleCount; i++) - { - _AnalysisBuffer[i] = _AnalysisBuffer[i + SampleCount]; - } - - byte[] b = new byte[2]; - // copy new samples to analysis buffer - for (int i = 0; i < SampleCount; i++) - { - b[0] = buffer[BufferOffset + i * 2]; - b[1] = buffer[BufferOffset + i * 2 + 1]; - - _AnalysisBuffer[_AnalysisBuffer.Length - SampleCount + i] = BitConverter.ToInt16(b, 0); - } - } - catch (Exception) - { - - } Add(buffer); - _NewSamples = true; + + int len = _AnalysisBuffer.Length * 2; + if (_Stream.Length >= len) + { + byte[] buf = new byte[len]; + _Stream.Position -= len; + _Stream.Read(buf, 0, len); + + byte[] b = new byte[2]; + for (int i = 0; i < _AnalysisBuffer.Length; i++) + { + b[0] = buf[i * 2]; + b[1] = buf[i * 2 + 1]; + + _AnalysisBuffer[i] = BitConverter.ToInt16(b, 0); + } + _NewSamples = true; + } } } @@ -442,14 +465,10 @@ namespace Vocaluxe.Base _MaxVolume = Volume; } - if (_MaxVolume >= 0.05f) - { - // analyse the current voice pitch - AnalyzeByAutocorrelation(); - _ToneValid = true; - } + if (_MaxVolume >= 0.02f) + AnalyzeByAutocorrelation(true); else - _ToneValid = false; + AnalyzeByAutocorrelation(false); _NewSamples = false; } @@ -460,35 +479,67 @@ namespace Vocaluxe.Base } } - private void AnalyzeByAutocorrelation() + private void AnalyzeByAutocorrelation(bool valid) { const double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave) // prepare to analyze double MaxWeight = -1.0; - int MaxTone = 0; + double MinWeight = 1.0; + int MaxTone = -1; + float[] Weigth = new float[_NumHalfTones]; // analyze halftones // Note: at the lowest tone (~65Hz) and a buffer-size of 4096 // at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be // too few samples -> use a bigger buffer-size - for (int ToneIndex = 0; ToneIndex < NumHalfTones; ToneIndex++) + for (int ToneIndex = 0; ToneIndex < _NumHalfTones; ToneIndex++) { - double CurFreq = BaseToneFreq * Math.Pow(HalftoneBase, ToneIndex); + double CurFreq = _BaseToneFreq * Math.Pow(HalftoneBase, ToneIndex); double CurWeight = AnalyzeAutocorrelationFreq(CurFreq); - // TODO: prefer higher frequencies (use >= or use downto) - if (CurWeight > MaxWeight /* && (Math.Abs(ToneIndex - _ToneAbs) < 5 || _ToneAbs == 0)*/) - { - // this frequency has a higher weight + if (CurWeight > MaxWeight) MaxWeight = CurWeight; - MaxTone = ToneIndex; - } + + if (CurWeight < MinWeight) + MinWeight = CurWeight; + + Weigth[ToneIndex] = (float)CurWeight; } - _ToneAbs = MaxTone; - _Tone = MaxTone % 12; + if (valid && MaxWeight - MinWeight > 0.01) + { + int m = -1; + float prev = -1f; + bool raising = false; + for (int i = 0; i < Weigth.Length; i++) + { + if (i > 0 && Weigth[i] > prev) + raising = true; + + if (Weigth[i] < prev && raising) + { + m = i-1; + MaxTone = i-1; + raising = false; + } + + prev = Weigth[i]; + _ToneWeigth[i] = Weigth[i]; + } + + if (m != -1) + { + _ToneAbs = MaxTone; + _Tone = MaxTone % 12; + _ToneValid = true; + } + else + _ToneValid = false; + } + else + _ToneValid = false; } private double AnalyzeAutocorrelationFreq(double Freq) diff --git a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs index a55a28d0..d61e06bc 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs @@ -249,6 +249,22 @@ namespace Vocaluxe.Lib.Sound return _Buffer[Player].ToneValid; } + public int NumHalfTones(int Player) + { + if (!_initialized) + return 0; + + return _Buffer[Player].NumHalfTones; + } + + public float[] ToneWeigth(int Player) + { + if (!_initialized) + return null; + + return _Buffer[Player].ToneWeigth; + } + public SRecordDevice[] RecordDevices() { if (!_initialized) diff --git a/Vocaluxe/Lib/Sound/IRecord.cs b/Vocaluxe/Lib/Sound/IRecord.cs index e4b9cc2b..3b664a71 100644 --- a/Vocaluxe/Lib/Sound/IRecord.cs +++ b/Vocaluxe/Lib/Sound/IRecord.cs @@ -51,6 +51,8 @@ namespace Vocaluxe.Lib.Sound void SetTone(int Player, int Tone); float GetMaxVolume(int Player); bool ToneValid(int Player); + int NumHalfTones(int Player); + float[] ToneWeigth(int Player); SRecordDevice[] RecordDevices(); } diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 4426b7af..79b9985d 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -51,6 +51,8 @@ namespace Vocaluxe.Screens private bool _DelayTestRunning; private int _DelaySound; + private Equalizer[] _Equalizer; + public CScreenOptionsRecord() { Init(); @@ -274,20 +276,27 @@ namespace Vocaluxe.Screens if (player > 0) { ChannelEnergy[0] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[0].Update(CSound.ToneWeigth(player - 1)); } + else + _Equalizer[0].Reset(); ChannelEnergy[1] = 0f; player = SelectSlides[htSelectSlides(SelectSlideRecordChannel2)].Selection; if (player > 0) { ChannelEnergy[1] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[1].Update(CSound.ToneWeigth(player - 1)); } + else + _Equalizer[1].Reset(); } else { for (int i = 0; i < ChannelEnergy.Length; i++) { ChannelEnergy[i] = 0f; + _Equalizer[i].Reset(); } } @@ -351,6 +360,13 @@ namespace Vocaluxe.Screens _DelayTestRunning = false; _DelaySound = -1; + + _Equalizer = new Equalizer[2]; + + for (int i = 0; i < _Equalizer.Length; i++) + { + _Equalizer[i] = new Equalizer(new SRectF(50 + 350 * i, 400, 230, 150, -1), CSound.NumHalfTones(0), 2); + } } public override void OnShowFinish() @@ -389,6 +405,11 @@ namespace Vocaluxe.Screens } } + for (int i = 0; i < _Equalizer.Length; i++) + { + _Equalizer[i].Draw(); + } + DrawFG(); return true; @@ -571,4 +592,88 @@ namespace Vocaluxe.Screens } } } + + class Equalizer + { + + private SRectF _Bounds; + private float _Space; + + private float[] _Bars; + + public Equalizer(SRectF bounds, int numBars, float space) + { + _Bounds = bounds; + _Space = space; + + if (numBars > 0) + _Bars = new float[numBars]; + } + + public void Update(float[] weights) + { + if (weights == null || weights.Length == 0 || _Bars == null) + return; + + if (_Bars.Length < weights.Length) + { + } + else if (_Bars.Length > weights.Length) + { + } + else + { + for (int i = 0; i < _Bars.Length; i++) + { + //if (weights[i] > 0) + _Bars[i] = weights[i]; + //else + // _Bars[i] = 0f; + } + } + } + + public void Reset() + { + if (_Bars == null || _Bars.Length == 0) + return; + + for (int i = 0; i < _Bars.Length; i++) + { + _Bars[i] = 0f; + } + } + + public void Draw() + { + if (_Bars == null) + return; + + float dx = _Bounds.W / _Bars.Length + _Space; + int max = _Bars.Length - 1; + float maxB = _Bars[max]; + for (int i = 0; i < _Bars.Length - 1; i++) + { + if (_Bars[i] > maxB) + { + maxB = _Bars[i]; + max = i; + } + } + + + for (int i = 0; i < _Bars.Length; i++) + { + SRectF bar = new SRectF(_Bounds.X + dx * i, _Bounds.Y + _Bounds.H - _Bars[i] * _Bounds.H, dx - _Space, _Bars[i] * _Bounds.H, _Bounds.Z); + SColorF color = new SColorF(1f, 1f, 1f, 1f); + if (i == max) + { + color.B = 0f; + color.G = 0f; + } + + CDraw.DrawColor(color, bar); + } + } + } }