github.com/noriah/catnip@v1.8.5/cmd/catnip/number_writer.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/noriah/catnip/dsp"
     8  	"github.com/noriah/catnip/util"
     9  )
    10  
    11  // Constants
    12  const (
    13  	// ScalingWindow in seconds
    14  	ScalingWindow = 1.5
    15  	// PeakThreshold is the threshold to not draw if the peak is less.
    16  	PeakThreshold = 0.001
    17  )
    18  
    19  // Writer handles drawing our visualizer.
    20  type Writer struct {
    21  	Smoother   dsp.Smoother
    22  	trackZero  int
    23  	binCount   int
    24  	invertDraw bool
    25  	window     *util.MovingWindow
    26  }
    27  
    28  func NewWriter() *Writer {
    29  	return &Writer{
    30  		binCount: 50,
    31  	}
    32  }
    33  
    34  // Init initializes the display.
    35  // Should be called before any other display method.
    36  func (d *Writer) Init(sampleRate float64, sampleSize int) error {
    37  	// make a large buffer as this could be as big as the screen width/height.
    38  
    39  	windowSize := ((int(ScalingWindow * sampleRate)) / sampleSize) * 2
    40  	d.window = util.NewMovingWindow(windowSize)
    41  
    42  	return nil
    43  }
    44  
    45  // Close will stop display and clean up the terminal.
    46  func (d *Writer) Close() error {
    47  	return nil
    48  }
    49  
    50  func (d *Writer) SetBinCount(count int) {
    51    d.binCount = count
    52  }
    53  
    54  func (d *Writer) SetInvertDraw(invert bool) {
    55  	d.invertDraw = invert
    56  }
    57  
    58  // Start display is bad.
    59  func (d *Writer) Start(ctx context.Context) context.Context {
    60  	return ctx
    61  }
    62  
    63  // Stop display not work.
    64  func (d *Writer) Stop() error {
    65  	return nil
    66  }
    67  
    68  // Draw takes data and draws.
    69  func (d *Writer) Write(buffers [][]float64, channels int) error {
    70  
    71  	peak := 0.0
    72  	bins := d.Bins(channels)
    73  
    74  	for i := 0; i < channels; i++ {
    75  		for _, val := range buffers[i][:bins] {
    76  			if val > peak {
    77  				peak = val
    78  			}
    79  		}
    80  	}
    81  
    82  	scale := 1.0
    83  
    84  	if peak >= PeakThreshold {
    85  		d.trackZero = 0
    86  
    87  		// do some scaling if we are above the PeakThreshold
    88  		d.window.Update(peak)
    89  
    90  	} else {
    91  		if d.trackZero++; d.trackZero == 5 {
    92  			d.window.Recalculate()
    93  		}
    94  	}
    95  
    96  	vMean, vSD := d.window.Stats()
    97  
    98  	if t := vMean + (2.0 * vSD); t > 1.0 {
    99  		scale = t
   100  	}
   101  
   102  	scale = 100.0 / scale
   103  
   104  	for xSet, chBins := range buffers {
   105  
   106  		for xBar := 0; xBar < d.binCount; xBar++ {
   107  
   108  			xBin := (xBar * (1 - xSet)) + (((d.binCount - 1) - xBar) * xSet)
   109  
   110  			if d.invertDraw {
   111  				xBin = d.binCount - 1 - xBin
   112  			}
   113  
   114  			fmt.Printf("%6.3f ", chBins[xBin]*scale)
   115  		}
   116  	}
   117  
   118  	fmt.Println()
   119  
   120  	return nil
   121  }
   122  
   123  // Bins returns the number of bars we will draw.
   124  func (d *Writer) Bins(chCount int) int {
   125  	return d.binCount
   126  }