Almost 25 years ago, I created NAudio, an open-source audio library for .NET. Over the years I've had periods where I've done a lot of work on it, and periods where I barely touched it. That's certainly been the case recently, partly because I've been busy with other projects, and partly because creating a version 3 of NAudio requires extensive modernization and refactoring, which under normal circumstances would be impossible for me to find time for.
Claude Code
However recently, Anthropic's "Claude for Open Source" program very generously offered me six month's free access to their "20x Max subscription plan". This allowed me to try Claude Code for the first time (I'd been mainly using GitHub Copilot and Google Gemini previously), and gave me freedom to attempt some extremely ambitious coding tasks without worrying about burning through my token allowance too quickly.
I decided to run an experiment to see how well Claude Code could assist with modernizing the NAudio codebase, including adding some of my most wanted features that were previously out of scope due to their size.
Modernization
The first item on my to-do list was a wide-ranging modernization of the NAudio codebase. Right from the start of NAudio I've always tried to support as many versions of Windows and .NET as possible, and while I'm proud of how long I have kept that going, it has got in the way of adopting new features from .NET Core.
For example, the Span<T> feature is perfect for NAudio, but to fully embrace it means dropping support for the legacy .NET Framework. Another area that was in need of an overhaul was the COM interop, moving to the newer [GeneratedComInterface] approach instead of [ComImport] which opens the door to supporting IL trimming and Native AOT. I also wanted to tidy up the project structure, to clearly distinguish between the Windows specific, and cross-platform capabilities of NAudio.
Pair Programming with AI
What makes using coding assistants like Claude Code so fun is being able to treat them as an expert pair programmer, and run your crazy ideas past it. It's a great way to discover alternative approaches you hadn't thought of.
This was particularly valuable for revisiting some of my original API design decisions that I wasn't happy with. Some of these were due to my own inexperience, while others made sense in the past but are now well past their best-before date.
Examples include rethinking the approach to supporting custom chunks in WaveFileReader (which currently requires inheritance for every customized chunk), reconsidering how best to allow you to decorate a WaveStream with ISampleProvider effects without needing to hold a reference to the start and end of the chain in order to support repositioning, and considering whether the very Windows MME-centric WaveFormat class (based on WAVEFORMATEX) is the best approach or whether I should make a more generic abstraction (e.g. AudioFormat).
For each of these big design decisions, including how to make ASIO playback and recording much more pleasant to work with, I held an in-depth discussion with Claude Code up front. This helped solidify API design and make naming decisions that I was happy with, as well as thrashing out implementation plans that include testing and documentation.
With a well-defined concrete plan in place, in most cases I was able to just let Claude get on with the implementation. I did find myself needing to interrupt and course correct sometimes, but often I'd just do a thorough code review at the end. I'm still convinced that a manual code review of AI-generated code is vital. It regularly uncovered issues that I hadn't considered up front, and often resulted in several additional rounds of refactoring.
Test Coverage
AI assistants can be quite lazy about testing. They are so focused on achieving the 'goal' that they'll happily write code with no tests at all, or ask you to manually try things out for them and report back! You need to be clear about what level of testing you expect from them.
There are several areas of NAudio that were lacking in their unit test coverage. For example, Fast Fourier Transforms and pitch shifting algorithms are not straightforward to validate, especially if you don't fully trust your own DSP skills. So it was useful to get Claude Code to introduce sanity checks for some of these trickier areas.
Of course many NAudio capabilities require true "integration/end-to-end" testing. I need to play and record audio through real soundcards, and listen to the output of various operations such as decoding MP3s or applying audio effects in order to be confident that things are working as expected.
For years I've mostly made use of two test harnesses - one WinForms and one WPF app. These are very useful, but I've always wanted a console-based test harness, with a menu system that I could use to pick which test to run, but that would also support scripting so it could automatically run through a series of tests, and generate a test report, recording what tests were run, any errors encountered, and details of the system on which it was run. This would make it much easier for NAudio users to submit bug reports.
I got Claude Code to quickly scaffold my console test harness idea, and while it's still far from finished, it has already greatly accelerated the speed at which I can validate new features. It's an example of where a more "vibe coding" approach can be used - where you don't really need detailed scrutinization of all of the code generated, but just try it and see if it works. With auxiliary utilities like this, the stakes are a lot lower and technical debt is not really a major concern.
One of the primary goals of introducing Span<T> into NAudio was improved performance, but just updating the public interface to use Span<T> wasn't enough. I had to flow that right through many of the classes in NAudio all the way into the interop layer, eliminating as many unnecessary copies as possible. Again this was something that Claude Code was able to greatly accelerate as it was able to search through hundreds of files and propose strategies for wide-scale refactoring that previously would have taken me days to plan.
It was also able to take additional steps to improve performance. For example there are some parts of NAudio that would benefit from vectorization and SIMD optimizations, which are not my speciality at all. But with sufficient unit tests in place, I could safely implement the vectorization performance optimizations that it had recommended and backed them up with a BenchmarkDotNet project to validate and quantify how much faster the new code actually was.
Memory Management and Interop
A large part of NAudio consists of COM interop to Windows APIs, and that poses some tricky memory management challenges. In particular, COM works by reference counting, but .NET uses a mark and sweep approach to garbage collection and so bridging the two worlds can be complicated, and it can be difficult to know when it's safe to dispose of COM objects. I was able to discuss this problem with Claude Code and come up with a consistent strategy for how I wanted memory management to behave. And then was able to quickly get it to roll that out across all of the WASAPI API wrappers in NAudio.
I was also able to get it to audit the coverage of Windows audio APIs and identify missing capabilities. This has allowed me to fill in a number of key gaps in NAudio. It wasn't all plain sailing though. Some of the capabilities offered by the Windows audio APIs have proved incredibly challenging to successfully wrap in C#. One of the most difficult so far is capturing audio from a specific process, which I'd spent many hours trying to do manually before using AI and every time failed miserably. And when I tried using Claude Code I ran into exactly the same problems and have had several failed attempts. I've not completely given up yet - hopefully the next try will be the successful one, but it certainly feels a lot less risky to attempt tasks like this now - a failed attempt is now just a few hours rather than days of wasted time.
Challenging Features
Although NAudio has lots of features, there are many missing capabilities that I would love to offer but have simply been too difficult for me to implement. Often it's a skill issue - I don't have enough deep understanding of digital signal processing or interop. But it's just as often a time constraint problem.
One of the great things about AI assistants like Claude Code is that (almost) no task is too daunting to attempt. Now I can realistically consider taking on challenges like creating my own synthesiser or VST3 plugin wrapper. So it's been really enjoyable with Claude Code to start tackling some of the more ambitious ideas on my backlog.
As a simple example of something I really struggled with many years back was creating a spectrum analyzer visualization in WPF. This required me to work out what the best FFT windowing function to use was, and decide things like whether I should use linear or logarithmic scales for each axis.
So it was fascinating to talk through all of my questions with Claude Code and discuss each of the existing design decisions and my concerns about what I'd got wrong and what I wanted to be improved. Within a short period of time it had discovered several mistakes in my original implementation, and created a much better visualization.

Bug and PR backlog
One of my biggest regrets as a maintainer of an open source project like NAudio is that it has simply not been possible for me to keep up with the rate of issues and PRs that I've received. Several years ago I reached the point where I wasn't able to reply to every single issue any more. That means there's probably many valid bugs and feature requests that deserve to be looked at, and also probably many excellent contributions sitting idle that are worthy of being merged into the NAudio code base.
So one of the next tasks I have with Claude Code is to see if it can help me triage all of these legacy issues and pull requests. This will let me close the ones that don't make sense to keep open any more but also to respond to many of the existing issues, and fix the bugs that have been reported. For pull requests, the substantial changes in NAudio 3 will mean they won't necessarily merge easily, but it should be possible to take the key ideas and reimplement them in a way that fits with the NAudio 3 design.
I've made a small start on this recently, so if you're wondering why your bug report from 2017 is suddenly being looked at, you'll know why!
Documentation
Documenting a library like NAudio is a major task, and although I've written many blog posts and tutorials, there's certainly a lot of scope for improvement. Again this is something Claude Code is able to help a lot with. I've already asked it to audit all of the existing documentation, check it for mistakes and correct it.
I've also used it to draft tutorials for the new features, and I'm also eager to use it to generate a migration guide. This will be especially valuable for NAudio 3, as I have decided to allow myself to make a number of strategic breaking changes to the API. A good migration document should allow users to point their own coding assistants at it and get upgraded relatively painlessly.
Can I trust its output?
Perhaps the biggest question in the software development industry at the moment is this - can we really trust AI coding assistants to create high-quality, production-ready code? Are we in danger of just accepting code that seems superficially correct, but under the hood and behind the scenes, significant bugs or architectural issues have been introduced?
Certainly, it's not all been plain sailing even with Claude Code's most powerful Opus models. In fact, some of the recent work I've used it on to completely rewrite the COM interop has surfaced some extremely challenging access violations that have taken hours to troubleshoot (and in fact as I write this there's still a really nasty one I'm struggling to get to the bottom of).
AI coding assistants can fail in less spectacular ways as well. They might simply ignore instructions, or accidentally drop an important line of code while refactoring some code. Or they might decide to implement a requirement that I didn't ask for or want. Or everything might seem great but after "speed-running" your way through several large features you discover you hadn't fully validated an earlier feature and now have to go back and unpick the mess.
I've been trying to be disciplined with thorough manual testing and careful reading of all of the code that Claude has generated, asking it questions and challenging its decisions. Often this leads to a much better implementation. But I must also admit that there have been times when I don't fully understand its changes, because it's doing things that are outside my comfort zone, such as modernizing the COM interop mechanisms.
This means I've spent a lot of time running manual tests, trying to find edge cases and race conditions. I'm determined that NAudio 3 is not going to just be a bunch of AI slop, but of course I can't guarantee that it will be bug free. For this reason I intend to release some early "alpha" versions of NAudio 3, allowing people to give feedback on the architectural changes as well as report bugs.
10x Speed-up?
Without doubt, AI has accelerated my progress way beyond what I could have achieved manually. But ironically, I've probably put in way more hours on NAudio 3 as a result of this speed-up than I was ever likely to have done without AI assistance. There are a few reasons for that - one is that the increased speed often results in me expanding the scope accordingly - attempting much more ambitious tasks than I would have previously dared. Another is that some of the access violations introduced by changes to the interop proved extremely time-consuming to root cause - you end up pulling the AI slot-machine lever repeatedly, hoping that this time it will fix the bug.
Another factor is that the huge speed increase allows you to try out wide-scale changes and then completely backtrack on them. The cost of prototyping has dropped dramatically, but that doesn't always result in as much of a speed increase as you might imagine, as you often allow yourself to go much further down a dead end before walking it back.
When is NAudio 3 coming?
I've been working on this modernisation of NAudio for over a month now and have committed a lot of work which you can find on the naudio3dev branch in GitHub if you're interested. There is still a lot that needs to be done, in terms of features to add, design decisions to be finalized and bugs to be fixed. I'm hoping to be in a place fairly soon where I can publish some pre-release NuGet packages allowing people to try out the changes and give me feedback. Hopefully people will be understanding of the reasoning behind making a number of breaking changes to the public API, but if there is enough pushback there will be time to reconsider some of the choices.
I'm also hoping to find some time to blog about a number of the important decisions so watch this space.