---
title: "Generate SRT subtitles from audio in C#"
url: https://recursiveai.org/onespeech/cookbook/generate-subtitles-from-audio/
description: "Generate SRT subtitles from audio in C# with OneSpeech. Download a runnable .NET 10 example, export captions, and remove leading caption spaces."
version: "1.0.0"
---

# Generate SRT subtitles from audio 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.Media) · [GitHub](https://github.com/recursive-ai-oss/onespeech-csharp) · [Docs](https://recursiveai.org/onespeech/docs/) · [Download example (.zip)](https://recursiveai.org/onespeech/cookbook/generate-subtitles-from-audio/generate-subtitles-from-audio.zip)

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

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

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

```csharp
using OneSpeech;
using OneSpeech.Media;
var transcript = Speech.Transcribe(
    "sample.flac", language: "en");
File.WriteAllText(
    "subtitles.srt", transcript.ToSrt());
```

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

Writes `subtitles.srt` with the cue printed below.

## The full program

The snippet at the top writes `subtitles.srt`. The full program prints the exact contents of that file as well.

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;
using OneSpeech.Media;

Transcript transcript = Speech.Transcribe("sample.flac", language: "en");
string srt = transcript.ToSrt();
File.WriteAllText("subtitles.srt", srt);
Console.Write(srt);
```

`dotnet run` prints:

```text
1
00:00:00,546 --> 00:00:02,786
 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/).

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.

If a caption has no known time bounds, `ToSrt()` throws `CapabilityNotSupportedException` instead of inventing a duration.

## Variations

**Remove caption-line padding.** Leading spaces are visible text padding, not invalid SRT syntax or changed timing; trim each exported line if you don’t want that padding.

```csharp
using OneSpeech;
using OneSpeech.Media;

var transcript = Speech.Transcribe("sample.flac", language: "en");
string trimmed = string.Join("\n", transcript.ToSrt()
    .Split('\n').Select(line => line.Trim()));
File.WriteAllText("subtitles.srt", trimmed);
Console.Write(trimmed);
```

```text
1
00:00:00,546 --> 00:00:02,786
stuffered into you, his belly counseled
him.
```

## Related recipes

- [Speech to text in C#](https://recursiveai.org/onespeech/cookbook/speech-to-text/)
- [Transcribe an audio file in C#](https://recursiveai.org/onespeech/cookbook/transcribe-audio-file/)
- [Run Whisper in C# without native libraries](https://recursiveai.org/onespeech/cookbook/whisper-dotnet/)
- [Get speech-to-text word timestamps in C#](https://recursiveai.org/onespeech/cookbook/word-timestamps/)

## The short answer

To generate SRT subtitles from audio in C#, transcribe the recording with OneSpeech, then call the `ToSrt()` extension from `RecursiveAI.OneSpeech.Media` and save its string. The extension builds timed caption cues from the transcript; you don’t need to format timestamp strings or divide the recording into arbitrary equal-length blocks yourself.

The sample writes a real SRT file and prints its contents. It includes a recognition error from the audio run, not a corrected reference transcript. Proofread the caption text and watch it against the recording before delivering it. You can remove leading caption spaces after export without running recognition a second time.

## How do I generate an SRT file from audio in C#?

The full program shows the two stages: recognition produces a transcript; caption export turns it into a subtitle string. For this FLAC input, installing the Media package supplies the caption extensions and the core library transitively. No decoder registration is needed for this FLAC recording or for SRT export.

The [caption policy](https://recursiveai.org/onespeech/docs/media/) starts with each recognized stretch of speech. When every word has a time, it starts a new caption when the speaker changes, the text reaches 84 character units, or it spans six seconds. It wraps lines at 42 character units without breaking a word. These counts use .NET’s UTF-16 character units. A single long word or a word with a long time interval can exceed those targets. The sample uses these built-in rules without configuring them.

If a segment has an untimed word, it stays one wrapped cue because there is no measured evidence for extra split boundaries. Completely untimed cues make the string export throw `CapabilityNotSupportedException`. The writer does not fabricate a duration merely to make an SRT file possible. Correct or align the affected transcript before retrying that export.

## Can I generate SRT subtitles for free?

Yes. The OneSpeech library and the Media package are open source under MIT or Apache-2.0. The example needs no subscription or speech-service key. Model weights have their own licenses; the models used here are MIT or Apache-2.0, as listed in the [overview](https://recursiveai.org/onespeech/docs/overview/).

The initial run downloads missing model files and may convert verified publisher weights locally. Plan for several GB of disk use and sufficient memory; the small project zip is not a bundle of the recognition weights. Once verified files are cached, the transcription path can reuse them without network requests. Caption export itself downloads no models. It only consumes the transcript you already have.

## How do I convert text to SRT?

Plain text alone lacks the start and end times an SRT cue needs. If you have the original audio, speech recognition supplies timed text, as above. If you already have a corrected transcript and need to locate its words in a recording, forced alignment is the relevant task: it maps supplied text to audio instead of recognizing new wording. OneSpeech has a separate [alignment API](https://recursiveai.org/onespeech/docs/word-timing/), whose standalone helper accepts at most 60 seconds and can leave unalignable words untimed.

SRT keeps cue text and cue times, but not per-word times or speaker identities. Use JSON to retain the full transcript for later processing. Subtitle interchange is not lossless transcript storage. Exporting another caption format cannot repair a recognition error or turn uncertain timing into measured ground truth.
