Monday, 20 February 2012

To rebase or not to rebase, that is the question

In recent weeks I’ve made my first code contributions to open source projects on GitHub. A number of GitHub hosted projects like their contributors to rebase their changes before issuing a pull request. Since I normally use Mercurial, which doesn’t enable rebasing by default (although is easily turned on with an extension), I haven’t used rebase much except to experiment with it. And rebase is notorious for causing problems if you use it incorrectly.

Why would you want to rebase?

1. Simplified history

The main argument for rebasing is that it makes the history of your repository much simpler. Instead of seeing lots of short-lived branches and merge commits, you get one single linear history for your branch.

This might seem like a case of OCD on the part of the developers wanting rebase, but unfortunately, the task of looking back through source control history is something we’ve all had to do at some time or another, so the desire for it to appear as simple as possible is understandable.

If like me you quite often forget to do a pull before making a change to your local clone, you may end up requiring a merge when you do get round to doing a push. And more often than not, it is a trivial merge, since your change doesn’t conflict with the most recent commits that you forgot to fetch. In this scenario, rebase is able to present your change as though you had remembered to do the pull before starting work, and eliminates the superfluous merge commit.

Also if you work on a feature for a few weeks, you might end up with lots of intermediate merge commits as you keep pulling from the source repository. Rebasing simplifies the history of your feature by eliminating the many (often trivial) merge commits.

2. Commit combining

At the same time as rebasing, it is a common practice to combine your commits into one. Again, this is more about keeping the history of your repository nice and clean. If you made 20 commits to implement a single feature, perhaps with a few of them going in directions that you later backtracked out of, do you really want all those to be pushed up into the master repository?

Again, at some point in the future, someone will be trawling back through history trying to find where something went wrong, and it is a waste of their time to look at a revision that perhaps contains a silly mistake (might not even build), when your work could be combined into one revision.

Having your feature contained in a single commit also makes life simpler for the code reviewer, since they can just look at the diff for that one revision (although your tools ought to be able to show you a combined diff for a range of revisions – I noticed that github does this very elegantly with pull requests that contain multiple revisions).

Some people have called commit combining a “pretend you are perfect” feature – where you show the final outcome of your work without revealing all the stupid mistakes you made along the way. But that shouldn’t be the point of combining commits. You do it to save time for whoever in the future needs to look back at the history of the project.

What are the dangers?

So if rebase makes our history simpler, why would some people not want to use it. There are a few dangers associated with rebasing and combining commits.

1. Rebasing published revisions

The biggest danger with rebase is rebasing already published revisions. This is most likely to happen if you accidentally rebase the wrong way round (rebasing changes you pulled in from elsewhere onto your own work), something I imagine would be quite easy to do by mistake for a beginner with DVCS. Or maybe you forgot or unintentionally already pushed the revisions you are about to rebase to a public repository.

Doing this means that the revisions you rebased, rather than disappearing, will keep coming back again, and end up getting merged back in alongside the rebased versions of the same change. It can be very hard with a DVCS to get rid of revisions you no longer care about once they have been published.

In Mercurial 2.1, there is a new feature called phases, which gives the repository the ability to know which revisions have been published. This means that commands like rebase can now refuse to work on published revisions, making it a much safer command to use. It will be interesting to see how well this works in practice, and if it does work, maybe Mercurial will allow rebase and other history changing extensions, to be enabled by default). Having said that, since (unlike git), Mercurial by default pushes and pulls all heads, you might find you end up sharing a work in progress branch earlier than you intended.

2. Loss of information provided by a merge commit

One of the benefits of rebase, the removal of the merge commit, is also one of its dangers. It is possible for a rebase to complete successfully, with no merge conflicts, but the resulting code to be broken (e.g. one developer adds a call to functionX, while another developer renames functionX to functionY).

The original commit you made may well have been working perfectly and passing all its unit tests when it was in its own branch, but now it has been rebased there is a commit with your name against it that doesn’t build or contains bugs.

With an explicit merge commit, it is much easier to identify the point at which things went wrong. This remains the main reason why I am not convinced that rebase should be a major part of my workflow. The important thing to remember is that a rebase is just like a merge – it needs to be tested before it can be considered a success, even if there were no conflicts.

