File size: 4,511 Bytes
bf67612
 
 
 
 
 
 
 
 
 
 
14e5437
bf67612
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14e5437
bf67612
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import os
from typing import Dict, Any

import librosa


def validate_audio_path(audio_path: str) -> str:
    """
    Validate and return absolute path for audio file.

    Args:
        audio_path: Path to audio file or URL (can be relative or absolute)

    Returns:
        Absolute path to audio file

    Raises:
        FileNotFoundError: If file doesn't exist
        ValueError: If path is invalid
    """
    if not audio_path:
        raise ValueError("Audio path cannot be empty")

    # Convert to absolute path
    abs_path = os.path.abspath(audio_path)

    # Check if file exists
    if not os.path.exists(abs_path):
        raise FileNotFoundError(f"Audio file not found: {abs_path}")

    # Check if it's a file (not directory)
    if not os.path.isfile(abs_path):
        raise ValueError(f"Path is not a file: {abs_path}")

    return abs_path


def get_audio_info(audio_path: str) -> Dict[str, Any]:
    """
    Get detailed information about an audio file.

    This function analyzes an audio file and returns comprehensive metadata
    including duration, sample rate, channels, and format information.

    Args:
        audio_path: Path to the input audio file or URL (supports common formats: WAV, MP3, FLAC, M4A)

    Returns:
        Dictionary with audio information:
        {
            "duration": duration_in_seconds,
            "sample_rate": sample_rate,
            "channels": number_of_channels,
            "format": "stereo" or "mono",
            "filename": original_filename,
            "file_size": file_size_bytes,
            "bit_depth": bit_depth_if_available
        }

    Example:
        info = get_audio_info("song.mp3")
        print(f"Duration: {info['duration']} seconds")
        print(f"Sample rate: {info['sample_rate']} Hz")
        print(f"Channels: {info['channels']} ({info['format']})")

    Note:
        Uses librosa for audio analysis which supports most common audio formats
        File size is included for reference
        Bit depth is available for uncompressed formats like WAV
    """
    try:
        # Validate audio path
        validated_path = validate_audio_path(audio_path)

        # Load audio with librosa
        y, sr = librosa.load(validated_path, sr=None, mono=False)

        # Get basic audio info
        duration = len(y) / sr if y.ndim == 1 else len(y[0]) / sr
        channels = 1 if y.ndim == 1 else y.shape[0]
        audio_format = "mono" if channels == 1 else "stereo"

        # Get file info
        filename = os.path.basename(validated_path)
        file_size = os.path.getsize(validated_path)

        # Try to get bit depth for WAV files
        bit_depth = None
        try:
            import soundfile as sf

            with sf.SoundFile(validated_path) as f:
                if hasattr(f, "subtype"):
                    bit_depth = f.subtype
        except Exception:
            pass  # Bit depth not available or error occurred

        return {
            "duration": round(duration, 2),
            "sample_rate": sr,
            "channels": channels,
            "format": audio_format,
            "filename": filename,
            "file_size": file_size,
            "file_size_mb": round(file_size / (1024 * 1024), 2),
            "bit_depth": bit_depth,
            "status": "success",
        }

    except Exception as e:
        return {"status": "error", "message": f"Error analyzing audio: {str(e)}"}


if __name__ == "__main__":
    import argparse
    import json

    parser = argparse.ArgumentParser(
        description="Get detailed information about audio files"
    )
    parser.add_argument("audio_path", help="Path to audio file")
    parser.add_argument("--json", action="store_true", help="Output as JSON")

    args = parser.parse_args()

    try:
        info = get_audio_info(args.audio_path)

        if args.json:
            print(json.dumps(info, indent=2))
        else:
            print(f"Audio Information for: {info.get('filename', args.audio_path)}")
            print(f"Duration: {info.get('duration', 'N/A')} seconds")
            print(f"Sample Rate: {info.get('sample_rate', 'N/A')} Hz")
            print(
                f"Channels: {info.get('channels', 'N/A')} ({info.get('format', 'N/A')})"
            )
            print(f"File Size: {info.get('file_size_mb', 'N/A')} MB")
            if info.get("bit_depth"):
                print(f"Bit Depth: {info.get('bit_depth')}")

    except Exception as e:
        print(f"Error: {e}")
        exit(1)