Sunday, 29 May 2011

Development process signal to noise ratio (a rant)

In the world of audio recording, maintaining a high signal to noise ratio (SNR) is vital. Signal is the singer’s voice; noise is the traffic on the road outside. Signal is what we want to record; noise is what we don’t.

Just as noise can get introduced at any stage in the audio recording process, degrading the signal quality; the software development lifecycle has many points at which noise can be introduced. The only difference is, that the signal is information rather than sound. In software development, signal is information that is of use to me; noise is information that wastes my time.

In the audio world, if the signal to noise ratio is too low, it becomes simply too difficult or distracting to keep listening. The same is true with information. A low SNR to ratio bores people into switching off.

Here’s five areas in the software development / business process that you need to watch your SNR in…

Meetings

As a general rule, I dread meetings. They get me away from what I would rather be doing (coding). A meeting is maximally useful if the information that flows within it is relevant to all those present. Meetings to tell people things they already know, or that they don’t need to know, or that only one or two people need to know, are invitations to daydream, resulting in attendees missing the little that could have benefitted them.

The worst offenders are the “weekly” meetings, or meetings that are required by some kind of process (“kick off” meeting, “release” meeting, “checklist checker checking meeting”). If you attend a 90 minute meeting with only 5-10 minutes having relevance to you, something is wrong.

Talking in detail through everyone’s weekly progress, or everyone’s holiday plans, or everyone’s tasks for next week, or every open bug, or every support case, is likely to be relevant only to the person who organized the meeting. For everyone else, the meeting SNR is minimal.

Documents

Software documents, particularly those created from templates, also often suffer from poor SNR. Instead of getting right down to business telling us the crucial facts, we have to wade through pages of boilerplate sections marked “Not applicable”.

In one company I worked for, there were several pages in every software design document we ever produced devoted to the utterly irrelevant topic of PCB layout. If the first section of your document that contains useful information is numbered 4.6.12.5, something is wrong.

Documents with low SNR actively discourage people from reading. And the less likely anyone is to consult your document, the less motivated you are to write good documentation, resulting in a vicious cycle.

Presentations

Presentations can have terribly low SNR. A favourite example is presenters who try to follow the rule that says: “Tell people what you are going to tell them, then tell them, then tell them what you told them”.

Fine advice, but not when they interpret this as “tell people that you are telling them what it is that you are going to tell them, then tell them that you are telling them the things you told them you were going to tell them, and then tell them that you are telling them that you have finished telling them the things you told them you told them you were going to tell them.” Instead, use your introduction to make us want to hear what is coming next.

As with meetings, any attempt to exhaustively cover a topic in a presentation is a mistake. Don’t show me every possible graph and chart from last quarter’s financial results. Don’t show me every feature and configuration option. Show me something interesting. Leave me wanting more at the end of your presentation, not praying for it to end.

Comments

Comments in source code are also prime offenders for low SNR. Comments that state the obvious, or are sources of misinformation soon train the developer to completely ignore comments. It’s like the boy who cries wolf. Soon no one is listening anymore. The one really helpful comment you write might as well be invisible. No one will read it.

Comments are like footnotes in a book. Most readers will pause to see what a footnote says the first time they encounter one. But if what they find there is of no relevance or interest to them, they will soon train themselves to stop looking.

Code

What about your code? Surely that is all signal right? After all, we can’t delete 50% of the lines and leave the behaviour of the code intact. But the truth is that code can be written in a very noisy way. This happens when so much code for logging, or caching, or error handling, (or whatever) is mixed in that the structure and intent of the method in question is obscured from view.

The solution is simple: write clean code. Extract each task out into small, well-named helper methods or dependencies. This allows people to see the “signal” of what is going on, and only delve into the details that are of interest to them. Implementation details are usually noise.

Summary

Stop writing comments that are just noise. Delete comments that are wrong. Refactor “noisy” code out into helper methods. Learn what clean code is. Hold fewer and shorter meetings. Write shorter documents. Tell me what I need to know. Stop wasting my time.

Saturday, 28 May 2011

NAudio and NuGet (and the x64 problem)

Several people have contacted me recently asking when NAudio will appear on nuget.org. The short answer is, hopefully soon. For the longer answer, read on…

The need for a decent build process