3. Loss of intermediate revisions

The goal of rebasing and collapsing is to get rid of intermediate revisions. But I wonder whether you could shoot yourself in the foot by over-enthusiastic collapsing of multiple revisions into one. Often after getting a feature working, I might quickly go over the code and do some last minute cleanup, refactoring a few class names, deleting TODO comments etc. But what if I accidentally break something in these final commits? If I collapse to a single commit it is too late to do a revert of the offending revision, or to rewind to the last good revision and make the changes correctly. Keeping your intermediate commits allows you to backtrack to the last good point.

Summary

In short, I think rebase is a useful tool to have available, but one that should be used with caution. Innovations like Mercurial’s phases could make it much safer, but on the whole, I prefer my source control history to show what really happened, rather than what I would have liked to happen in an ideal world.

As always, I welcome your thoughts on this in the comments.

Saturday, 18 February 2012

Modular WPF Screencast Part 3

Due to popular demand, I have finally got round to recording part three of my modular WPF application screencast series. Rather than jumping directly to a fully featured solution, I wanted to show how we might evolve an architecture step by step, and without being afraid to make some wrong choices that we will need to refactor later.

  • Part 1 covered setting up the framework to use MEF
  • Part 2 covered adding MVVM to make it unit testable

In this episode I walk through adding a new feature, the ability to cancel switching between modules, which turns out to be a bit more tricky than we might have anticipated, and ends up with us creating a templated list of buttons to replace our original ListBox. (n.b. an even better choice might have been to use a tab control, but I didn’t think of that when I created this tutorial, so maybe that can be another refactoring for a future episode).

Also, loads of people are asking for the code, so I have made the Mercurial repository publicly available. In the video, the reason you don’t see me coding, is because I am just switching between revisions of my repository (and it also keeps the video much more succinct). I’ve bought a new headset too, so the voice quality ought to be better than before (although I’ll probably reduce the level slightly for next time). I also tried capturing at 1280x720, so there is a bit more screen real estate. Let me know if this is better or worse.

Thursday, 16 February 2012

Fork First or Just in Time?

I’ve been following the progress of Code 52 a bit over recent weeks. It is an audacious attempt to create a new open source project every week for a year. They also seem willing to accept code contributions, so I was tempted to download a few of their projects and make some minor improvements.

I’ve been using Mercurial for my projects at CodePlex for some time now, but I hadn’t used git in anger, and since Code52 store all their projects on the very impressive github, it gave me a good excuse to learn.

I read up a few tutorials on how to fork a repository in github. The official guide is good, and Scott Hanselman wrote a great post on how to contribute to Code 52 projects. But one thing they all have in common, is a workflow of Fork, Clone, Commit, [optional: Pull & Merge], Push, Pull Request. This has always struck me as being the wrong way round. (CodePlex recommends essentially the same workflow for Mercurial).

Fork First

The reason I don’t like this workflow, is that it assumes the first thing I want to do is create a fork. But that’s not how I typically interact with an open source project. My workflow goes like this:

  1. I come across a new open source project and maybe I find it interesting
  2. Often I will just want to download compiled binaries, but maybe I want to explore the code to see how it was implemented
  3. I clone it (git/hg clone) and maybe I will get round to playing with it later
  4. I attempt to build it locally and maybe it succeeds on my machine (surprising how often it doesn’t)
  5. I attempt to use it and maybe I find a bug or I wish it had a new feature
  6. I report the bug or feature to the developers, and maybe I think I could fix it myself
  7. I explore the source code, and maybe I understand it well enough to make a change
  8. I begin coding a fix/feature, and maybe I get it working
  9. I realise my code needs cleaning up before I issue a pull request, and maybe I get round to doing so
  10. If I have made it this far, now is the time I am ready to push to a public fork and issue a pull request. I estimate I get to this step on less than 1 percent of open source projects I come across.

As you can see, it is only at step 10 that I need to have a fork, but the tutorials all want me to make my fork at step 3. This results in lots of projects having multiple forks that have never been pushed to. Or have been pushed to but no pull request ever submitted, leaving you wondering what the status of the changes is.

Just in time fork

