---
title: "Transcribe an audio file in C#"
url: https://recursiveai.org/onespeech/cookbook/transcribe-audio-file/
description: "Transcribe audio files to text in C# with OneSpeech. Download a runnable .NET 10 example that saves plain text and transcript JSON."
version: "1.0.0"
---

# Transcribe an audio file in C#

**OneSpeech** is a free, open-source speech recognition library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneSpeech) · [GitHub](https://github.com/recursive-ai-oss/onespeech-csharp) · [Docs](https://recursiveai.org/onespeech/docs/) · [Download example (.zip)](https://recursiveai.org/onespeech/cookbook/transcribe-audio-file/transcribe-audio-file.zip)

Transcribe `sample.flac` (in the zip). First use downloads several GB of models.

```shell
dotnet add package RecursiveAI.OneSpeech
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneSpeech;
var transcript = Speech.Transcribe(
    "sample.flac", language: "en");
File.WriteAllText(
    "transcript.txt", transcript.Text);
Console.WriteLine(transcript.Text);
```

Unzip [the example](https://recursiveai.org/onespeech/cookbook/transcribe-audio-file/transcribe-audio-file.zip), then `dotnet run`.

Prints:

```text
 stuffered into you, his belly counseled him.
```

This is the model’s real output on a real recording, mistake included; `word.Text.Trim()` removes a recognized word’s leading space.

The default recognizer is Whisper large-v3-turbo: its publisher weights are 1,617.8 MB (about 1.62 GB). This English run also loads Qwen3-ForcedAligner (1,835.5 MB of publisher weights) to time words and CAM++ English (29.4 MB) to group speakers; the built-in Silero detector finds speech. Converted runtime files take additional disk space. By default, models are cached in `%LOCALAPPDATA%/OneSpeech/models` on Windows, `~/Library/Caches/OneSpeech/models` on macOS, or `$XDG_CACHE_HOME/onespeech/models` on Linux (falling back to `~/.cache/onespeech/models`). `ONESPEECH_MODEL_CACHE` overrides that location. See [Model files and pre-fetch](https://recursiveai.org/onespeech/docs/models/) and the [download sizes](https://recursiveai.org/onespeech/docs/model-downloads/).

## The full program

The snippet at the top writes `transcript.txt`. The full program also saves the structured transcript as `transcript.json`; pass your own file with `dotnet run -- recording.wav`.

The input `sample.flac` is the unmodified LibriSpeech test-clean recording 1089-134686-0001: “stuff it into you his belly counselled him”. It ships in the zip under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), credited to Vassil Panayotov, Guoguo Chen, Daniel Povey and Sanjeev Khudanpur ([LibriSpeech](https://www.openslr.org/12)).

```csharp
using OneSpeech;

string path = args.Length > 0 ? args[0] : "sample.flac";
Transcript transcript = Speech.Transcribe(path, language: "en");
File.WriteAllText("transcript.txt", transcript.Text);
File.WriteAllText("transcript.json", transcript.ToJson());
Console.WriteLine(transcript.Text);
Console.WriteLine("Saved transcript.txt and transcript.json");
```

`dotnet run` prints:

```text
 stuffered into you, his belly counseled him.
Saved transcript.txt and transcript.json
```

This is the recognizer’s actual output, including its “stuffered” mistake and leading spaces. Missing models download on first use; subsequent runs reuse verified cache files.

Invalid encoded audio throws `UnsupportedAudioException`; model download or integrity failures are reported as typed model errors.

## Variations

**Read an encoded audio stream.** The stream stays caller-owned; `await using` disposes it after the call. Use the same `sample.flac` from the zip.

```csharp
using OneSpeech;

await using var input = File.OpenRead("sample.flac");
Transcript transcript = await Speech.TranscribeAsync(input, language: "en");
Console.WriteLine(transcript.Text);
```

```text
 stuffered into you, his belly counseled him.
```

## Related recipes

- [Speech to text in C#](https://recursiveai.org/onespeech/cookbook/speech-to-text/)
- [Run Whisper in C# without native libraries](https://recursiveai.org/onespeech/cookbook/whisper-dotnet/)
- [Generate SRT subtitles from audio in C#](https://recursiveai.org/onespeech/cookbook/generate-subtitles-from-audio/)
- [Get speech-to-text word timestamps in C#](https://recursiveai.org/onespeech/cookbook/word-timestamps/)

## The short answer

To transcribe an audio file in C#, call `Speech.Transcribe(path, language: "en")` and save the returned `Text` with `File.WriteAllText`. The program above writes both a plain-text transcript and structured JSON. It uses OneSpeech’s default file recognizer, Whisper large-v3-turbo, and runs in managed .NET 10 without a speech-service key.

The input is a real recording, not a stored transcript returned as a placeholder. Its reference wording is “stuff it into you his belly counselled him”. The output printed above is what the recognizer heard, including its mistake. Substitute your own path with `dotnet run -- recording.wav`; keep the language argument appropriate for your recording.

## How can I transcribe an audio file to text?

Start with an existing audio file and choose the result you need. Plain text is useful for reading, indexing or editing; transcript JSON also keeps segments, words, timing methods, models and speaker turns. The full program writes both from the same result, so saving a second format does not run recognition again. See the [JSON schema](https://recursiveai.org/onespeech/docs/transcript-json/) before building a consumer that depends on individual fields.

OneAudio is the .NET audio library that reads encoded sound and converts its sample rate for recognition. The [audio-input docs](https://recursiveai.org/onespeech/docs/audio-input/) list WAV, FLAC, MP3, Ogg Vorbis/Opus, AAC-LC in M4A/3GP/ADTS, and AMR-NB/WB; the core also handles A-law and μ-law WAV. This download uses FLAC so the exact recording can ship with the project. You don’t need to convert this sample to WAV first. An extension alone does not establish that damaged or unsupported encoded data can be read.

A normal whole-file call includes recognition, word timing and speaker clustering. Speaker labels are anonymous and local to a recording. They are not verified names, and the default diarizer does not detect overlapping speech. Missing word boundaries remain null rather than receiving guessed timestamps.

## Can I transcribe audio offline in C#?

Yes, after preparing the models. Missing automatically fetched model files are downloaded on first use; verified existing files need no network request. The file recognizer is only one part of the work: word timing and speaker assignment can need additional models. The [first-use model table](https://recursiveai.org/onespeech/docs/model-downloads/) is the deployment checklist for those dependencies.

Allow for publisher-weight conversion and temporary disk space during initial preparation. A tiny recognizer selection is not a promise of a tiny total download. `ONESPEECH_MODEL_CACHE` chooses the cache directory; keep it in a trusted location writable only by the intended user. The example zip is small because model weights stay in that cache rather than being copied beside every audio file.

## What does a C# audio transcription example need?

For the path-based example, the requirements are the .NET 10 SDK, the pinned package, an input recording and space for the models. The zip supplies the first project and sample recording; NuGet restores the library. First use acquires missing model files. No microphone permission is needed because this program reads a file.

If your application receives a readable encoded stream instead of a path, use the variation above. `TranscribeAsync` does not own or close the caller’s stream. It spools encoded input to a temporary seekable file, with a 512 MiB bound, so recognition and timing replay can revisit the audio. It is not live microphone recognition, and an asynchronous method name does not make CPU inference asynchronous. For input beyond that stream bound, use a local file path. For cancellation or format failures, handle the documented typed errors rather than writing a success message before transcription finishes.
