// https://stackoverflow.com/questions/36081740/uwp-async-read-file-into-byte public static async Task <WaveData> LoadWave(StorageFile file) { byte[] wav; using (Stream stream = await file.OpenStreamForReadAsync()) { using (var memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); wav = memoryStream.ToArray(); } } int channels = wav[22]; int sampleRate = wav[24] + wav[25] * 256; int bitsPerSample = wav[34]; int pos = 12; while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97)) { pos += 4; int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216; pos += 4 + chunkSize; } pos += 8; // Pos is now positioned to start of actual sound data int samples = (wav.Length - pos) / 2; // 2 bytes per sample (16 bit sound mono) if (channels == 2) { samples /= 2; // 4 bytes per sample (16 bit stereo) } // Allocate memory (right will be null if only mono sound) var result = new WaveData { BitsPerSample = bitsPerSample, SampleRate = sampleRate, LeftChannel = new double[samples], RightChannel = channels == 2 ? new double[samples] : null }; int i = 0; while (pos < wav.Length) { result.LeftChannel[i] = WaveUtils.BytesToDouble(wav[pos], wav[pos + 1]); pos += 2; if (channels == 2) { result.RightChannel[i] = WaveUtils.BytesToDouble(wav[pos], wav[pos + 1]); pos += 2; } i++; } return(result); }
public async Task LoadWave(string filePath) { var picker = new Windows.Storage.Pickers.FileOpenPicker(); picker.FileTypeFilter.Add(".wav"); var file = await picker.PickSingleFileAsync(); var filename = file.Name; this.filenameTextBlock.Text = filename; this.Editor.WaveData = await WaveUtils.LoadWave(file); this.sampleRateTextBlock.Text = $"{this.Editor.WaveData.SampleRate.ToString()} Hz"; this.formatTextBlock.Text = $"{this.Editor.WaveData.BitsPerSample.ToString()}-bit"; }
// https://stackoverflow.com/questions/39605118/how-to-draw-an-audio-waveform-to-a-bitmap private void canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args) { if (Editor.WaveData.LeftChannel == null) { return; } const int FONT_SIZE = 14; args.DrawingSession.Clear(sender.ClearColor); args.DrawingSession.Antialiasing = Microsoft.Graphics.Canvas.CanvasAntialiasing.Aliased; var textFormat = new CanvasTextFormat { FontSize = FONT_SIZE, Direction = CanvasTextDirection.TopToBottomThenLeftToRight }; var negTextFormat = new CanvasTextFormat { FontSize = FONT_SIZE, Direction = CanvasTextDirection.BottomToTopThenLeftToRight }; var scale = Editor.Scale; var size = Editor.WaveData.LeftChannel.Length; var height = sender.ActualHeight; var width = sender.ActualWidth * scale; float previousX = 0; float previousY = (float)(height / 2); for (int x = 0; x < width / scale; x++) { int start = (int)(x * (size / width)); int end = (int)((x + 1) * (size / width)); if (end > size) { end = size; } if (start == end) { // Blank pixel continue; } WaveUtils.averages(Editor.WaveData.LeftChannel, start, end, out double posAvg, out double negAvg); float yMax = (float)(height - ((posAvg + 1) * .5f * height)); float yMin = (float)(height - ((negAvg + 1) * .5f * height)); args.DrawingSession.DrawLine(x, yMax, x, yMin, Colors.Red); if (posAvg > 0) { args.DrawingSession.DrawText(posAvg.ToString(), x - FONT_SIZE / 2, yMin, Colors.Blue, textFormat); args.DrawingSession.DrawLine(previousX, previousY, x, yMax, Colors.Silver); previousY = yMax; } else if (negAvg < 0) { args.DrawingSession.DrawText(negAvg.ToString(), x - FONT_SIZE / 2, yMax, Colors.Blue, negTextFormat); args.DrawingSession.DrawLine(previousX, previousY, x, yMin, Colors.Silver); previousY = yMin; } else { args.DrawingSession.DrawText("0", x - FONT_SIZE / 2, yMin, Colors.Blue, textFormat); previousY = (float)(height / 2); } previousX = x; } // Selection if (this.Editor.PointerX1 > 0) { args.DrawingSession.DrawLine((float)this.Editor.PointerX1, 0f, (float)this.Editor.PointerX1, (float)height, Colors.Blue); } if (this.Editor.PointerX2 > 0) { args.DrawingSession.DrawLine((float)this.Editor.PointerX2, 0f, (float)this.Editor.PointerX2, (float)height, Colors.Blue); } if (this.Editor.IsPointerPressed) { var brush = new CanvasSolidColorBrush(canvas, Colors.LightSkyBlue); brush.Opacity = 0.4f; args.DrawingSession.FillRectangle((float)this.Editor.PointerX1, 0f, (float)(this.Editor.PointerX2 - this.Editor.PointerX1), (float)height, brush); } }