In my opinion, forks (which are really just publicly visible clones), should be made just in time. Currently, Code 52’s Pretzel project has 47 forks, and as far as I can tell, many (most?) of them have had no changes pushed to them at all. (In fact, a nice github feature would be to hide forks that have not been pushed to yet, and to highlight forks that have pull requests outstanding).

The just in time fork workflow isn’t difficult. First clone from the main repository. Think of this clone as your private fork if that helps.

git clone https://github.com/Code52/pretzel.git

Once you decide to make some changes to your repo, you can make a branch to work on (not strictly necessary, but recommended).

git checkout –b my-new-feature

Now work away on your feature. You can pull in changes from the master repository, and optionally merge them into your working branch whenever you like.

Once you are sure that you want to contribute to the project, at this point, you create your public fork on github. Now you add it as a remote:

git remote add myfork https://myname@github.com/myfork/pretzel.git

You can now easily push to your github fork. I think it is probably best to also have a feature branch on your github fork, which means that if you wanted to contribute another unrelated feature, you could do that in another branch, and have two pull requests outstanding that weren’t dependent on each other.

git push myfork my-new-feature

The github gui makes it very easy to issue a pull request from a branch.

Summary

Why create dozens of unused forks when it is straightforward to create them at the point they are needed? Am I missing some important reason why you shouldn’t work like this? Let me know in the comments.

Friday, 27 January 2012

Handling multi-channel audio in NAudio

One of the recurring questions on the NAudio support forums is to do with how you can route different sounds to different outputs in a multi-channel soundcard setup. For example, can you play one MP3 file out of one speaker and a different one out of the other? If you have four outputs, can you route a different signal to each one?

The first issue to deal with is that just because your soundcard has multiple outputs, doesn’t mean you can necessarily open WaveOut with multiple outs. That depends on how the writers of the device driver have chosen to present the card’s capabilities to Windows. For example a four output card may appear as though it were two separate stereo soundcards. The good news is that if you have an ASIO driver, you ought to be able to open it and address all the outputs.

Having got that out of the way, in NAudio it is possible for audio streams to have any number of channels. The WaveFormat class has a channel count, and though this is normally set at 1 or 2, there is no reason why you can’t set it to 8.

What would be useful is an implementation of IWaveProvider that allows us to connect different inputs to particular outputs, kind of like a virtual patch bay. For example, if you had two Mp3FileReaders, and wanted to connect the left channel of the first to output 1 and the left channel of the second to output 2, this class would let you do that.

So I’ve created something I’ve called the MultiplexingWaveProvider (if you can think of a better name, let me know in the comments). In the constructor, you simply provide all the inputs you wish to use, and specify the number of output channels you would like. By default the inputs will be mapped directly onto the outputs (and wrap round if there are less outputs than inputs – so a single mono input would be automatically copied to every output), but these can be changed.

Creating and Configuring MultiplexingWaveProvider

In the following example, we create a new four-channel WaveProvider, so the first two outputs will play left and right channel from input1 and the second two outputs will have the left and right channels from input2. Note that input1 and input2 must be at the same sample rate and bit depth.

var input1 = new Mp3FileReader("test1.mp3");
var input2 = new Mp3FileReader("test2.mp3");
var waveProvider = new MultiplexingWaveProvider(new IWaveProvider[] { input1, input2 }, 4));

Then you can configure the outputs, which is done using ConnectInputToOutput:

waveProvider.ConnectInputToOutput(2,0);
waveProvider.ConnectInputToOutput(3,1);
waveProvider.ConnectInputToOutput(1,2);
waveProvider.ConnectInputToOutput(1,3);

The numbers used are zero-based, so connecting inputs 2 and 3 to outputs 0 and 1 means that test2.mp3 will now play out of the first two outputs instead of the second two. In this example I have connected input 1 (i.e. the right channel of test1.mp3) to both outputs 2 and 3. So you can copy the same input to multiple output channels, and not all input channels need a mapping.

Implementation of MultiplexingWaveProvider

The bulk of the work to achieve this is performed in the Read method of MultiplexingWaveProvider. The first task is to work out how many “sample frames” are required. A sample frame is a single sample in a mono signal, a left and right pair in a stereo signal, and so on. Once we have worked out how many sample frames we need, we then attempt to read that many sample frames from every one of the input WaveProviders (irrespective of whether they are connected to an output – we want to keep them in sync). Then, using our mappings dictionary, work out if any of the channels from this input WaveProvider are needed in the output. Since samples are interleaved in both input and output waveproviders, we can’t do just one Array.Copy – we must copy each sample across individually and put it into the right place.

