From 9448e4054bbe25a9d023e94e6b826683b285789b Mon Sep 17 00:00:00 2001 From: Alexander Eckart Date: Wed, 11 Apr 2012 16:53:59 +0200 Subject: [PATCH 1/3] just a simple equalizer for testing --- Vocaluxe/Base/CSound.cs | 67 +++++++++++++------ Vocaluxe/Lib/Sound/CPortAudioRecord.cs | 16 +++++ Vocaluxe/Lib/Sound/IRecord.cs | 2 + Vocaluxe/Screens/CScreenOptionsRecord.cs | 82 ++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 18 deletions(-) diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index 440d405d..0ccf4d07 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,9 +291,10 @@ 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 float[] _ToneWeigth; private Int16[] _AnalysisBuffer = new Int16[4096]; private Object _AnalysisBufferLock = new Object(); @@ -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); @@ -443,13 +471,9 @@ namespace Vocaluxe.Base } if (_MaxVolume >= 0.05f) - { - // analyse the current voice pitch - AnalyzeByAutocorrelation(); - _ToneValid = true; - } + AnalyzeByAutocorrelation(true); else - _ToneValid = false; + AnalyzeByAutocorrelation(false); _NewSamples = false; } @@ -460,7 +484,7 @@ namespace Vocaluxe.Base } } - private void AnalyzeByAutocorrelation() + private void AnalyzeByAutocorrelation(bool valid) { const double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave) @@ -473,9 +497,9 @@ namespace Vocaluxe.Base // 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) @@ -485,10 +509,17 @@ namespace Vocaluxe.Base MaxWeight = CurWeight; MaxTone = ToneIndex; } + _ToneWeigth[ToneIndex] = (float)CurWeight; } - _ToneAbs = MaxTone; - _Tone = MaxTone % 12; + if (valid) + { + _ToneAbs = MaxTone; + _Tone = MaxTone % 12; + _ToneValid = true; + } + else + _ToneValid = false; } private double AnalyzeAutocorrelationFreq(double Freq) diff --git a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs index 87bff1ab..b0ca8503 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioRecord.cs @@ -240,6 +240,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..89cb5291 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,6 +276,7 @@ namespace Vocaluxe.Screens if (player > 0) { ChannelEnergy[0] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[0].Update(CSound.ToneWeigth(player - 1)); } ChannelEnergy[1] = 0f; @@ -281,6 +284,7 @@ namespace Vocaluxe.Screens if (player > 0) { ChannelEnergy[1] = CSound.RecordGetMaxVolume(player - 1); + _Equalizer[1].Update(CSound.ToneWeigth(player - 1)); } } else @@ -288,6 +292,7 @@ namespace Vocaluxe.Screens for (int i = 0; i < ChannelEnergy.Length; i++) { ChannelEnergy[i] = 0f; + _Equalizer[i].Reset(); } } @@ -351,6 +356,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 + 300 * i, 400, 250, 150, -1), CSound.NumHalfTones(0), 1); + } } public override void OnShowFinish() @@ -389,6 +401,11 @@ namespace Vocaluxe.Screens } } + for (int i = 0; i < _Equalizer.Length; i++) + { + _Equalizer[i].Draw(); + } + DrawFG(); return true; @@ -571,4 +588,69 @@ namespace Vocaluxe.Screens } } } + + class Equalizer + { + + private SRectF _Bounds; + private float _Space; + + private float[] _Bars; + + public Equalizer(SRectF bounds, int numBars, float space) + { + _Bounds = bounds; + + 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; + + 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, _Bars[i] * _Bounds.H, _Bounds.Z); + CDraw.DrawColor(new SColorF(1f, 1f, 1f, 1f), bar); + } + } + } } From 9154243a7fa746d10b1bfc0409123cbc46f569b2 Mon Sep 17 00:00:00 2001 From: Alexander Eckart Date: Sat, 28 Apr 2012 12:50:39 +0200 Subject: [PATCH 2/3] some drawing changes and other improvements --- Vocaluxe/Base/CConfig.cs | 2 +- Vocaluxe/Base/CSound.cs | 37 +++++++++++++++++------- Vocaluxe/Screens/CScreenOptionsRecord.cs | 31 +++++++++++++++++--- 3 files changed, 55 insertions(+), 15 deletions(-) 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/CSound.cs b/Vocaluxe/Base/CSound.cs index 0ccf4d07..101e5da4 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -295,7 +295,7 @@ namespace Vocaluxe.Base private const int _NumHalfTones = 47; private float[] _ToneWeigth; - private Int16[] _AnalysisBuffer = new Int16[4096]; + private Int16[] _AnalysisBuffer = new Int16[4096*2]; private Object _AnalysisBufferLock = new Object(); private bool _ToneValid = false; @@ -490,7 +490,9 @@ namespace Vocaluxe.Base // 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 @@ -502,18 +504,33 @@ namespace Vocaluxe.Base 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; - } - _ToneWeigth[ToneIndex] = (float)CurWeight; + + if (CurWeight < MinWeight) + MinWeight = CurWeight; + + Weigth[ToneIndex] = (float)CurWeight; } - if (valid) + if (valid && MaxWeight - MinWeight > 0.05) { + int m = -1; + float prev = 0f; + for (int i = 0; i < Weigth.Length; i++) + { + if (Weigth[i] < prev && i > 0) + { + m = i; + MaxTone = i; + } + + if (i == Weigth.Length - 1 && m == -1) + MaxTone = i; + + prev = Weigth[i]; + _ToneWeigth[i] = Weigth[i]; + } _ToneAbs = MaxTone; _Tone = MaxTone % 12; _ToneValid = true; diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index 89cb5291..79b9985d 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -278,6 +278,8 @@ namespace Vocaluxe.Screens 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; @@ -286,6 +288,8 @@ namespace Vocaluxe.Screens ChannelEnergy[1] = CSound.RecordGetMaxVolume(player - 1); _Equalizer[1].Update(CSound.ToneWeigth(player - 1)); } + else + _Equalizer[1].Reset(); } else { @@ -361,7 +365,7 @@ namespace Vocaluxe.Screens for (int i = 0; i < _Equalizer.Length; i++) { - _Equalizer[i] = new Equalizer(new SRectF(50 + 300 * i, 400, 250, 150, -1), CSound.NumHalfTones(0), 1); + _Equalizer[i] = new Equalizer(new SRectF(50 + 350 * i, 400, 230, 150, -1), CSound.NumHalfTones(0), 2); } } @@ -600,6 +604,7 @@ namespace Vocaluxe.Screens public Equalizer(SRectF bounds, int numBars, float space) { _Bounds = bounds; + _Space = space; if (numBars > 0) _Bars = new float[numBars]; @@ -644,12 +649,30 @@ namespace Vocaluxe.Screens if (_Bars == null) return; - float dx = _Bounds.W / _Bars.Length; + 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, _Bars[i] * _Bounds.H, _Bounds.Z); - CDraw.DrawColor(new SColorF(1f, 1f, 1f, 1f), bar); + 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); } } } From 2c4e0d87081250187dd1d2aae28d347ba52bb64a Mon Sep 17 00:00:00 2001 From: Alexander Eckart Date: Mon, 30 Apr 2012 14:25:15 +0200 Subject: [PATCH 3/3] some more test with pitch detection, new line bonus calculation --- Vocaluxe/Base/CGame.cs | 48 +++++++++++++++++++------ Vocaluxe/Base/CSound.cs | 77 +++++++++++++++++++++-------------------- 2 files changed, 77 insertions(+), 48 deletions(-) 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 101e5da4..4268cb57 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -295,7 +295,7 @@ namespace Vocaluxe.Base private const int _NumHalfTones = 47; private float[] _ToneWeigth; - private Int16[] _AnalysisBuffer = new Int16[4096*2]; + private Int16[] _AnalysisBuffer = new Int16[4096 * 4]; private Object _AnalysisBufferLock = new Object(); private bool _ToneValid = false; @@ -425,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; + } } } @@ -470,7 +465,7 @@ namespace Vocaluxe.Base _MaxVolume = Volume; } - if (_MaxVolume >= 0.05f) + if (_MaxVolume >= 0.02f) AnalyzeByAutocorrelation(true); else AnalyzeByAutocorrelation(false); @@ -513,27 +508,35 @@ namespace Vocaluxe.Base Weigth[ToneIndex] = (float)CurWeight; } - if (valid && MaxWeight - MinWeight > 0.05) + if (valid && MaxWeight - MinWeight > 0.01) { int m = -1; - float prev = 0f; + float prev = -1f; + bool raising = false; for (int i = 0; i < Weigth.Length; i++) { - if (Weigth[i] < prev && i > 0) - { - m = i; - MaxTone = i; - } + if (i > 0 && Weigth[i] > prev) + raising = true; - if (i == Weigth.Length - 1 && m == -1) - MaxTone = i; + if (Weigth[i] < prev && raising) + { + m = i-1; + MaxTone = i-1; + raising = false; + } prev = Weigth[i]; _ToneWeigth[i] = Weigth[i]; } - _ToneAbs = MaxTone; - _Tone = MaxTone % 12; - _ToneValid = true; + + if (m != -1) + { + _ToneAbs = MaxTone; + _Tone = MaxTone % 12; + _ToneValid = true; + } + else + _ToneValid = false; } else _ToneValid = false;