7 people like it.
Like the snippet!
AsciiWaveformRenderer
The ASCII wave renderer behind https://goq2q.net/blog/tech/using-ascii-waveforms-to-test-real-time-audio-code
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
|
namespace AsciiWaveRenderer
open System
open NAudio.Wave
open FSharp
module private AsciiWaveRenderer =
let garbageSeq =
let rand = new Random()
let b = Array.zeroCreate 4
Seq.initInfinite (fun _ ->
rand.NextBytes b
BitConverter.ToSingle (b, 0)
)
|> Seq.cache
type AsciiWaveRenderer =
static member RenderSamples (buffer: float32[], waveFormat: WaveFormat, ?graphHeight) =
let h = defaultArg graphHeight 10
let channels = [|
for ci in 0 .. waveFormat.Channels - 1 -> [|
for si in 0 .. (buffer.Length / waveFormat.Channels) - 1 ->
let i = (si * waveFormat.Channels) + ci
buffer.[i]
|]
|]
let cs =
channels
|> Array.map (fun samples ->
let halfh = h/2
let halfhf = float32 halfh
[|
for hi in halfh .. -1 .. -halfh -> String([|
for si in 0 .. samples.Length - 1 ->
if hi = (int (round (samples.[si] * halfhf))) then '*' else ' '
|])
|]
)
cs
static member ReadAndRenderSamples ((sampleProvider: ISampleProvider), nSamples, ?buffSize, ?buffOffset, ?graphHeight, ?fillBufferWithGarbage) =
let count = nSamples * sampleProvider.WaveFormat.Channels
let buff = Array.zeroCreate<float32> (defaultArg buffSize count)
let garbage = AsciiWaveRenderer.garbageSeq |> Seq.take buff.Length |> Seq.toArray
garbage.CopyTo (buff, 0)
let count' = sampleProvider.Read (buff, defaultArg buffOffset 0, count)
AsciiWaveRenderer.RenderSamples (buff, sampleProvider.WaveFormat, ?graphHeight = graphHeight)
static member MakeGarbageBufferForSampleReading ((sampleProvider: ISampleProvider), nSamples, ?buffSize) =
let count = nSamples * sampleProvider.WaveFormat.Channels
let buff = Array.zeroCreate<float32> (defaultArg buffSize count)
let garbage = AsciiWaveRenderer.garbageSeq |> Seq.take buff.Length |> Seq.toArray
garbage.CopyTo (buff, 0)
buff
|
Multiple items
module AsciiWaveRenderer
from AsciiWaveRenderer
--------------------
type AsciiWaveRenderer =
static member MakeGarbageBufferForSampleReading : sampleProvider:ISampleProvider * nSamples:int * ?buffSize:int -> float32 []
static member ReadAndRenderSamples : sampleProvider:ISampleProvider * nSamples:int * ?buffSize:int * ?buffOffset:int * ?graphHeight:int * ?fillBufferWithGarbage:'a -> String [] []
static member RenderSamples : buffer:float32 [] * waveFormat:WaveFormat * ?graphHeight:int -> String [] []
namespace System
namespace NAudio
namespace NAudio.Wave
namespace Microsoft.FSharp
val private garbageSeq : seq<float32>
val rand : Random
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit + 1 overload
member NextDouble : unit -> float
--------------------
Random() : Random
Random(Seed: int) : Random
val b : byte []
type Array =
member Clone : unit -> obj
member CopyTo : array:Array * index:int -> unit + 1 overload
member GetEnumerator : unit -> IEnumerator
member GetLength : dimension:int -> int
member GetLongLength : dimension:int -> int64
member GetLowerBound : dimension:int -> int
member GetUpperBound : dimension:int -> int
member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
member Initialize : unit -> unit
member IsFixedSize : bool
...
val zeroCreate : count:int -> 'T []
module Seq
from Microsoft.FSharp.Collections
val initInfinite : initializer:(int -> 'T) -> seq<'T>
type BitConverter =
static val IsLittleEndian : bool
static member DoubleToInt64Bits : value:float -> int64
static member GetBytes : value:bool -> byte[] + 9 overloads
static member Int32BitsToSingle : value:int -> float32
static member Int64BitsToDouble : value:int64 -> float
static member SingleToInt32Bits : value:float32 -> int
static member ToBoolean : value:ReadOnlySpan<byte> -> bool + 1 overload
static member ToChar : value:ReadOnlySpan<byte> -> char + 1 overload
static member ToDouble : value:ReadOnlySpan<byte> -> float + 1 overload
static member ToInt16 : value:ReadOnlySpan<byte> -> int16 + 1 overload
...
BitConverter.ToSingle(value: ReadOnlySpan<byte>) : float32
BitConverter.ToSingle(value: byte [], startIndex: int) : float32
val cache : source:seq<'T> -> seq<'T>
module AsciiWaveRenderer
from AsciiWaveRenderer
val buffer : float32 []
Multiple items
val float32 : value:'T -> float32 (requires member op_Explicit)
--------------------
type float32 = Single
--------------------
type float32<'Measure> = float32
val waveFormat : WaveFormat
Multiple items
type WaveFormat =
new : unit -> WaveFormat + 3 overloads
member AverageBytesPerSecond : int
member BitsPerSample : int
member BlockAlign : int
member Channels : int
member ConvertLatencyToByteSize : milliseconds:int -> int
member Encoding : WaveFormatEncoding
member Equals : obj:obj -> bool
member ExtraSize : int
member GetHashCode : unit -> int
...
--------------------
WaveFormat() : WaveFormat
WaveFormat(br: IO.BinaryReader) : WaveFormat
WaveFormat(sampleRate: int, channels: int) : WaveFormat
WaveFormat(rate: int, bits: int, channels: int) : WaveFormat
val graphHeight : int option
val h : int
val defaultArg : arg:'T option -> defaultValue:'T -> 'T
val channels : float32 [] []
val ci : int
val si : int
val i : int
val cs : String [] []
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []
val samples : float32 []
val halfh : int
val halfhf : float32
val hi : int
Multiple items
type String =
new : value:char[] -> string + 8 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool + 3 overloads
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 3 overloads
member EnumerateRunes : unit -> StringRuneEnumerator
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
...
--------------------
String(value: char []) : String
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: ReadOnlySpan<char>) : String
String(c: char, count: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
Multiple items
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val round : value:'T -> 'T (requires member Round)
val sampleProvider : ISampleProvider
type ISampleProvider =
member Read : buffer:float32[] * offset:int * count:int -> int
member WaveFormat : WaveFormat
val nSamples : int
val buffSize : int option
val buffOffset : int option
val fillBufferWithGarbage : 'a option
val count : int
val buff : float32 []
val garbage : float32 []
val take : count:int -> source:seq<'T> -> seq<'T>
val toArray : source:seq<'T> -> 'T []
val count' : int
static member AsciiWaveRenderer.RenderSamples : buffer:float32 [] * waveFormat:WaveFormat * ?graphHeight:int -> String [] []
More information