A well behaved Read method will always return count unless it has reached the end of its available data (and then it should always return 0 in every subsequent call). The way we do this is work out the maximum number of sample frames read out of any of the inputs, and use that to report back the count that is read. This means that we will keep going until we have reached the end of all of our inputs. Because buffers might be reused, it is important that we zero out the output buffer if there was no available input data.

Here’s the implementation as it currently stands:

public int Read(byte[] buffer, int offset, int count)
{
    int sampleFramesRequested = count / (bytesPerSample * outputChannelCount);
    int inputOffset = 0;
    int sampleFramesRead = 0;
    // now we must read from all inputs, even if we don't need their data, so they stay in sync
    foreach (var input in inputs)
    {
        int bytesRequired = sampleFramesRequested * bytesPerSample * input.WaveFormat.Channels;
        byte[] inputBuffer = new byte[bytesRequired];
        int bytesRead = input.Read(inputBuffer, 0, bytesRequired);
        sampleFramesRead = Math.Max(sampleFramesRead, bytesRead / (bytesPerSample * input.WaveFormat.Channels));

        for (int n = 0; n < input.WaveFormat.Channels; n++)
        {
            int inputIndex = inputOffset + n;
            for (int outputIndex = 0; outputIndex < outputChannelCount; outputIndex++)
            {
                if (mappings[outputIndex] == inputIndex)
                {
                    int inputBufferOffset = n * bytesPerSample;
                    int outputBufferOffset = offset + outputIndex * bytesPerSample;
                    int sample = 0;
                    while (sample < sampleFramesRequested && inputBufferOffset < bytesRead)
                    {
                        Array.Copy(inputBuffer, inputBufferOffset, buffer, outputBufferOffset, bytesPerSample);
                        outputBufferOffset += bytesPerSample * outputChannelCount;
                        inputBufferOffset += bytesPerSample * input.WaveFormat.Channels;
                        sample++;
                    }
                    // clear the end
                    while (sample < sampleFramesRequested)
                    {
                        Array.Clear(buffer, outputBufferOffset, bytesPerSample);
                        outputBufferOffset += bytesPerSample * outputChannelCount;
                        sample++;
                    }
                }
            }
        }
        inputOffset += input.WaveFormat.Channels;
    }

    return sampleFramesRead * bytesPerSample * outputChannelCount;
}

Performance

Looking at the code above, you will probably notice that this could be made more efficient if we knew in advance whether we were dealing with 16, 24 or 32 bit input audio (it currently has lots of calls to Array.Copy to copy just 2, 3 or 4 bytes). And I might make three versions of this class at some point, to ensure that this performs a bit better. Another weakness in the current design is the creation of buffers every call to Read, which is something that I generally avoid since it gives work to the garbage collector (update – this is fixed in the latest code).

I have written a full suite of unit tests for this class, so if it does need some performance tuning, there is a safety net to ensure nothing gets broken along the way.

MultiplexingSampleProvider

NAudio 1.5 also has a ISampleProvider interface, which is a much more programmer friendly way of dealing with 32 bit floating point audio. I have also made MultiplexingSampleProvider for the next version of NAudio. One interesting possibility would be then to build on that to create a kind of bus matrix, where every input can be mixed by different amounts into each of the output channels.

Uses

This class actually has uses beyond supporting soundcards with more than 2 outputs. You could use it to swap left and right channels in a stereo signal, or provide a simple switch that selects between several mono inputs.

You also don’t need to output to the soundcard. The WaveFileReader will happily write multi-channel WAV files. However, there are no guarantees about how other programs will deal with WAVs that have more than two channels in them.

Availability

I’ve already checked in the initial version to the latest codebase, so expect this to be part of NAudio 1.6. The only caution is that I might change the class name if I come up with a better idea.

Tuesday, 10 January 2012

10 Commandments of Inversion of Control Containers

