Skip to content

Commit 55a81e4

Browse files
committed
Standardize API patterns across all file types
API Consistency: - Add TryRead(ReadOnlySpan<byte>, out T?) to all 14 file types - Add TryRead(BinaryData, out T?) convenience overloads - Add SaveToFile(path, originalData) overload to AsfFile, MonkeysAudioFile, WavPackFile, MusepackFile, OggFlacFile - Remove WavFile.ReadFromData (use Read or TryRead instead) - Mark AiffFile.TryParse as obsolete (use TryRead) Core Type Improvements: - Convert AudioProperties from class to readonly record struct - Add VideoProperties readonly record struct - Add ImageProperties readonly record struct - Add MediaTypes enum (Audio, Video, Image, Unknown) - Update IMediaFile interface with MediaTypes, VideoProperties, ImageProperties Test Updates: - Update WavFileTests to use Read().File pattern - Update WavFilePictureTests to use Read().File pattern - Update CrossTaggerCompatibilityTests for new API - Update AiffFileTests to use TryRead instead of TryParse
1 parent 9656d34 commit 55a81e4

38 files changed

Lines changed: 1385 additions & 285 deletions

docs/CORE-TYPES.md

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,308 @@ Standard picture types from ID3v2 and FLAC specifications.
531531
| 0x12 | Illustration | Illustration |
532532
| 0x13 | BandLogo | Band/artist logotype |
533533
| 0x14 | PublisherLogo | Publisher/studio logotype |
534+
535+
---
536+
537+
## IMediaProperties Interface
538+
539+
Interface for audio/video stream properties. Implemented by `AudioProperties` struct and format-specific classes.
540+
541+
### Properties
542+
543+
| Property | Type | Description |
544+
|----------|------|-------------|
545+
| `Duration` | `TimeSpan` | Duration of the media |
546+
| `Bitrate` | `int` | Bitrate in kbps (0 if unknown) |
547+
| `SampleRate` | `int` | Sample rate in Hz (0 if unknown) |
548+
| `BitsPerSample` | `int` | Bit depth (0 for lossy formats) |
549+
| `Channels` | `int` | Number of audio channels |
550+
| `Codec` | `string?` | Codec name (e.g., "FLAC", "MP3") |
551+
552+
### Usage
553+
554+
```csharp
555+
// Access through IMediaFile interface
556+
IMediaFile file = MediaFile.Open("song.flac");
557+
IMediaProperties? props = file.AudioProperties;
558+
559+
if (props is not null)
560+
{
561+
Console.WriteLine($"Duration: {props.Duration}");
562+
Console.WriteLine($"Sample Rate: {props.SampleRate} Hz");
563+
Console.WriteLine($"Bitrate: {props.Bitrate} kbps");
564+
Console.WriteLine($"Codec: {props.Codec}");
565+
}
566+
```
567+
568+
---
569+
570+
## AudioProperties Struct
571+
572+
Immutable value type representing audio stream properties. Implements `IMediaProperties`.
573+
574+
### Definition
575+
576+
```csharp
577+
public readonly record struct AudioProperties(
578+
TimeSpan Duration,
579+
int Bitrate,
580+
int SampleRate,
581+
int BitsPerSample,
582+
int Channels,
583+
string? Codec = null) : IMediaProperties
584+
```
585+
586+
### Properties
587+
588+
| Property | Type | Description |
589+
|----------|------|-------------|
590+
| `Duration` | `TimeSpan` | Audio duration |
591+
| `Bitrate` | `int` | Bitrate in kbps |
592+
| `SampleRate` | `int` | Sample rate in Hz |
593+
| `BitsPerSample` | `int` | Bit depth |
594+
| `Channels` | `int` | Channel count |
595+
| `Codec` | `string?` | Codec name |
596+
| `IsValid` | `bool` | True if Duration > 0 and SampleRate > 0 |
597+
598+
### Static Members
599+
600+
| Member | Description |
601+
|--------|-------------|
602+
| `Empty` | Returns a default (empty) instance |
603+
| `FromFlac(...)` | Creates from FLAC stream info |
604+
| `FromVorbis(...)` | Creates from Vorbis identification header |
605+
| `FromOpus(...)` | Creates from Opus identification header |
606+
| `FromDsf(...)` | Creates from DSF (DSD) file info |
607+
| `FromDff(...)` | Creates from DFF (DSDIFF) file info |
608+
609+
### Usage
610+
611+
```csharp
612+
// Create directly
613+
var props = new AudioProperties(
614+
Duration: TimeSpan.FromMinutes(3.5),
615+
Bitrate: 320,
616+
SampleRate: 44100,
617+
BitsPerSample: 16,
618+
Channels: 2,
619+
Codec: "MP3");
620+
621+
// Check validity
622+
if (props.IsValid)
623+
Console.WriteLine($"Duration: {props.Duration:mm\\:ss}");
624+
625+
// Create for FLAC
626+
var flacProps = AudioProperties.FromFlac(
627+
totalSamples: 10584000,
628+
sampleRate: 44100,
629+
bitsPerSample: 16,
630+
channels: 2);
631+
```
632+
633+
### Performance Note
634+
635+
`AudioProperties` is a `readonly record struct`, meaning:
636+
- Zero heap allocations when stored as a field or local variable
637+
- Value semantics (copied on assignment)
638+
- Equality based on all property values
639+
640+
---
641+
642+
## VideoProperties Struct
643+
644+
Immutable value type representing video stream properties.
645+
646+
### Definition
647+
648+
```csharp
649+
public readonly record struct VideoProperties(
650+
TimeSpan Duration,
651+
int Width,
652+
int Height,
653+
int Bitrate,
654+
double FrameRate,
655+
string? Codec = null)
656+
```
657+
658+
### Properties
659+
660+
| Property | Type | Description |
661+
|----------|------|-------------|
662+
| `Duration` | `TimeSpan` | Video duration |
663+
| `Width` | `int` | Frame width in pixels |
664+
| `Height` | `int` | Frame height in pixels |
665+
| `Bitrate` | `int` | Bitrate in kbps |
666+
| `FrameRate` | `double` | Frames per second |
667+
| `Codec` | `string?` | Codec name (e.g., "H.264", "VP9") |
668+
| `IsValid` | `bool` | True if Width > 0 and Height > 0 |
669+
670+
### Static Members
671+
672+
| Member | Description |
673+
|--------|-------------|
674+
| `Empty` | Returns a default (empty) instance |
675+
676+
### Usage
677+
678+
```csharp
679+
var video = new VideoProperties(
680+
Duration: TimeSpan.FromMinutes(90),
681+
Width: 1920,
682+
Height: 1080,
683+
Bitrate: 5000,
684+
FrameRate: 23.976,
685+
Codec: "H.264");
686+
687+
Console.WriteLine($"Resolution: {video.Width}x{video.Height}");
688+
Console.WriteLine($"Frame rate: {video.FrameRate:F2} fps");
689+
```
690+
691+
---
692+
693+
## ImageProperties Struct
694+
695+
Immutable value type representing image properties.
696+
697+
### Definition
698+
699+
```csharp
700+
public readonly record struct ImageProperties(
701+
int Width,
702+
int Height,
703+
int ColorDepth = 0,
704+
string? Format = null)
705+
```
706+
707+
### Properties
708+
709+
| Property | Type | Description |
710+
|----------|------|-------------|
711+
| `Width` | `int` | Image width in pixels |
712+
| `Height` | `int` | Image height in pixels |
713+
| `ColorDepth` | `int` | Bits per pixel (24 for RGB, 32 for RGBA) |
714+
| `Format` | `string?` | Image format (e.g., "JPEG", "PNG") |
715+
| `IsValid` | `bool` | True if Width > 0 and Height > 0 |
716+
717+
### Static Members
718+
719+
| Member | Description |
720+
|--------|-------------|
721+
| `Empty` | Returns a default (empty) instance |
722+
723+
### Usage
724+
725+
```csharp
726+
var image = new ImageProperties(
727+
Width: 3000,
728+
Height: 3000,
729+
ColorDepth: 24,
730+
Format: "JPEG");
731+
732+
Console.WriteLine($"Size: {image.Width}x{image.Height}");
733+
Console.WriteLine($"Color depth: {image.ColorDepth} bpp");
734+
```
735+
736+
---
737+
738+
## MediaTypes Enum
739+
740+
Flags enum indicating types of media content in a file.
741+
742+
### Definition
743+
744+
```csharp
745+
[Flags]
746+
public enum MediaTypes
747+
{
748+
None = 0,
749+
Audio = 1 << 0, // 1
750+
Video = 1 << 1, // 2
751+
Image = 1 << 2 // 4
752+
}
753+
```
754+
755+
### Values
756+
757+
| Value | Description |
758+
|-------|-------------|
759+
| `None` | No media content |
760+
| `Audio` | Contains audio stream(s) |
761+
| `Video` | Contains video stream(s) |
762+
| `Image` | Contains image content |
763+
764+
### Usage
765+
766+
```csharp
767+
MediaTypes types = file.MediaTypes;
768+
769+
if (types.HasFlag(MediaTypes.Audio))
770+
Console.WriteLine("Has audio");
771+
772+
if (types.HasFlag(MediaTypes.Video))
773+
Console.WriteLine("Has video");
774+
775+
// Check for multiple types
776+
if (types == (MediaTypes.Audio | MediaTypes.Video))
777+
Console.WriteLine("Audio+Video container");
778+
```
779+
780+
---
781+
782+
## IMediaFile Interface
783+
784+
Interface for media file containers with tags and properties.
785+
786+
### Properties
787+
788+
| Property | Type | Description |
789+
|----------|------|-------------|
790+
| `Tag` | `Tag?` | Primary metadata tag |
791+
| `AudioProperties` | `IMediaProperties?` | Audio stream properties |
792+
| `VideoProperties` | `VideoProperties?` | Video stream properties |
793+
| `ImageProperties` | `ImageProperties?` | Image properties |
794+
| `MediaTypes` | `MediaTypes` | Types of media in the file |
795+
| `SourcePath` | `string?` | File path if read from disk |
796+
| `Format` | `MediaFormat` | Detected file format |
797+
798+
### Usage
799+
800+
```csharp
801+
using IMediaFile file = MediaFile.Open("song.flac");
802+
803+
// Access tag metadata
804+
if (file.Tag is not null)
805+
{
806+
Console.WriteLine($"Title: {file.Tag.Title}");
807+
Console.WriteLine($"Artist: {file.Tag.Artist}");
808+
}
809+
810+
// Check media types
811+
if (file.MediaTypes.HasFlag(MediaTypes.Audio))
812+
{
813+
var props = file.AudioProperties;
814+
if (props is not null)
815+
Console.WriteLine($"Duration: {props.Duration:mm\\:ss}");
816+
}
817+
818+
// Format detection
819+
Console.WriteLine($"Format: {file.Format}");
820+
```
821+
822+
### Supported Formats
823+
824+
| Format | Audio | Video | Image |
825+
|--------|:-----:|:-----:|:-----:|
826+
| FLAC || | |
827+
| MP3 || | |
828+
| Ogg Vorbis || | |
829+
| Ogg Opus || | |
830+
| WAV || | |
831+
| AIFF || | |
832+
| MP4/M4A || | |
833+
| ASF/WMA || | |
834+
| DSF (DSD) || | |
835+
| DFF (DSDIFF) || | |
836+
| Monkey's Audio || | |
837+
| WavPack || | |
838+
| Musepack || | |