To release NAudio, there is a bunch of stuff I have to do, such as remembering to run all the unit tests and manual tests on all the operating systems and soundcards I can get my hands on (which in truth is a pretty limited selection). I then have to create a bunch of zip files for the binaries, the demo apps, and the source code to go on CodePlex. Then there is the release notes. A NuGet package adds yet another thing to a process that I would rather not be spending my free time on.

The hassle of doing all this means I don’t release as often as I should. However, I have created an MSBuild script for NAudio now that should make it a lot easier for me to create releases. And yes, one of the things it now does is creates a nupkg for NAudio.

The need to decide on a version numbering strategy

The approach to versioning I have taken with NAudio is that there is a major and minor version, and then the third digit gets updated regularly (used to be every checkin, but I have got lazy). If I am to release NAudio to nuget, I need to decide now how I will version it. Ideally I just want the public releases to be called “1.4”, “1.5” etc. But when I do bugfixes, what should their package number be? It doesn’t seem right if the package is 1.4.1 but the NAudio.dll version is 1.4.272.0. There seems to be a mixture of choices taken by other libraries on nuget.org, but I guess the safest is simply to use all four numbers as the package version and eliminate any possible confusion.

The need for an updated NAudio 1.4

After releasing NAudio 1.4 RC a while ago, I spotted a couple of bugs that I would really like to fix before calling it NAudio 1.4 final. Since I suspect that NAudio will get a lot more downloads once it is available on nuget.org, I want to make people’s first experience as good as possible.

However, since I am well into writing the code for NAudio 1.5, I will need to create a branch to back-port the crucial fixes in. I’ve contacted CodePlex asking them to turn the NAudio repository into Mercurial so I can branch more easily. Hopefully once the conversion has taken place I can create my branch and start work towards an updated 1.4 release that can go on nuget. There will however be one outstanding issue remaining…

The need to decide on an approach to the x64 problem

The NAudio.dll is currently compiled with the platform target explicitly set to x86 . This means if your application is running as a 64 bit process it will fail when it tries to load NAudio. You need to mark your main project as x86 too for it to work.

There are two reasons for this. The main reason is that since my development environment is x86 (soon to change – I have ordered a new laptop and will finally enter the world of 64 bit), I cannot be sure that the interop all works properly in x64, even though I have heard reports that the vast majority of it is good to go on both architectures. However, until I am sure that all the interop (and there is a lot of interop in NAudio) is safe in Windows x64, it is easier for me to simply enforce running as a 32 bit process.

The second issue is that NAudio uses ACM codecs to perform its MP3 decoding, and I have heard rumours that when running in 64 bit windows, not all your ACM codecs appear. I will have a chance to test this for myself in the near future.

Going forwards, it may be easiest to unset the x86 only flag on the NAudio DLL and just strongly recommend to people that they set it on their calling executable. We could actually do this for people using nuget’s ability to use PowerShell to automate Visual Studio. But I would rather not fiddle with people’s project settings in this way.

Conclusion

I think NuGet is a brilliant development for the .NET open source community and I can’t wait to get NAudio on there. But it might be a few more weeks yet before I have sorted my own build and release processes out.

Wednesday, 25 May 2011

NAudio and Mercurial

I am on the verge of upgrading the NAudio CodePlex project to use Mercurial for source control instead of TFS. Like many CodePlex developers I have been using TortoiseSVN since CodePlex allows you to access your project as though it were a Subversion repository. I prefer this to having to install the Team Explorer Client, which puts source control bindings in my csproj files, making them a pain to open for those without access.

I have converted a number of my other open source projects on CodePlex to Mercurial recently, and the process has gone very smoothly, and I am beginning to think that Mercurial offers a lot more benefits than the TFS/SVN model.

Easier Acceptance of Patches

For a long time I was completely oblivious of the fact that people were submitting patches to NAudio, because Codeplex didn’t send me any automated notifications. And often I don’t have time to review a patch straight away, meaning that by the time I get round to looking at it, it doesn’t merge into the latest code.

Then there is the fact that over 50% of patches I receive either contain a bug, or break some aspect of existing behaviour. I would like the ability to work with patch submitters to get their code fully ready for integration before accepting the patch.

Another benefit is that it allows for contributors to get their own name attached to checkins, without having to give them checkin privileges to the central repository, since I can pull from them, make any minor changes needed, and then push to CodePlex. It means contributors can get the credit for features they add (and the blame for bugs they introduce!).

Possibility for Forks