Inversion of Control containers can be a very powerful tool for decoupling spaghetti code in large software systems. However, with any power tool, you can hurt yourself badly if you don’t use it correctly. In this post, I present “10 commandments” to help you avoid causing problems with IoC, with a particular focus on very large software systems with many developers and hundreds of interfaces. I am currently using Unity, but these tips apply to pretty much any IoC container.

1. Configure everything before your first resolve

It is possible to ask the IoC container to resolve an interface before you have finished configuring the container. So long as it knows how to make the interface you asked for and its dependencies, it will have no problem fulfilling your request. But if your application hasn’t yet finished configuring the container yet, you run the risk of getting the wrong thing. Consider the following simple example:

IUnityContainer container = new UnityContainer();
container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
var f1 = container.Resolve<IFoo>();

Fairly straightforward, we ask for IFoo and get an instance of Foo. But what if we hadn’t quite finished configuring the container, and some other part in your app attempts to override the registration for IFoo:

container.RegisterType<IFoo, Foo2>(new ContainerControlledLifetimeManager());

Now, whenever we attempt to resolve IFoo, we get Foo2. But the initial component that did an early resolve is using the wrong implementation. This can make for horrible debugging sessions. Configure your container completely, before you start to resolve things from it. Which leads us to our second commandment…

2. Don’t pass the container around

What I mean here, is don’t pass around the top-level interface that allows further configuration of the container. In Unity, this is the IUnityContainer interface. It might feel very powerful to send it around, since it allows other parts of your application register new rules, but it opens the door for the kind of bugs we just discussed.

But what about just a Service Locator interface. Can I pass one of those around? Onto commandment 3…

3. Avoid passing an IServiceLocator around

Passing a service locator in as a dependency gives your class great power. It can ask for anything it wants, which is super convenient. But it also introduces some problems.

First, it means your class no longer advertises what it needs in the constructor. Without examining the code you can’t be sure what needs to be in the container for the class to work correctly. It means that unit tests, or callers of your class that aren’t using a container, will have to mock a container just to instantiate your class.

This has been called the “Hollywood principle” – Don’t call the DI Container, it’ll call you. Just put the interfaces you really need in your constructor.

4. Avoid making the container a singleton

Making your container a singleton is the quickest route to providing access to all your services everywhere in your application. It can seem like a great idea because wherever you are, you can just do this to get whatever interface you like:

var foo = MyContainer.Instance.Resolve<IFoo>();

But there are two big problems. First, this introduces hidden dependencies into your class. Instead of your constructor advertising its dependencies, we again must examine the code to know what needs to be set up in the container.

Second, it assumes that all parts of your application will work with the same container, and the same implementations of each interface. This may be true for small applications, but in large enterprise systems, there may well be the need for multiple IoC containers. In our systems, we make use of Unity child containers, allowing different sections of the application get access to their own implementations of interfaces. With a singleton container, this is impossible.

5. Avoid constructor bloat

One of the great things about IoC containers is that you don’t have to call constructors yourself – the container does the hard work for you. This means you can have a dozen constructor parameters, each representing a different dependency, and yet without ever having to write code that calls it.

public MyClass(IFoo foo, IFoo2 foo2, ILog log, IExporter exporter, IEmailer emailer, ISettings settings, IAudit audit)
{
}

That is, until you want to test it. Then you have to mock up all of those interfaces. And probably you will find that your class only needs to call one or two methods on each. This is the time to apply the Interface Segregation Principle and replace them with one or two more focussed interfaces that represent the real dependencies of your class under test.

6. Avoid property injection

Most IoC containers offer a way to let you put attributes on properties in order to tell the container that it needs to set that property after constructing the object. In Unity you use the Dependency attribute:

class Bar
{
    [Dependency]
    public IFoo Foo { get; set; }

    public Bar()
    {
    }
}

Although this seems like a great feature, it has the effect of hiding this dependency from anyone who is constructing your object without an IoC container. At the very least, your class should report a good error message if someone forgets to set up a property dependency.

7. Document your interfaces

If you are using an IoC container, chances are you are working on a large system, and other developers are resolving interfaces that you put in the container.

Often developers will add good comments to the concrete implementation of a class, but spend very little time commenting the interface (who likes to write the same comments twice?). So in the concrete class we might have a comment like this:

