Skip to content

Commit

Permalink
init capture on enable; better memory mgmt on disable
Browse files Browse the repository at this point in the history
  • Loading branch information
glowboy committed Apr 1, 2017
1 parent e27a28a commit d17bc34
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 27 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Ok, maybe not all that. But maybe changing from a yellow-red spectrum to blue-w
Bear in mind I am not a C# developer, but the Logitech SDK was way easier to use in C# than the Java JNI version. Ugh.

#### Version History
0.3.0:
- Initialization of capture now happens when enabled. This allows changing audio output devices (e.g., speakers to headphones) without the need to restart the application
- Better memory management when starting and stopping capture

0.2.0:
- Read in color mappings from file
- Copy LogitechLedEnginesWrapper.dll to output at build
Expand Down
75 changes: 49 additions & 26 deletions SpectrumLED/SpectrumApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,30 @@ namespace SpectrumLED
*/
public class SpectrumApp
{

// Our ticker that triggers keyboard re-rendering. User-controllable via the systray menu
private Timer ticker;

// CSCore classes that read the WASAPI data and pass it to the SampleHandler
private WasapiCapture capture;
private SingleBlockNotificationStream notificationSource;
private IWaveSource finalSource;

// An attempt at only-just-post-stream-of-consciousness code organization
private SampleHandler sampleHandler;
private KeyboardHandler keyboardHandler;

/*
* Initialize audio capture and our sample and keyboard handlers. No audio is read until
* SetEnable(true) is called.
* Basic initialization. No audio is read until SetEnable(true) is called.
*/
public void Initialize()
public SpectrumApp()
{
// Init the timer
ticker = new Timer(SpectrumLEDApplicationContext.SLOW_MS);
ticker.Elapsed += Tick;

// Init audio capture
capture = new WasapiLoopbackCapture();
capture.Initialize();

// Init sample and keyboard handlers
sampleHandler = new SampleHandler(capture.WaveFormat.Channels, capture.WaveFormat.SampleRate);
// Create keyboard handler
keyboardHandler = new KeyboardHandler();

// Configure per-block reads rather than per-sample reads
var notificationSource = new SingleBlockNotificationStream(new SoundInSource(capture).ToSampleSource());
notificationSource.SingleBlockRead += (s, e) => sampleHandler.Add(e.Left, e.Right);

finalSource = notificationSource.ToWaveSource();
capture.DataAvailable += (s, e) => finalSource.Read(e.Data, e.Offset, e.ByteCount);
}

/*
Expand All @@ -58,15 +46,15 @@ public void SetEnabled(bool enabled)
{
if (enabled)
{
capture.Start();
StartCapture();
keyboardHandler.Connect();
ticker.Start();
}
else
{
ticker.Stop();
keyboardHandler.Disconnect();
capture.Stop();
StopCapture();
}
}

Expand All @@ -92,13 +80,7 @@ public void UpdateTickSpeed(double intervalMs)
*/
public void Shutdown(object sender, EventArgs e)
{
ticker.Stop();
keyboardHandler.Disconnect();
if (!(capture.RecordingState == RecordingState.Stopped))
{
capture.Stop();
}
capture.Dispose();
SetEnabled(false);
}

/*
Expand All @@ -115,5 +97,46 @@ private void Tick(object sender, ElapsedEventArgs e)
}
}

/*
* Begin audio capture. Connects to WASAPI, initializes the sample handler, and begins
* sending captured data to it.
*/
private void StartCapture()
{
// Initialize hardware capture
capture = new WasapiLoopbackCapture();
capture.Initialize();

// Init sample handler
sampleHandler = new SampleHandler(capture.WaveFormat.Channels, capture.WaveFormat.SampleRate);

// Configure per-block reads rather than per-sample reads
notificationSource = new SingleBlockNotificationStream(new SoundInSource(capture).ToSampleSource());
notificationSource.SingleBlockRead += (s, e) => sampleHandler.Add(e.Left, e.Right);

finalSource = notificationSource.ToWaveSource();
capture.DataAvailable += (s, e) => finalSource.Read(e.Data, e.Offset, e.ByteCount);

// Start capture
capture.Start();
}

/*
* Stop the audio capture, if currently recording. Properly disposes member objects.
*/
private void StopCapture()
{
if (capture.RecordingState == RecordingState.Recording)
{
capture.Stop();

finalSource.Dispose();
notificationSource.Dispose();
capture.Dispose();

sampleHandler = null;
}
}

}
}
1 change: 0 additions & 1 deletion SpectrumLED/SpectrumLEDApplicationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public class SpectrumLEDApplicationContext : ApplicationContext
public SpectrumLEDApplicationContext()
{
spectrumLED = new SpectrumApp();
spectrumLED.Initialize();

MenuItem spectrumMenu = new MenuItem("Spectrum");
ReadColorOptions().ForEach(colorOpt => spectrumMenu.MenuItems.Add(
Expand Down

0 comments on commit d17bc34

Please sign in to comment.