src/TagLibSharp2/Aiff/AiffAudioProperties.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace TagLibSharp2.Aiff;
2525
/// <item>Bytes 22+: Compression name (Pascal string)</item>
2626
/// </list>
2727
/// </remarks>
28-
public class AiffAudioProperties
28+
public class AiffAudioProperties : IMediaProperties
2929
{
3030
/// <summary>
3131
/// Minimum size of the COMM chunk data for AIFF.
@@ -94,6 +94,14 @@ public class AiffAudioProperties
9494
/// </remarks>
9595
public string? CompressionName { get; }
9696

97+
/// <summary>
98+
/// Gets the codec name for this audio format.
99+
/// </summary>
100+
/// <remarks>
101+
/// Returns "AIFF" for standard AIFF files, or the compression type for AIFC files.
102+
/// </remarks>
103+
public string? Codec { get; }
104+
97105
AiffAudioProperties (int channels, uint sampleFrames, int bitsPerSample, int sampleRate,
98106
string? compressionType = null, string? compressionName = null)
99107
{
@@ -103,6 +111,7 @@ public class AiffAudioProperties
103111
SampleRate = sampleRate;
104112
CompressionType = compressionType;
105113
CompressionName = compressionName;
114+
Codec = compressionType ?? "AIFF";
106115

107116
// Calculate duration
108117
if (sampleRate > 0 && sampleFrames > 0)

0 commit comments

Comments
 (0)