/// <summary>
/// Call this to process all the files in the InputFiles collection, using the rules from the Rules collection
/// </summary>
/// <param name="mode">Processing mode, 0 = replace, 1 = update, 2 = overwrite, 3 = test only</param>
public void Process(int mode)

but in the interface, we couldn’t be bothered to type that all again (and we hate cutting and pasting anyway) so we just have this:

/// <summary>
/// Process
/// </summary>
void Process(int mode);

But it is the interface that is the public API for your service. The comments on the interface will be used to display Intellisense to the user. The caller may not even have access to the code for the concrete implementation. If you are going to spend time writing good comments, write them on the interface. Here’s the difference in intellisense experience:

bad-intellisense

versus:

good-intellisense

8. Don’t depend on Dispose in a specific order

When you Dispose your IoC container, it will go through all of the IDisposable instances it knows about and call Dispose on them. But this can introduce a problem, because we cannot guarantee the order the services are disposed in. If you make a call into another service in your Dispose method, how do you know that service hasn’t already been Disposed?

Instead, design your services in such a way that they can be disposed in any order, and use events or some other form of messaging to report to your system that a shutdown is about to happen, allowing any last minute logging, saving etc to be done beforehand, while all the services are still up and running.

9. Make sure Lifetime Management is communicated

If you call Resolve<IFoo> twice on your IoC container, you might get two new instances of the Foo class, or you might get the same one twice. Without looking at how your container is configured, you have no way of knowing. But this can be a real headache if IFoo implements IDisposable. How do you know whether you ought to call Dispose on it or not?

I don’t know of any slick solution to this, but I would typically avoid instances where a Resolve gives you something you need to Dispose yourself. Instead I would return a factory object that makes it very clear you are building a new instance that you are in control of its lifetime yourself. Whatever approach you use, make sure your whole development team understands it. You don’t want someone Disposing a service too early, resulting in the next person to use it getting a nasty exception.

10. Document your public API

In a large system, a container can easily fill up with a lot of interfaces. The trouble is, not all of these are at the same level. Some are high-level interfaces, allowed to be called from anywhere, whilst other things are only in the container so they can fulfil the dependencies of those high-level interfaces. It means that you run the risk of developers guessing incorrectly about which interface they are supposed to call to achieve a particular task. They will assume that if they can get at it from the container, then they must be allowed to call it.

Now there are ways of having interfaces defined in your container that people can’t get at from the wrong place by making good use of assemblies and the internal keyword, but really, you need to make it easy for developers to know what is in the container and how they are intended to use it. This may well involve maintaining an API document, and also means writing good comments on the interface. If you don’t do this, don’t be surprised to see code that inadvertently circumvents key functionality by calling into a component at too low a level, or the wheel being reinvented, simply because a developer didn’t know the container included a service that had the desired behaviour.

Do you have any tips for getting the best out of IoC containers? Please let me know in the comments.

Sunday, 18 December 2011

NAudio 1.5 Released

