protected override void Render(Widget widget) { base.Render(widget); Animator <AudioAction> actionAnimator; if (!audio.Animators.TryFind("Action", out actionAnimator)) { return; } foreach (var key in actionAnimator.ReadonlyKeys) { if (key.Value == AudioAction.Play) { var sample = GetSampleAtFrame(key.Frame); Waveform waveform = null; try { waveform = GetWaveform(sample.Path); } catch (System.Exception) { continue; } var pos = new Vector2(key.Frame * TimelineMetrics.ColWidth + 1, 0); var scale = Document.Current.Format == DocumentFormat.Scene ? 0.5f : 1; foreach (var p in waveform.Parts) { var size = new Vector2(p.Width * scale * TimelineMetrics.ColWidth / pixelsPerFrame, widget.Height); Renderer.DrawRect(pos, pos + size, ColorTheme.Current.TimelineGrid.WaveformBackground); Renderer.DrawSprite(p.Texture, ColorTheme.Current.TimelineGrid.WaveformColor, pos, size, Vector2.Zero, Vector2.One); pos.X += size.X; } } } }
static unsafe Waveform GetWaveform(string path) { Waveform waveform; if (waveforms.TryGetValue(path, out waveform)) { return(waveform); } waveform = new Waveform(); var textureWidth = 256; var textureHeight = 64; using (var fs = AssetBundle.Current.OpenFile(path + ".ogg")) { using (var decoder = AudioDecoderFactory.CreateDecoder(fs)) { var stereo = decoder.GetFormat() == AudioFormat.Stereo16; while (true) { var maxPartLength = textureWidth / (AnimationUtils.FramesPerSecond * pixelsPerFrame); var maxPartSamples = (int)(maxPartLength * decoder.GetFrequency()); var maxBlocks = maxPartSamples / decoder.GetBlockSize() * (stereo ? 4 : 2); var samples = Marshal.AllocHGlobal(maxBlocks * decoder.GetBlockSize()); try { var numBlocks = decoder.ReadBlocks(samples, 0, maxBlocks); if (numBlocks == 0) { break; } var numSamples = numBlocks * decoder.GetBlockSize() / (stereo ? 4 : 2); var pixels = new Color4[textureWidth * textureHeight]; int width = numSamples * textureWidth / maxPartSamples; if (stereo) { BuildMonoWaveform((short *)samples, 2, numSamples, pixels, textureWidth, width, 0, textureHeight / 2 - 1); BuildMonoWaveform(((short *)samples + 1), 2, numSamples, pixels, textureWidth, width, textureHeight / 2 + 1, textureHeight - 1); } else { BuildMonoWaveform((short *)samples, 1, numSamples, pixels, textureWidth, width, 0, textureHeight - 1); } var texture = new Texture2D(); texture.LoadImage(pixels, textureWidth, textureHeight); waveform.Parts.Add(new Waveform.Part { Texture = texture, Width = width }); } finally { Marshal.FreeHGlobal(samples); } } } } waveforms.Add(path, waveform); return(waveform); }