Finally, whilst I do often accept user contributed features into NAudio, sometimes the feature is too obscure to be considered for the core library. With Mercurial on CodePlex, people can publish their own extensions and special versions as forks, and retain the ability to pull in bug fixes and new features from the latest branch.

Need for Branches

A while ago I released NAudio 1.4 RC. Since its release I have discovered and fixed a few bugs that really ought to be back-ported into NAudio 1.4. However, I have no branching structure at the moment – NAudio is just in a single folder. Although TFS has branching support through creating a brand new folder containing a copy of the entire codebase, I prefer Mercurial’s approach which keeps the branch hidden from view unless you really need to work with it. I anticipate that only critical bugfixes will be done on previous releases, so the use of branching will be minimal in the central repository.

Better Offline Development

Often when I am working on NAudio, I will want to make fairly large changes before checking into the central repository. The trouble with this is that I want to make regular small checkins, so I can easily roll back if I go down a wrong path. Mercurial makes this very easy, essentially giving me my own local branch to experiment in before commiting to the central repository.

Also, since I try to test NAudio on all the different OS’s and soundcards I have available to me, I often need to sync code between two computers without going via the central CodePlex repository. Mercurial makes this easy.

Backup

One final thing. In its early days CodePlex had a disaster where they lost all their source control history. That’s why the NAudio history doesn’t go back earlier than April 2007. I think they have much more reliable backup processes in place now, but it would be nice to know with Mercurial that I would have a full backup of the checkin history if they ever lost it again, or if I felt the need to host elsewhere.

Also while the subversion to TFS bridge they use is good, it is not foolproof. A recent server upgrade meant that my local subversion repositories lost their ability to commit back into CodePlex, requiring me to check out to another folder and manually copy my changed files across.

Disadvantages?

Are there any disadvantages to using Mercurial? One slight issue is that Mercurial never forgets anything, which of course is normally a good thing for a version control system. But if I accidentally checked in a large WAV file for example, that would vastly increase the download time for a repository clone, even if I deleted it in the very next check-in. There are ways to do history rewriting, but it requires contacting the CodePlex admins and getting them to do it for you.

Another slight issue is that when you switch from TFS to Mercurial on Codeplex, it loses all the stats of how many downloads each revision had. Any links to specific versions of files posted in forums are also broken. I suspect I will have to manually re-associate releases with their new changeset IDs too.

The only other TFS benefit over Mercurial that I can think of is that in TFS you can modify a checkin message

Conclusion

I’ll probably be going ahead with the move soon. If anyone has any objections, or cautionary tales to tell, now is the time to speak up.

Monday, 23 May 2011

NAudio Output Devices

NAudio supplies wrappers for four different audio output APIs. In addition, some of them support several different modes of operation. This can be confusing for those new to NAudio and the various Windows audio APIs, so in this post I will explain what the four main options are and when you should use them.

IWavePlayer

We’ll start off by discussing the common interface for all output devices. In NAudio, each output device implements IWavePlayer, which has an Init method into which you pass the Wave Provider that will be supplying the audio data. Then you can call Play, Pause and Stop which are pretty self-explanatory, except that you need to know that Play only begins playback. You should only call Init once on a given instance of an IWavePlayer. If you need to play something else, you should Dispose of your output device and create a new one.

You will notice there is no capability to get or set the playback position. That is because the output devices have no concept of position – they just read audio from the WaveProvider supplied until it reaches an end, at which point the PlaybackStopped event is fired (see this post for more details). Alternatively, you can ignore PlaybackStopped and just call Stop whenever you decide that playback is finished.

You may notice a Volume property on the interface that is marked as [Obsolete]. Don’t use it. There are better ways of setting the volume in NAudio. For example look at the WaveChannel32 class or in NAudio 1.5 onwards, the SampleChannel class.

Finally there is a PlaybackState property that can report Stopped, Playing or Paused. Be careful with Stopped though, since if you call the Stop method, the PlaybackState will immediately go to Stopped but it may be a few milliseconds before any background playback threads have actually exited.

WaveOut

WaveOut should be thought of as the default audio output device in NAudio. If you don’t know what to use, choose WaveOut. It essentially wraps the Windows waveOut APIs, and is the most universally supported of all the APIs.

The WaveOut object allows you to configure several things before you get round to calling Init. Most common would be to change the DeviceNumber property. –1 indicates the default output device, while 0 is the first output device (usually the same in my experience). To find out how many WaveOut output devices are available, query the static WaveOut.DeviceCount property.

