double scaleOffset = 1;//0.997; public MainWindow() { dx11 = new DXWPF.D3D11(); dx11.SingleThreadedRender = true; scene = new ImgScene() { Renderer = dx11 }; midiOutput = new OutputDevice(0); InitializeComponent(); SourceInitialized += (s, e) => { IntPtr handle = (new WindowInteropHelper(this)).Handle; HwndSource.FromHwnd(handle).AddHook(new HwndSourceHook(WindowProc)); }; for (int i = 0; i < 128; i++) { var k = 127 - i; DockPanel d = new DockPanel(); Grid key = new Grid(); key.SetBinding(Grid.WidthProperty, new Binding("ActualWidth") { Source = keyboardBox }); Storyboard storyboard = new Storyboard(); if (isBlackNote(k)) { Panel.SetZIndex(d, 10); SolidColorBrush keycolbrush = new SolidColorBrush(Colors.Black); var bord = new Border() { Background = keycolbrush, Margin = new Thickness(70, 0, 0, 0) }; key.Children.Add(bord); var keyCol = new ColorAnimation(Color.FromArgb(255, 0, 0, 250), Colors.Black, new Duration(TimeSpan.FromSeconds(0.5))); storyboard.Children.Add(keyCol); Storyboard.SetTarget(keyCol, bord); Storyboard.SetTargetProperty(keyCol, new PropertyPath("(Border.Background).(SolidColorBrush.Color)")); } else { Panel.SetZIndex(d, 0); SolidColorBrush keycolbrush = new SolidColorBrush(Colors.White); var bord = new Border() { Background = keycolbrush, BorderBrush = Brushes.Black, BorderThickness = new Thickness(1) }; key.Children.Add(bord); var keyCol = new ColorAnimation(Color.FromArgb(255, 50, 50, 255), Colors.White, new Duration(TimeSpan.FromSeconds(0.5))); storyboard.Children.Add(keyCol); Storyboard.SetTarget(keyCol, bord); Storyboard.SetTargetProperty(keyCol, new PropertyPath("(Border.Background).(SolidColorBrush.Color)")); var n = k % 12; Func <double, Thickness> conv = (v) => new Thickness(0); if (n == 11) { conv = (v) => new Thickness(0, 0, 0, -v * 3 / 4); } if (n == 9) { conv = (v) => new Thickness(0, -v / 4, 0, -v / 2); } if (n == 7) { conv = (v) => new Thickness(0, -v / 2, 0, -v / 4); } if (n == 5) { conv = (v) => new Thickness(0, -v * 3 / 4, 0, 0); } if (n == 4) { conv = (v) => new Thickness(0, 0, 0, -v * 2 / 3); } if (n == 2) { conv = (v) => new Thickness(0, -v / 3, 0, -v / 3); } if (n == 0) { conv = (v) => new Thickness(0, -v * 2 / 3, 0, 0); } new InplaceConverter(new[] { new Binding("ActualHeight") { Source = d } }, (args) => conv((double)args[0])).Set(key, MarginProperty); } SolidColorBrush linecolbrush = new SolidColorBrush(Colors.Transparent); Border b = new Border() { BorderBrush = new SolidColorBrush(Color.FromArgb(50, 50, 50, 255)), BorderThickness = new Thickness(0, 1, 0, 1), Background = linecolbrush }; var lineCol = new ColorAnimation(Color.FromArgb(50, 50, 50, 255), Colors.Transparent, new Duration(TimeSpan.FromSeconds(0.5))); storyboard.Children.Add(lineCol); Storyboard.SetTarget(lineCol, b); Storyboard.SetTargetProperty(lineCol, new PropertyPath("(Border.Background).(SolidColorBrush.Color)")); //var h = new DoubleAnimation(0, 20, new Duration(TimeSpan.FromSeconds(0.5))); //storyboard.Children.Add(h); //Storyboard.SetTarget(h, d); //Storyboard.SetTargetProperty(h, new PropertyPath(HeightProperty)); keyPressAnimations.Add(storyboard); d.Children.Add(key); d.Children.Add(b); d.SetBinding(HeightProperty, new Binding("LayerHeight") { Source = this }); layersContainer.Children.Add(d); d.Tag = k; d.PreviewMouseDown += (s, e) => { if (Keyboard.IsKeyDown(Key.LeftCtrl)) { var pos = e.GetPosition(contentGrid); var scaled = pos.X / contentGrid.ActualWidth * (scene.HorizontalScale.Right - scene.HorizontalScale.Left) + scene.HorizontalScale.Left; scaled *= scaleOffset; var finalPos = (long)(scaled * (fileReader.Length / fileReader.WaveFormat.Channels)) * fileReader.WaveFormat.Channels; if (finalPos > fileReader.Length) { finalPos = fileReader.Length; } if (finalPos < 0) { finalPos = 0; } fileReader.Position = finalPos; return; } PlayKey((int)d.Tag); keyPressAnimations[127 - (int)d.Tag].Begin(); }; } new InplaceConverter(new[] { new Binding("VerticalScale") { Source = this }, new Binding("ActualHeight") { Source = containerGrid } }, (b) => { var scale = (VScale)b[0]; var height = scale.Bottom - scale.Top; var layerHeight = (double)b[1] / height; return(layerHeight); }).Set(this, LayerHeightProperty); new InplaceConverter(new[] { new Binding("VerticalScale") { Source = this }, new Binding("ActualHeight") { Source = containerGrid } }, (b) => { var scale = (VScale)b[0]; var height = scale.Bottom - scale.Top; var layerHeight = (double)b[1] / height; var topMargin = LayerHeight * scale.Top; return(new Thickness(0, -topMargin, 0, 0)); }).Set(layersContainer, MarginProperty); imgRender.Renderer = scene; string path; var open = new OpenFileDialog(); open.Filter = "All Files|*.*"; if ((bool)open.ShowDialog()) { path = open.FileName; } else { throw new Exception(); } scene.LoadTexture(LoadSong(path)); var fr = new MediaFoundationDecoder(path); MemoryStream cache = new MemoryStream(); fr.WriteToWaveStream(cache); cache.Position = 0; fileReader = new WaveFileReader(cache); waveOut = GetSoundOut(); waveOut.Initialize(fileReader); }
float[,] LoadSong(string path) { IWaveSource reader = new MediaFoundationDecoder(path); var sampleRate = reader.WaveFormat.SampleRate; reader = reader.ToMono(); MemoryStream cache = new MemoryStream(); reader.WriteToWaveStream(cache); cache.Position = 0; reader.Dispose(); reader = new WaveFileReader(cache); var r = reader.ToSampleSource(); // Samples per key var fftSamplesPerKey = 10; // Width of the array var fftWidth = 10000; // Number of subdivisions in each sample group // Higher = more precise var precisionMultiplier = 5; // Wavelengths in each sample // Higher = more precise var wavelengthsPerSample = 20; var fftResultLen = 128 * fftSamplesPerKey; int len = (int)(reader.Length / 2); var result = new float[fftWidth, fftResultLen]; var datafull = new float[(int)len]; r.Read(datafull, 0, (int)len); r.Dispose(); int progress = 0; object lck = new object(); Stopwatch s = new Stopwatch(); s.Start(); Parallel.For(0, fftResultLen, i => { float key = i / (float)fftSamplesPerKey - 0.5f / fftSamplesPerKey; float freq = (float)Math.Pow(2, (key - 69 + 9 - 7 * 3 + 12 * 1) / 12) * 440; int waveSize = (int)(sampleRate / freq) * wavelengthsPerSample; double waveStep = (double)waveSize * fftWidth / len; waveStep /= precisionMultiplier; if (waveStep < 1) { waveStep = 1; } waveStep = waveStep / fftWidth * len; if (waveSize < 1000) { waveSize = 1000; } for (double _l = 0; _l + waveSize < len; _l += waveStep) { var l = (int)_l; float mult = freq / sampleRate * (float)Math.PI * 2; float sum_r = 0; float sum_i = 0; for (int j = 0; j < waveSize; j++) { float a = mult * j + (float)Math.PI; sum_r += (float)Math.Cos(a) * datafull[l + j]; sum_i += (float)Math.Sin(a) * datafull[l + j]; } var val = (Math.Abs(sum_r) + Math.Abs(sum_i)) / waveSize; int start = (int)((double)l * fftWidth / len); int end = (int)((double)(l + waveSize) * fftWidth / len); for (int p = start; p <= end; p++) { result[p, i] = val; } } lock (lck) { Console.WriteLine("Processed frequency bands: " + (++progress)); } }); Console.WriteLine("Complete! Seconds spent: " + Math.Round(s.ElapsedMilliseconds / 1000.0, 1)); return(result); }
float[,] LoadSong(string path) { IWaveSource reader = new MediaFoundationDecoder(path); var sampleRate = reader.WaveFormat.SampleRate; reader = reader.ToMono(); MemoryStream cache = new MemoryStream(); reader.WriteToWaveStream(cache); cache.Position = 0; reader.Dispose(); reader = new WaveFileReader(cache); var r = reader.ToSampleSource(); // Samples per key var fftSamplesPerKey = 10; // Width of the array var fftWidth = 10000; // Number of subdivisions in each sample group // Higher = more precise var precisionMultiplier = 5; // Wavelengths in each sample // Higher = more precise var wavelengthsPerSample = 20; var fftResultLen = 128 * fftSamplesPerKey; int len = (int)(reader.Length / 2); var result = new float[fftWidth, fftResultLen]; var datafull = new float[(int)len]; r.Read(datafull, 0, (int)len); r.Dispose(); int progress = 0; object lck = new object(); Stopwatch s = new Stopwatch(); s.Start(); unsafe { fixed(float *input_ptr = datafull) { float *output_ptr = (float *)CudaFFT.process_audio((IntPtr)input_ptr, (ulong)len, (uint)sampleRate); ulong idx = 0; for (int x = 0; x < fftWidth; x++) { for (int y = 0; y < fftResultLen; y++) { result[x, y] = output_ptr[idx++]; } } } } Console.WriteLine("Complete! Seconds spent: " + Math.Round(s.ElapsedMilliseconds / 1000.0, 1)); return(result); }