I have finally got round to releasing the long overdue version 1.5 of NAudio. There are loads of bugfixes and improvements, so I recommend upgrading if possible. Here’s the highlights.

  • Now available on NuGet!
  • Numerous bugfixes mean we are now working fully in x64 as well as x86, so NAudio.dll is now marked as AnyCPU. (You can still force x86 by marking your own executable as x86 only.)
  • WaveOutEvent – a new WaveOut mode with event callback, highly recommended instead of WaveOut with function callbacks
  • 24 bit ASIO driver mode (LSB)
  • Float LSB ASIO driver mode
  • WaveFileWriter has had a general code review and API cleanup
  • Preview of new ISampleProvider interface making it much easier to write custom 32 bit IEEE (float) audio pipeline components, without the need to convert to byte[]. Lots of examples in NAudioDemo of using this and more documentation will follow in future.
  • Several ISampleProvider implementations to get you started. Expect plenty more in future NAudio versions:
    • PanningSampleProvider
    • MixingSampleProvider
    • MeteringSampleProvider
    • MonoToStereoSampleProvider
    • NotifyingSampleProvider
    • Pcm16BitToSampleProvider
    • Pcm8BitToSampleProvider
    • Pcm24BitToSampleProvider
    • SampleChannel
    • SampleToWaveProvider
    • VolumeSampleProvider
    • WaveToSampleProvider
  • Added AiffFileReader courtesy of Giawa
  • AudioFileReader to simplify opening any supported file, easy volume control, read/reposition locking
  • BufferedWaveProvider uses CircularBuffer instead of queue (less memory allocations)
  • CircularBuffer is now thread-safe
  • MP3Frame code cleanup
  • MP3FileReader throws less exceptions
  • ASIOOut bugfixes for direct 16 bit playback
  • Some Demos added to NAudioDemo to give simple examples of how to use the library
    • NAudioDemo has an ASIO Direct out form, mainly for testing the AsioOut class at different bit depths (still recommended to convert to float before you get there).
    • NAudioDemo has simple MP3 streaming form (play MP3s while they download)
    • NAudioDemo has simple network streaming chat application
    • NAudioDemo playback form uses MEF to make it much more modular and extensible (new output drivers, new file formats etc)
    • NAudioDemo can play aiff
  • GSM 6.10 ACM codec support
  • DSP Group TrueSpeech ACM codec support
  • Fully managed G.711 a-law and mu-law codecs (encode & decode)
  • Fully managed G.722 codec (encode & decode)
  • Example of integration with NSpeex
  • Fix to PlaybackStopped using SyncContext for thread safety
  • Obsoleted IWavePlayer.Volume (can still set volume on WaveOut directly if you want)
  • Improved FFT display in WPF demo
  • WaveFileReader - tolerate junk after data chunk
  • WaveOut constructor detects if no sync context & choose func callbacks
  • WaveOut function mode callbacks hopefully chased out the last of the hanging bugs (if in a WaveOutWrite at same time as WaveOutReset, bad things happen - so need locks, but if WaveOutReset called during a previous func callback that is about to call waveOutWrite we deadlock)
  • Now has an msbuild script allowing me to more easily create releases, run tests etc
  • Now using Mercurial for source control, hopefully making bug fixing old releases and accepting user patches easier. n.b. this unfortunately means all old submitted patches are no longer available for download on the CodePlex page.
  • WPF Demo enhancements:
    • WPF Demo is now .NET 4, allowing us to use MEF, and will be updated hopefully with more examples of using NAudio.
    • WPF Demo uses windowing before FFT for a more accurate spectrum plot
    • WPF Demo has visualization plugins, allowing me to trial different drawing mechanisms
    • WPF Demo has a (very basic) drum machine example

I also intend that this will be the last NAudio that targets .NET 2.0 (1.6 will be .NET 3.5). Let me know if you have any objections.

Hope you have fun using it, and do send me the links to any cool stuff you make with it.

Tuesday, 29 November 2011

Creating Zip Files with IronPython

I’ve been working on automating some of the parts of the release process for NAudio, as I always seem to forget something or make a mistake. One of the tasks was to create a “demo” zip file containing the demo applications together with their supporting files.

I initially attempted to do this with MSBuild and the Zip task from MSBuild Community Extensions, but I ended up double-adding a number of files, as well as struggling to get exactly the right folder structure.

This is exactly the sort of task that Python excels at, and Python comes with the zipfile module built in, meaning that the script I wrote is not IronPython specific. Here’s what I came up with:

import zipfile
import os

folders = ['AudioFileInspector','NAudioDemo','NAudioWpfDemo']
files = {}

def exclude(filename):
    return filename.endswith('.pdb') or ('nunit' in filename)

for folder in folders:
    fullpath = folder + "\\bin\\debug\\"
    for filename in os.listdir(fullpath):
        if not exclude(filename):
            files[filename] = fullpath + filename

zip = zipfile.ZipFile("BuildArtefacts\\test.zip", "w")

for filename, fullpath in files.iteritems():
    if os.path.isdir(fullpath):
        for subfile in os.listdir(fullpath):
            zip.write(fullpath + "\\" + subfile, filename + "\\" + subfile)
    else:
        zip.write(fullpath, filename)

zip.close()

There's not a lot to it really. I first build up a dictionary containing the files I want in my zip, using the filename to exclude duplicates. Then I use the write method on zipfile to specify the file I want to add, and the folder it belongs in.

My Python skills are a bit rusty, so the code above would probably benefit from being refactored a little, but as you can see, it is very easy, and much simpler than fighting MSBuild to make it do what I want.