You can also set DesiredLatency, which is measured in milliseconds. This figure actually sets the total duration of all the buffers. So in fact, you could argue that the real latency is shorter. In a future NAudio, I might reduce confusion by replacing this with a BufferDuration property. By default the DesiredLatency is 300ms, which should ensure a smooth playback experience on most computers. You can also set the NumberOfBuffers to something other than its default of 2 although 3 is the only other value that is really worth using.

One complication with WaveOut is that there are several different “callback models” available. Understanding which one to use is important. Callbacks are used whenever WaveOut has finished playing one of its buffers and wants more data. In the callback we read from the source wave provider and fill a new buffer with the audio. It then queues it up for playback, assuming there is still more data to play. As with all output audio driver models, it is imperative that this happens as quickly as possible, or your output sound will stutter.

New Window

This is the default and recommended approach if you are creating a WaveOut object from the GUI thread of a Windows Forms or WPF application. Whenever WaveOut wants more data it posts a message that is handled by the Windows message pump of an invisible new window. You get this callback model by default when you call the empty WaveOut constructor. However, it will not work on a background thread, since there is no message pump.

One of the big benefits of using this model (or the Existing Window model) is that everything happens on the same thread. This protects you from threading race conditions where a reposition happens at the same time as a read.

note: The reason for using a new window instead of an existing window is to eliminate bugs that can happen if you start one playback before a previous one has finished. It can result in WaveOut picking up messages it shouldn’t.

Existing Window

Existing Window is essentially the same callback mechanism as New Window, but you have to pass in the handle of an existing window. This is passed in as an IntPtr to make it compatible with WPF as well as WinForms. The only thing to be careful of with this model is using multiple concurrent instances of WaveOut as they will intercept each other’s messages (I may fix this in a future version of NAudio).

note: with both New and Existing Window callback methods, audio playback will deteriorate if your windows message pump on the GUI thread has too much other work to do.

Function Callback

Function callback was the first callback method I attempted to implement for NAudio, and has proved the most problematic of all callback methods. Essentially you can give it a function to callback, which seems very convenient, these callbacks come from a thread within the operating system.

To complicate matters, some soundcards really don’t like two threads calling waveOut functions at the same time (particularly one calling waveOutWrite while another calls waveOutReset). This in theory would be easily fixed with locks around all waveOut calls, but some audio drivers call the callbacks from another thread while you are calling waveOutReset, resulting in deadlocks.

I am pretty sure that in NAudio 1.5 all the potential deadlocks have been chased out. Until recently Function callbacks have been the only way to play audio through WaveOut on a non-GUI thread in NAudio. But with NAudio 1.5 there is now also the Event callback, which, once it has has an appropriate amount of testing, will become the recommended alternative to windowed callbacks for those wanting to play audio on background threads.

Event Callback

New to NAudio 1.5, this is currently implemented in the WaveOutEvent class, although I may try to think of a way of making event callbacks an option within the WaveOut class. This is implemented similar to WASAPI and DirectSound. A background thread simply sits around filling up buffers when they become empty. To help it respond at the right time, an event handle is set to trigger the background thread that a buffer has been returned by the soundcard and is in need of filling again.

note: WaveOut also supports a No Callback mode, which currently isn’t implemented in NAudio, but it would be very easy to change WaveOutEvent to support it. Essentially instead of waiting on an event handle, you sleep for a bit (half the buffer duration would be sensible) and then wake up to see if any of the buffers need filling.

note 2: there is one final WaveOut callback model I haven’t mentioned and that is thread callback. I don’t think it offers anything the other models don’t have, but you give it a thread ID and it posts messages to the thread. The thread would need to call Application.Run to instantiate a message pump, and so if implemented, this method could also enable the Window callback methods to work on a background thread.

DirectSoundOut

DirectSound is a good alternative if for some reason you don’t want to use WaveOut since it is simple and widely supported.

To select a specific device with DirectSound, you can call the static DirectSoundOut.Devices property which will let you get at the GUID for each device, which you can pass into the DirectSoundOut constructor. Like WaveOut, you can adjust the latency (overall buffer size),

DirectSoundOut uses a background thread waiting to fill buffers (same as WaveOut with event callbacks). This is a reliable and uncomplicated mechanism, but as with any callback mechanism that uses a background thread, you must take responsibility yourself for ensuring that repositions do not happen at the same time as reads (although some of NAudio’s built-in WaveStreams can protect you from getting this wrong).

