using System; using System.Collections.Generic; using System.IO.Ports; using System.Windows; using System.Windows.Forms; using Un4seen.Bass; using Un4seen.BassWasapi; namespace MCAudioSpectrumAnalyzer { internal class Analyzer { private bool _enable; //enabled status private Timer _t; //timer that refreshes the display private float[] _fft; //buffer for fft data private ProgressBar _l, _r; //progressbars for left and right channel intensity private WASAPIPROC _process; //callback function to obtain data private int _lastlevel; //last output level private int _hanctr; //last output level counter private List _spectrumdata; //spectrum data buffer //private Spectrum _spectrum; //spectrum dispay control private ComboBox _devicelist; //device list private bool _initialized; //initialized flag private int devindex; //used device index private int _lines = 16; // number of spectrum lines //ctor public Analyzer(ProgressBar left, ProgressBar right, ComboBox devicelist) { _fft = new float[1024]; _lastlevel = 0; _hanctr = 0; _t = new Timer(); _t.Tick += _t_Tick; //_t.Interval = 25; //40hz refresh rate //_t.Interval = 50; //20 Hz _t.Interval = 1000; _t.Enabled = false; _l = left; _r = right; _l.Minimum = 0; _r.Minimum = 0; _r.Maximum = ushort.MaxValue; _l.Maximum = ushort.MaxValue; _process = new WASAPIPROC(Process); _spectrumdata = new List(); _devicelist = devicelist; _initialized = false; Init(); } // Serial port for arduino output public SerialPort Serial { get; set; } // flag for display enable public bool DisplayEnable { get; set; } //flag for enabling and disabling program functionality public bool Enable { get { return _enable; } set { _enable = value; if (value) { if (!_initialized) { var array = (_devicelist.Items[_devicelist.SelectedIndex] as string).Split(' '); devindex = Convert.ToInt32(array[0]); bool result = BassWasapi.BASS_WASAPI_Init(devindex, 0, 0, BASSWASAPIInit.BASS_WASAPI_BUFFER, 1f, 0.05f, _process, IntPtr.Zero); if (!result) { var error = Bass.BASS_ErrorGetCode(); MessageBox.Show(error.ToString()); } else { _initialized = true; _devicelist.Enabled = false; } } BassWasapi.BASS_WASAPI_Start(); } else BassWasapi.BASS_WASAPI_Stop(true); System.Threading.Thread.Sleep(500); _t.Enabled = value; } } // initialization private void Init() { bool result = false; for (int i = 0; i < BassWasapi.BASS_WASAPI_GetDeviceCount(); i++) { var device = BassWasapi.BASS_WASAPI_GetDeviceInfo(i); if (device.IsEnabled && device.IsLoopback) { _devicelist.Items.Add(string.Format("{0} - {1}", i, device.name)); } } _devicelist.SelectedIndex = 0; Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATETHREADS, false); result = Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero); if (!result) throw new Exception("Init Error"); } //timer private void _t_Tick(object sender, EventArgs e) { int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT2048); //get channel fft data if (ret < -1) return; int x, y; int b0 = 0; //computes the spectrum data, the code is taken from a bass_wasapi sample. for (x=0; x<_lines; x++) { float peak = 0; int b1 = (int)Math.Pow(2, x * 10.0 / (_lines - 1)); if (b1 > 1023) b1 = 1023; if (b1 <= b0) b1 = b0 + 1; for (;b0 255) y = 255; if (y < 0) y = 0; _spectrumdata.Add((byte)y); //Console.Write("{0, 3} ", y); } Form1.Instance.Set(_spectrumdata); if (Serial != null) { Serial.Write(_spectrumdata.ToArray(), 0, _spectrumdata.Count); } _spectrumdata.Clear(); int level = BassWasapi.BASS_WASAPI_GetLevel(); _l.Value = Utils.LowWord32(level); _r.Value = Utils.HighWord32(level); if (level == _lastlevel && level != 0) _hanctr++; _lastlevel = level; //Required, because some programs hang the output. If the output hangs for a 75ms //this piece of code re initializes the output so it doesn't make a gliched sound for long. if (_hanctr > 3) { _hanctr = 0; _l.Value = 0; _r.Value = 0; Free(); Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero); _initialized = false; Enable = true; } } // WASAPI callback, required for continuous recording private int Process(IntPtr buffer, int length, IntPtr user) { return length; } //cleanup public void Free() { BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); } } }