WasapiOut

WASAPI is the latest and greatest Windows audio API, introduced with Windows Vista. But just because it is newer doesn’t mean you should use it. In fact, it can be a real pain to use, since it is much more fussy about the format of the WaveProvider passed to its Init function and will not perform resampling for you.

To select a specific output device, you need to make use of the MMDeviceEnumerator class, which can report the available audio “endpoints” in the system.

WASAPI out offers you a couple of configuration options. The main one is whether you open in shared or exclusive mode. In exclusive mode, your application requests exclusive access to the soundcard. This is only recommended if you need to work at very low latencies. You can also choose whether event callbacks are used. I recommend you do so, since it enables the background thread to get on with filling a new buffer as soon as one is needed.

Why would you use WASAPI? I would only recommend it if you want to work at low latencies or are wanting exclusive use of the soundcard. Remember that WASAPI is not supported on Windows XP. However, in situations where WASAPI would be a good choice, ASIO out is often a better one…

AsioOut

ASIO is the de-facto standard for audio interface drivers for recording studios. All professional audio interfaces for Windows will come with ASIO drivers that are designed to operate at the lowest latencies possible. ASIO is probably a better choice than WASAPI for low latency applications since it is more widely supported (you can use ASIO on XP for example).

ASIO Out devices are selected by name. Use the AsioOut.GetDriverNames() to see what devices are available on your system. Note that this will return all installed ASIO drivers. It does not necessarily mean that the soundcard is currently connected in the case of an external audio interface, so Init can fail for that reason.

ASIO drivers support their own customised settings GUI. You can access this by calling ShowControlPanel(). Latencies are usually set within the control panel and are typically specified in samples. Remember that if you try to work at a really low latency, your input WaveProvider’s Init function needs to be really fast.

ASIO drivers can process data in a whole host of native WAV formats (e.g. big endian vs little endian, 16, 24, 32 bit ints, IEEE floats etc), not all of which are currently supported by NAudio. If ASIO Out doesn’t work with your soundcard, post a message on the NAudio discussion groups, as it is fairly easy to add support for another format.

Friday, 20 May 2011

How to Add a Custom Work Item to a Category In TFS

I recently had to make a custom work item type using the TFS 2010 Power Tools. However, the requirements search in Test Center didn’t return any results for work items of this new type. The problem was, TFS has a concept of work item categories (or “groups”), and my new work item type needed to be in the “requirements” group.

To add a new work item type to a work item category you have to use witadmin. Open a VS2010 command prompt and get the categories like this:

C:\Users\Administrator\Documents>witadmin exportcategories /collection:http://win-gs9gmujits8:8080/tfs/defaultcollection /p:"My Project Name" /f:categories.xml

Then this MSDN article explains the syntax of the categories xml file. I added my custom work item type in like this:
<CATEGORY refname="Microsoft.RequirementCategory" name="Requirement Category">
  <DEFAULTWORKITEMTYPE name="User Story" />
  <WORKITEMTYPE name="My Custom Work Item Type" />
</CATEGORY>

Then you reimport them using the witadmin tool again:

C:\Users\Administrator\Documents>witadmin importcategories /collection:http://win-gs9gmujits8:8080/tfs/defaultcollection /p:"My Project Name" /f:categories.xml

And now Testing Center is able to assign the new work item types as requirements.

Thursday, 19 May 2011

NAudio and the PlaybackStopped Problem

The IWavePlayer interface in NAudio features an event called PlaybackStopped. The original idea behind this event was simple: you start playing a file (e.g. pass a WaveFileReader into WaveOut.Init and then call Play), and when it reaches its end you are informed, allowing you to dispose the input stream and playback device if you wanted to, or maybe start playing something else.

The reality was not quite so simple, and I have ended up trying to discourage users of the NAudio library from making use of the PlaybackStopped event. In this post I will explain some of the reasons behind that and explain how I hope to restore the usefulness of PlaybackStopped in future versions of NAudio.

The Never-Ending Stream Problem

The way that each implementor of IWavePlayer determines whether it should automatically stop playback is when the Read method on the source IWaveProvider returns 0 (In fact Read should always return the count parameter unless the end of the stream has been reached).

However, there are some WaveStreams / IWaveProviders in NAudio that never stop returning audio. This isn’t a bug – it is quite normal behaviour for some scenarios. Perhaps BufferedWaveProvider is the best example – it will return a zero-filled buffer if there is not enough queued data for playback. This is useful for streaming from the network where data might not be arriving fast enough but you don’t want playback to stop. Similarly WaveChannel32 has a property called PadWithZeroes allowing you to turn this behaviour on or off, which can be useful for scenarios where you are feeding into a mixer.

The Threading Problem

This is one of the trickiest problems surrounding the PlaybackStopped event. If you are using WaveOut, the chances are you are using windowed callbacks, which means that the PlaybackStopped event is guaranteed to fire on the GUI thread. Since only one thread makes calls to the waveOut APIs, it is also completely safe for the event handler to make other calls into waveOut, such as calling Dispose, or starting a new playback.

However, with DirectSound and WASAPI, the PlaybackStopped event is fired from a background thread we create. Even more problematic are WaveOut function callbacks and ASIO, where the event is raised from a thread from deep within the OS / soundcard device driver. If you make any calls back into the driver in the handler for the PlaybackStopped event you run the risk of deadlocks or errors. You also don’t want to give the user a chance to do anything that might take a lot of time in that context.

This problem almost caused me to remove PlaybackStopped from the IWavePlayer interface altogether. But I have decided to see if I can give it one last lease of life by using the .NET SynchronizationContext class. The SynchronizationContext class allows us easily in both WPF and WinForms to invoke the PlaybackStopped event on the GUI thread. This greatly reduces the chance of something you do in the handler causing a problem.

The Has it Really Finished Problem

The final problem with PlaybackStopped is another tricky one. How do you know when playback has stopped? You know when you have reached the end of the source file, since the Read method returns 0. And you know when you have given the last block of audio to the soundcard. But the audio may not have finished playing yet, particularly if you are working at high latency. The old WaveOut implementation in particular was guilty of raising PlaybackStopped too early.

One workaround requiring no changes to the existing IWavePlayer implementations would be to create a LeadOutWaveProvider class, deriving from IWaveProvider. This would do nothing more than append a specified amount of silence onto the end of your source stream, ensuring that it plays completely. Here’s a quick example of how that could be implemented:

private int silencePos = 0;
private int silenceBytes = 8000;

public int Read(byte[] buffer, int offset, int count)
{
    int bytesRead = source.Read(buffer,offset,count);
    if (bytesRead < count)
    {
        int silenceToAdd = Math.Min(silenceBytes – silencePos, count – bytesRead);
        Array.Zero(buffer,offset+bytesRead,silenceToAdd);
        bytesRead += silenceToAdd;
        silencePos += silenceToAdd;
    }
    return bytesRead;
}

Goals for NAudio 1.5

Fixing all the problems with PlaybackStopped may not be fully possible in the next version, but my goals are as follows:

  • Every implementor of IWavePlayer should raise PlaybackStopped (this is done)
  • PlaybackStopped should be automatically invoked on the GUI thread if at all possible using SynchronizationContext (this is done)
  • It should be safe to call the Dispose of IWavePlayer in the PlaybackStopped handler (currently testing and bugfixing)
  • PlaybackStopped should not be raised until all audio from the source stream has finished playing (done for WaveOut – we now raise it when there are no queued buffers, will need to code review other classes to decide if this is the case).
  • Keep the number of never-ending streams/providers in NAudio to a minimum and try to make it very clear which ones have this behaviour.

Tuesday, 17 May 2011

How to use the TFS API to retrieve a historical version of your project

I recently had the need to retrieve several old versions of a project from TFS. Fortunately, the TFS API allows you to automate this process.

First you need to connect to the TFS Server:

TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://tfsserver:8080/"));
tpc.EnsureAuthenticated();

Next we will set up a workspace to use. I check first that the workspace doesn’t exist.

VersionControlServer vcs = tpc.GetService<VersionControlServer>(); //.GetAllTeamProjects(false);
string workspaceName = "temp";
string workspaceOwner = "mheath"; // your user name
// protect ourselves from using a workspace in use for something else\
Assert.Throws<WorkspaceNotFoundException>(() => vcs.GetWorkspace(workspaceName, workspaceOwner), "The workspace already exists");
var workspace = vcs.CreateWorkspace(workspaceName, workspaceOwner);

// use the workspace...

// when we are done with it... 
vcs.DeleteWorkspace(workspaceName, workspaceOwner);

Now we need to map our workspace to a local temporary folder. We can use the server path to select only a subset of the code in the project (for example a single branch):

string localPath = @"D:\TFS\Temp";
string requestPath = "$/MyProject/Dev/Source";

// protect ourselves from accidentally overwriting something important
Assert.IsFalse(Directory.Exists(localPath), "directory should not exist before this test is run");
Directory.CreateDirectory(localPath);

workspace.Map(requestPath, localPath);

Finally we are ready to make a request. We use a VersionSpec to specify which version we want. I am using a DateVersionSpec here, but you can use a ChangeVersionSet or a LabelVersionSet if you prefer. The ItemSpec specifies what to get. We want everything in our request path including subfolders, so recursion is turned on:

var version = new DateVersionSpec(new DateTime(2009, 11, 24));
var item = new ItemSpec(requestPath, RecursionType.Full);
GetRequest getRequest = new GetRequest(item, version);

GetStatus status = workspace.Get(getRequest, GetOptions.GetAll);
Assert.AreEqual(0, status.NumWarnings);
Assert.AreEqual(0, status.NumFailures);

And that is it – it is usually quite quick to retrieve as well (certainly much faster than SourceSafe was!).

Wednesday, 11 May 2011

Announcing Audio Test Files Repository

Today I announce what is quite possibly the most exciting new open source project of the millennium. Or at least moderately interesting. If you like listening to the same bit of sound over and over at different sample rates and bit depths that is.

And that is exactly what is on offer in my brand new Audio Test Files project on CodePlex. For some time I have wanted to store a collection of brief test files in a wide variety of audio formats for the NAudio unit tests to make use of. But since these files would add up to at least 200Mb, I didn’t want to put them in the main NAudio source control.

The repository has only just begun with basic WAV files encoded with PCM 8 bit, 16 bit and 24 bit plus IEEE float all at several sample rates and in mono and stereo. To preview the stunning and original musical composition that is available in multiple encodings, you can have a listen in the embedded player below. Hold onto your hats:

The future will see such thrilling additions as MP3, MID, AIFF plus a whole smorgasbord of telephony codecs. Also, I plan to add useful test signals such as sine wave sweeps and white noise. There will also be files containing unusual or incorrect data structures.

Having these files will facilitate the quick manual testing that NAudio is still able to play the wide variety of audio that it currently supports. I will also run unit tests to check I can open and successfully read to the end of each file. Sadly with something like audio, the manual element of testing is impossible to avoid, but I would like to automate as much as possible.

I welcome submissions to this project. The files must of course not be copyrighted, and I am not looking for large files, just representative samples of each format. Read the submission guidelines first.

Friday, 6 May 2011

How to Convert AIFF files to WAV using NAudio 1.5

Thanks to Giawa, the latest NAudio source code (to be released with NAudio 1.5) has an AIFF File Reader. This makes it very easy to convert from AIFF files to WAV (or simply into PCM format for inputs to other NAudio streams). Here’s how to do it:

public static void ConvertAiffToWav(string aiffFile, string wavFile)
{
    using (AiffFileReader reader = new AiffFileReader(aiffFile))
    {
        using (WaveFileWriter writer = new WaveFileWriter(wavFile, reader.WaveFormat))
        {
            byte[] buffer = new byte[4096];
            int bytesRead = 0;
            do
            {
                bytesRead = reader.Read(buffer, 0, buffer.Length);
                writer.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);
        }
    }
}

Wednesday, 4 May 2011

How to Play Streaming MP3 Using NAudio

One of the most common support requests I get for NAudio is how it can be used for streaming MP3. Whilst all the requisite bits and pieces are present in NAudio, there has been no good example of how to do this. For NAudio 1.5 I will be rectifying this to include an example in the NAudioDemo application, and have made a few enhancements to the classes in NAudio to make this easier to implement. In this article I will explain how streaming MP3 playback is implemented in the NAudioDemo application.

Design Overview

The basic design for our streaming playback is that one thread will be downloading the audio, while another thread will play it back. One of the issues this raises is which thread should do the decompression. I have chosen that the download thread should do so. This takes work away from the playback thread and so should give additional protection against stuttering playback, but has the down-side that it requires more memory for buffered audio since it is stored in PCM.

Buffering Audio

The key class that enables us to queue up samples on one thread for playback on another is called the BufferedWaveProvider. The BufferedWaveProvider implements IWaveProvider so it can be used as an input to any Wave Output device. When its Read function is called it returns any bytes buffered, or zeroes the playback buffer if none are available. The AddSamples function is called from the downloader thread to queue up samples as they become available.

Under the hood, the BufferedWaveProvider in NAudio 1.4 used a queue of buffers to store the data. For NAudio 1.5 I am switching to a thread safe circular buffer. This means that memory is allocated once up front, and should result in better performance. By default it buffers enough for five seconds of audio, but this can be easily changed using BufferDuration (although once you start reading, the buffer size is fixed). It also makes more sense to track the number of buffered bytes (a helper method, BufferedDuration, turns this into a TimeSpan) instead of the number of queued buffers.

Parsing MP3 Frames

One if the issues that people quickly run into when attempting to play back streaming MP3 is that the MP3Frame class will throw an exception if it can’t read enough bytes to fully load an MP3 frame. Obviously while you are streaming you may well have half an MP3 frame available.

The solution is fairly simple. We wrap our network stream in a ReadFullyStream, which is just a simple class inheriting from System.IO.Stream that will not return from its Read method until it has read the number of bytes requested or the source stream reaches its end. The ReadFullyStream currently resides in the NAudioDemo project, but may be incorporated as a helper utility for NAudio 1.5.

Decompressing Frames

Once you have parsed a complete MP3 frame, it is time to decompress it so we can buffer the PCM audio. NAudio includes a choice of two MP3 frame decompressors, one using the ACM codecs, which should be present on Windows XP onwards, and one for using the DMO (DirectX Media Object) decoder, which is available with Windows Vista onwards. These two classes were internal with NAudio 1.4, but will be made public for NAudio 1.5. You could alternatively use a fully managed MP3 decoder, such as NLayer which is my C# port of the Java MP3 decoder JavaLayer. If I get time I will update NAudioDemo to allow you to select between the available frame decompressors.

Decompression Format

One of the trickiest design issues to work around is the fact that we don’t know the WaveFormat that the BufferedWaveProvider should output until we have read the first MP3 frame. Most MP3s decompress to stereo 44.1kHz, but some are 48kHz or 22.1kHz, and others are mono. We therefore can’t open the soundcard yet because we don’t know what PCM format we will be supplying it with.

There are two ways you can tackle this problem. First you can choose a PCM format (e.g. 44.1kHz stereo) that you will convert the decompressed MP3 frames to even if they are of a different sample rate or channel count. Alternatively, as I have chosen for the demo, you hold back from creating the BufferedWaveProvider until you have received the first MP3 frame and therefore know what format you will convert to.

In the NAudioDemo project this is handled by a timer running on the form periodically checking to see if we have a BufferedWaveProvider yet. Once the BufferedWaveProvider appears, we can initialise our WaveOut player.

Smooth Playback

One of the problems with playing back from a network stream is that we may get stuttering audio if the MP3 file is not downloading fast enough. Although the BufferedWaveProvider will continuously provide data to the soundcard, it could be very choppy if you are experiencing slow download speeds as there would be gaps between each decompressed frame.

For this reason, it is a good idea for the playback thread to go into pause when the buffered audio has run out, but not start playing again until there are at least a couple of seconds of buffered audio. This is accomplished in the NAudioDemo with a simple timer on the GUI thread firing four times a second and deciding if we should go into our come out of pause.

End of Stream

If you are streaming from internet radio, then there is no end of stream, you just keep listening until you have had enough. However, if you are streaming an MP3 file, it will come to an end at some point.

The first consequence is that our MP3Frame constructor will throw an EndOfStream exception because it was trying to read a new MP3Frame and got to the end of the stream. Handling this is straightforward – the downloader thread can capture this exception and exit, knowing we have got everything. I am considering improving the API for the MP3Frame to include a TryParse option so you can deal with this case without the need for catching exceptions.

The other issue is that the playback thread needs to know that the end of the file has been reached, otherwise it will go into pause, waiting for more audio to be buffered that will never arrive. A simple way to deal with this is to set a flag indicating that the whole stream has been read and that we no longer need to go into a buffering state.

Try It Yourself

The code is all checked in and will be part of NAudio 1.5. To try it yourself, go to the NAudio Source Code tab and download the latest code. Here’s a screenshot of the NAudioDemo application playing from an internet radio stream:

NAudio demo playing an internet radio station