audiowaveform 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +674 -0
  3. data/Cargo.lock +1108 -0
  4. data/Cargo.toml +28 -0
  5. data/README.md +255 -0
  6. data/bindings/ruby/CHANGELOG.md +29 -0
  7. data/bindings/ruby/Cargo.lock +621 -0
  8. data/bindings/ruby/Cargo.toml +8 -0
  9. data/bindings/ruby/README.md +193 -0
  10. data/bindings/ruby/ext/audiowaveform/Cargo.toml +20 -0
  11. data/bindings/ruby/ext/audiowaveform/build.rs +4 -0
  12. data/bindings/ruby/ext/audiowaveform/extconf.rb +6 -0
  13. data/bindings/ruby/ext/audiowaveform/src/lib.rs +239 -0
  14. data/bindings/ruby/lib/audiowaveform/version.rb +5 -0
  15. data/bindings/ruby/lib/audiowaveform.rb +131 -0
  16. data/crates/audiowaveform/Cargo.toml +73 -0
  17. data/crates/audiowaveform/examples/generate_from_pcm.rs +25 -0
  18. data/crates/audiowaveform/examples/generate_waveform.rs +18 -0
  19. data/crates/audiowaveform/examples/render_waveform.rs +18 -0
  20. data/crates/audiowaveform/examples/resample_waveform.rs +19 -0
  21. data/crates/audiowaveform/src/audio.rs +938 -0
  22. data/crates/audiowaveform/src/color.rs +201 -0
  23. data/crates/audiowaveform/src/error.rs +89 -0
  24. data/crates/audiowaveform/src/format.rs +215 -0
  25. data/crates/audiowaveform/src/lib.rs +79 -0
  26. data/crates/audiowaveform/src/render.rs +802 -0
  27. data/crates/audiowaveform/src/wav.rs +95 -0
  28. data/crates/audiowaveform/src/waveform.rs +790 -0
  29. data/crates/audiowaveform/tests/formats.rs +223 -0
  30. data/crates/audiowaveform/tests/generate.rs +233 -0
  31. data/crates/audiowaveform/tests/render.rs +263 -0
  32. data/crates/audiowaveform/tests/support/mod.rs +125 -0
  33. data/crates/audiowaveform/tests/wav.rs +54 -0
  34. data/crates/audiowaveform/tests/waveform_io.rs +255 -0
  35. data/crates/audiowaveform-cli/Cargo.toml +43 -0
  36. data/crates/audiowaveform-cli/src/main.rs +803 -0
  37. data/crates/audiowaveform-cli/tests/cli.rs +483 -0
  38. data/crates/audiowaveform-cli/tests/support/mod.rs +111 -0
  39. data/sig/audiowaveform.rbs +33 -0
  40. metadata +100 -0
@@ -0,0 +1,201 @@
1
+ use std::str::FromStr;
2
+
3
+ use crate::Error;
4
+
5
+ /// A single RGBA color.
6
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
7
+ pub struct Color {
8
+ /// Red channel.
9
+ pub red: u8,
10
+ /// Green channel.
11
+ pub green: u8,
12
+ /// Blue channel.
13
+ pub blue: u8,
14
+ /// Alpha channel, where `255` is fully opaque.
15
+ pub alpha: u8,
16
+ }
17
+
18
+ impl Color {
19
+ /// Creates an opaque color from RGB values.
20
+ pub const fn opaque(red: u8, green: u8, blue: u8) -> Self {
21
+ Self {
22
+ red,
23
+ green,
24
+ blue,
25
+ alpha: 255,
26
+ }
27
+ }
28
+
29
+ /// Creates a color from RGBA values.
30
+ pub const fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
31
+ Self {
32
+ red,
33
+ green,
34
+ blue,
35
+ alpha,
36
+ }
37
+ }
38
+
39
+ /// Returns `true` when the color uses transparency.
40
+ pub const fn has_alpha(self) -> bool {
41
+ self.alpha < 255
42
+ }
43
+ }
44
+
45
+ impl FromStr for Color {
46
+ type Err = Error;
47
+
48
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
49
+ if !(s.len() == 6 || s.len() == 8) || !s.as_bytes().iter().all(u8::is_ascii_hexdigit) {
50
+ return Err(Error::invalid_argument("color", "Invalid color value"));
51
+ }
52
+
53
+ let red = u8::from_str_radix(&s[0..2], 16)
54
+ .map_err(|_| Error::invalid_argument("color", "Invalid color value"))?;
55
+ let green = u8::from_str_radix(&s[2..4], 16)
56
+ .map_err(|_| Error::invalid_argument("color", "Invalid color value"))?;
57
+ let blue = u8::from_str_radix(&s[4..6], 16)
58
+ .map_err(|_| Error::invalid_argument("color", "Invalid color value"))?;
59
+ let alpha = if s.len() == 8 {
60
+ u8::from_str_radix(&s[6..8], 16)
61
+ .map_err(|_| Error::invalid_argument("color", "Invalid color value"))?
62
+ } else {
63
+ 255
64
+ };
65
+
66
+ Ok(Self::rgba(red, green, blue, alpha))
67
+ }
68
+ }
69
+
70
+ /// A named color scheme matching the historical audiowaveform presets.
71
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
72
+ pub enum ColorScheme {
73
+ /// Audacity-like colors.
74
+ Audacity,
75
+ /// Adobe Audition-like colors.
76
+ Audition,
77
+ }
78
+
79
+ impl ColorScheme {
80
+ /// Returns the full color palette associated with the scheme.
81
+ pub fn palette(self) -> WaveformColors {
82
+ match self {
83
+ Self::Audacity => WaveformColors::audacity(),
84
+ Self::Audition => WaveformColors::audition(),
85
+ }
86
+ }
87
+ }
88
+
89
+ impl FromStr for ColorScheme {
90
+ type Err = Error;
91
+
92
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
93
+ match s.to_ascii_lowercase().as_str() {
94
+ "audacity" => Ok(Self::Audacity),
95
+ "audition" => Ok(Self::Audition),
96
+ _ => Err(Error::invalid_argument(
97
+ "colors",
98
+ format!("Unknown color scheme: {s}"),
99
+ )),
100
+ }
101
+ }
102
+ }
103
+
104
+ /// Complete color settings for waveform rendering.
105
+ #[derive(Clone, Debug, Eq, PartialEq)]
106
+ pub struct WaveformColors {
107
+ /// Border color.
108
+ pub border: Color,
109
+ /// Background color.
110
+ pub background: Color,
111
+ /// Per-channel waveform colors. Channels wrap if there are fewer colors than channels.
112
+ pub waveform: Vec<Color>,
113
+ /// Axis-label color.
114
+ pub axis_label: Color,
115
+ }
116
+
117
+ impl WaveformColors {
118
+ /// Returns the Audacity-inspired palette.
119
+ pub fn audacity() -> Self {
120
+ Self {
121
+ border: Color::opaque(0, 0, 0),
122
+ background: Color::opaque(214, 214, 214),
123
+ waveform: vec![Color::opaque(63, 77, 155)],
124
+ axis_label: Color::opaque(0, 0, 0),
125
+ }
126
+ }
127
+
128
+ /// Returns the Adobe Audition-inspired palette.
129
+ pub fn audition() -> Self {
130
+ Self {
131
+ border: Color::opaque(157, 157, 157),
132
+ background: Color::opaque(0, 63, 34),
133
+ waveform: vec![Color::opaque(134, 252, 199)],
134
+ axis_label: Color::opaque(190, 190, 190),
135
+ }
136
+ }
137
+
138
+ /// Returns `true` when any configured color uses transparency.
139
+ pub fn has_alpha(&self) -> bool {
140
+ self.border.has_alpha()
141
+ || self.background.has_alpha()
142
+ || self.axis_label.has_alpha()
143
+ || self.waveform.iter().any(|color| color.has_alpha())
144
+ }
145
+ }
146
+
147
+ impl Default for WaveformColors {
148
+ fn default() -> Self {
149
+ Self::audacity()
150
+ }
151
+ }
152
+
153
+ #[cfg(test)]
154
+ mod tests {
155
+ use std::str::FromStr;
156
+
157
+ use super::{Color, ColorScheme, WaveformColors};
158
+
159
+ #[test]
160
+ fn parses_rgb_and_rgba_colors() {
161
+ assert_eq!(
162
+ Color::from_str("123456").expect("rgb"),
163
+ Color::rgba(0x12, 0x34, 0x56, 0xff)
164
+ );
165
+ assert_eq!(
166
+ Color::from_str("abcdef80").expect("rgba"),
167
+ Color::rgba(0xab, 0xcd, 0xef, 0x80)
168
+ );
169
+ assert_eq!(
170
+ Color::from_str("A1B2C3").expect("uppercase"),
171
+ Color::rgba(0xa1, 0xb2, 0xc3, 0xff)
172
+ );
173
+ }
174
+
175
+ #[test]
176
+ fn rejects_invalid_color_strings() {
177
+ for value in ["", "12345", "gggggg", "123456789"] {
178
+ let error = Color::from_str(value).expect_err("invalid color");
179
+ assert_eq!(error.to_string(), "Invalid color value");
180
+ }
181
+ }
182
+
183
+ #[test]
184
+ fn parses_color_schemes_and_detects_alpha() {
185
+ assert_eq!(
186
+ ColorScheme::from_str("audacity").expect("audacity"),
187
+ ColorScheme::Audacity
188
+ );
189
+ assert_eq!(
190
+ ColorScheme::from_str("AUDITION").expect("audition"),
191
+ ColorScheme::Audition
192
+ );
193
+ let error = ColorScheme::from_str("unknown").expect_err("unknown scheme");
194
+ assert_eq!(error.to_string(), "Unknown color scheme: unknown");
195
+
196
+ let mut colors = WaveformColors::default();
197
+ assert!(!colors.has_alpha());
198
+ colors.background = Color::rgba(0, 0, 0, 128);
199
+ assert!(colors.has_alpha());
200
+ }
201
+ }
@@ -0,0 +1,89 @@
1
+ use std::io;
2
+
3
+ use thiserror::Error;
4
+
5
+ /// Errors returned by the `audiowaveform` library.
6
+ #[derive(Debug, Error)]
7
+ pub enum Error {
8
+ /// Returned when an argument or option is invalid.
9
+ #[error("{message}")]
10
+ InvalidArgument {
11
+ /// The logical argument name that failed validation.
12
+ name: &'static str,
13
+ /// Human-readable validation message.
14
+ message: String,
15
+ },
16
+
17
+ /// Returned when waveform or audio data is malformed.
18
+ #[error("{message}")]
19
+ InvalidData {
20
+ /// Human-readable validation message.
21
+ message: String,
22
+ },
23
+
24
+ /// Returned when a format name or feature is unsupported.
25
+ #[error("Unsupported format: {format}")]
26
+ UnsupportedFormat {
27
+ /// The unsupported format identifier.
28
+ format: String,
29
+ },
30
+
31
+ /// Returned when a capability was omitted from this build.
32
+ #[error("Feature disabled: enable the `{feature}` Cargo feature")]
33
+ FeatureDisabled {
34
+ /// Cargo feature required to enable the capability.
35
+ feature: &'static str,
36
+ },
37
+
38
+ /// Returned when a required value is missing from structured data.
39
+ #[error("Missing value: {name}")]
40
+ MissingValue {
41
+ /// The missing field name.
42
+ name: &'static str,
43
+ },
44
+
45
+ /// Returned when required stream metadata is unavailable.
46
+ #[error("Missing metadata: {name}")]
47
+ MissingMetadata {
48
+ /// The missing metadata field name.
49
+ name: &'static str,
50
+ },
51
+
52
+ /// Returned for I/O failures.
53
+ #[error(transparent)]
54
+ Io(#[from] io::Error),
55
+
56
+ /// Returned for JSON parsing failures.
57
+ #[error(transparent)]
58
+ Json(#[from] serde_json::Error),
59
+
60
+ /// Returned for Symphonia decode failures.
61
+ #[cfg(feature = "decode")]
62
+ #[error(transparent)]
63
+ Symphonia(#[from] symphonia::core::errors::Error),
64
+
65
+ /// Returned for WAV encoding failures.
66
+ #[cfg(feature = "wav-output")]
67
+ #[error(transparent)]
68
+ Hound(#[from] hound::Error),
69
+
70
+ /// Returned for PNG encoding failures.
71
+ #[cfg(feature = "render")]
72
+ #[error(transparent)]
73
+ PngEncoding(#[from] png::EncodingError),
74
+ }
75
+
76
+ impl Error {
77
+ pub(crate) fn invalid_argument(name: &'static str, message: impl Into<String>) -> Self {
78
+ Self::InvalidArgument {
79
+ name,
80
+ message: message.into(),
81
+ }
82
+ }
83
+
84
+ pub(crate) fn invalid_data(message: impl Into<String>) -> Self {
85
+ Self::InvalidData {
86
+ message: message.into(),
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,215 @@
1
+ use std::path::Path;
2
+ use std::str::FromStr;
3
+
4
+ use crate::Error;
5
+
6
+ /// Supported audio container or source formats.
7
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
8
+ pub enum AudioFormat {
9
+ /// AAC audio in an ADTS stream.
10
+ Aac,
11
+ /// AIFF or AIFF-C audio.
12
+ Aiff,
13
+ /// Core Audio Format audio.
14
+ Caf,
15
+ /// Audio in an ISO MP4 container, including M4A.
16
+ Mp4,
17
+ /// Audio in a Matroska or WebM container.
18
+ Mkv,
19
+ /// MPEG layer I audio.
20
+ Mp1,
21
+ /// MPEG layer II audio.
22
+ Mp2,
23
+ /// MP3 audio.
24
+ Mp3,
25
+ /// WAV audio.
26
+ Wav,
27
+ /// FLAC audio.
28
+ Flac,
29
+ /// Ogg Vorbis or FLAC audio.
30
+ Ogg,
31
+ /// Opus audio (recognized, but decoding is not supported).
32
+ Opus,
33
+ /// Headerless raw PCM or floating-point audio.
34
+ Raw,
35
+ }
36
+
37
+ impl AudioFormat {
38
+ /// Returns the canonical lowercase name for the format.
39
+ pub const fn as_str(self) -> &'static str {
40
+ match self {
41
+ Self::Aac => "aac",
42
+ Self::Aiff => "aiff",
43
+ Self::Caf => "caf",
44
+ Self::Mp4 => "mp4",
45
+ Self::Mkv => "mkv",
46
+ Self::Mp1 => "mp1",
47
+ Self::Mp2 => "mp2",
48
+ Self::Mp3 => "mp3",
49
+ Self::Wav => "wav",
50
+ Self::Flac => "flac",
51
+ Self::Ogg => "ogg",
52
+ Self::Opus => "opus",
53
+ Self::Raw => "raw",
54
+ }
55
+ }
56
+
57
+ /// Infers an audio format from a filesystem path extension.
58
+ pub fn from_path(path: impl AsRef<Path>) -> Option<Self> {
59
+ let extension = path.as_ref().extension()?.to_str()?;
60
+ Self::from_extension(extension)
61
+ }
62
+
63
+ /// Infers an audio format from a file extension string.
64
+ pub fn from_extension(extension: &str) -> Option<Self> {
65
+ match extension.to_ascii_lowercase().as_str() {
66
+ "aac" | "adts" => Some(Self::Aac),
67
+ "aiff" | "aif" | "aifc" => Some(Self::Aiff),
68
+ "caf" => Some(Self::Caf),
69
+ "mp4" | "m4a" | "m4b" | "m4r" | "m4v" | "mov" => Some(Self::Mp4),
70
+ "mkv" | "mka" | "webm" => Some(Self::Mkv),
71
+ "mp1" => Some(Self::Mp1),
72
+ "mp2" => Some(Self::Mp2),
73
+ "mp3" => Some(Self::Mp3),
74
+ "wav" | "w64" => Some(Self::Wav),
75
+ "flac" => Some(Self::Flac),
76
+ "ogg" | "oga" => Some(Self::Ogg),
77
+ "opus" => Some(Self::Opus),
78
+ "raw" => Some(Self::Raw),
79
+ _ => None,
80
+ }
81
+ }
82
+
83
+ /// Checks whether this build includes the input format's decoding feature.
84
+ ///
85
+ /// Raw audio is always available through the raw PCM APIs. Opus is recognized
86
+ /// only to report that it is unsupported, even with `all-formats` enabled.
87
+ pub fn ensure_enabled(self) -> Result<(), Error> {
88
+ let (enabled, feature) = match self {
89
+ Self::Aac => (cfg!(feature = "format-aac"), "format-aac"),
90
+ Self::Aiff => (cfg!(feature = "format-aiff"), "format-aiff"),
91
+ Self::Caf => (cfg!(feature = "format-caf"), "format-caf"),
92
+ Self::Mp4 => (cfg!(feature = "format-m4a"), "format-m4a"),
93
+ Self::Mkv => (cfg!(feature = "format-mkv"), "format-mkv"),
94
+ Self::Mp1 => (cfg!(feature = "format-mp1"), "format-mp1"),
95
+ Self::Mp2 => (cfg!(feature = "format-mp2"), "format-mp2"),
96
+ Self::Mp3 => (cfg!(feature = "format-mp3"), "format-mp3"),
97
+ Self::Wav => (cfg!(feature = "format-wav"), "format-wav"),
98
+ Self::Flac => (cfg!(feature = "format-flac"), "format-flac"),
99
+ Self::Ogg => (cfg!(feature = "format-ogg"), "format-ogg"),
100
+ Self::Raw => return Ok(()),
101
+ Self::Opus => {
102
+ return Err(Error::UnsupportedFormat {
103
+ format: "opus".into(),
104
+ });
105
+ }
106
+ };
107
+ if enabled {
108
+ Ok(())
109
+ } else {
110
+ Err(Error::FeatureDisabled { feature })
111
+ }
112
+ }
113
+ }
114
+
115
+ impl FromStr for AudioFormat {
116
+ type Err = Error;
117
+
118
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
119
+ Self::from_extension(s).ok_or_else(|| Error::UnsupportedFormat {
120
+ format: s.to_string(),
121
+ })
122
+ }
123
+ }
124
+
125
+ /// Supported serialized waveform data formats.
126
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
127
+ pub enum WaveformFormat {
128
+ /// Binary `.dat` waveform data.
129
+ Dat,
130
+ /// Compact JSON waveform data.
131
+ Json,
132
+ /// Plain text CSV-like waveform data.
133
+ Txt,
134
+ }
135
+
136
+ impl WaveformFormat {
137
+ /// Returns the canonical lowercase name for the format.
138
+ pub const fn as_str(self) -> &'static str {
139
+ match self {
140
+ Self::Dat => "dat",
141
+ Self::Json => "json",
142
+ Self::Txt => "txt",
143
+ }
144
+ }
145
+
146
+ /// Infers a waveform data format from a filesystem path extension.
147
+ pub fn from_path(path: impl AsRef<Path>) -> Option<Self> {
148
+ let extension = path.as_ref().extension()?.to_str()?;
149
+ Self::from_extension(extension)
150
+ }
151
+
152
+ /// Infers a waveform data format from a file extension string.
153
+ pub fn from_extension(extension: &str) -> Option<Self> {
154
+ match extension.to_ascii_lowercase().as_str() {
155
+ "dat" => Some(Self::Dat),
156
+ "json" => Some(Self::Json),
157
+ "txt" => Some(Self::Txt),
158
+ _ => None,
159
+ }
160
+ }
161
+ }
162
+
163
+ impl FromStr for WaveformFormat {
164
+ type Err = Error;
165
+
166
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
167
+ Self::from_extension(s).ok_or_else(|| Error::UnsupportedFormat {
168
+ format: s.to_string(),
169
+ })
170
+ }
171
+ }
172
+
173
+ #[cfg(test)]
174
+ mod tests {
175
+ use super::{AudioFormat, WaveformFormat};
176
+
177
+ #[test]
178
+ fn infers_audio_formats_from_extensions_and_paths() {
179
+ assert_eq!(AudioFormat::from_extension("mp3"), Some(AudioFormat::Mp3));
180
+ assert_eq!(AudioFormat::from_extension("w64"), Some(AudioFormat::Wav));
181
+ assert_eq!(AudioFormat::from_extension("oga"), Some(AudioFormat::Ogg));
182
+ assert_eq!(AudioFormat::from_path("clip.flac"), Some(AudioFormat::Flac));
183
+ assert_eq!(AudioFormat::from_path("clip.opus"), Some(AudioFormat::Opus));
184
+ assert_eq!(AudioFormat::from_extension("unknown"), None);
185
+ }
186
+
187
+ #[test]
188
+ fn parses_audio_format_strings() {
189
+ assert_eq!("wav".parse::<AudioFormat>().expect("wav"), AudioFormat::Wav);
190
+ assert_eq!("oga".parse::<AudioFormat>().expect("oga"), AudioFormat::Ogg);
191
+
192
+ let error = "unknown".parse::<AudioFormat>().expect_err("unsupported");
193
+ assert_eq!(error.to_string(), "Unsupported format: unknown");
194
+ }
195
+
196
+ #[test]
197
+ fn infers_and_parses_waveform_formats() {
198
+ assert_eq!(
199
+ WaveformFormat::from_extension("dat"),
200
+ Some(WaveformFormat::Dat)
201
+ );
202
+ assert_eq!(
203
+ WaveformFormat::from_path("waveform.json"),
204
+ Some(WaveformFormat::Json)
205
+ );
206
+ assert_eq!(
207
+ "txt".parse::<WaveformFormat>().expect("txt"),
208
+ WaveformFormat::Txt
209
+ );
210
+ assert_eq!(WaveformFormat::from_extension("png"), None);
211
+
212
+ let error = "csv".parse::<WaveformFormat>().expect_err("unsupported");
213
+ assert_eq!(error.to_string(), "Unsupported format: csv");
214
+ }
215
+ }
@@ -0,0 +1,79 @@
1
+ #![deny(missing_docs)]
2
+ //! First-class Rust library for generating, serializing, resampling, rendering,
3
+ //! and transcoding audio waveforms.
4
+ //!
5
+ //! The crate is designed around reusable domain types instead of command-line
6
+ //! flags. The companion CLI lives in `audiowaveform-cli` and translates its
7
+ //! argument model into these library APIs.
8
+ //!
9
+ //! # Features
10
+ //!
11
+ //! No features are enabled by default. PCM/raw waveform generation, serialization,
12
+ //! and resampling are always available. Enable `format-mp3`, `format-m4a`, or another
13
+ //! `format-*` bundle for decoding, or `all-formats` for every supported input format.
14
+ //! Each format enables the shared `decode` plumbing. `render` enables PNG rendering;
15
+ //! `wav-output` enables PCM16 WAV writing independently of input decoding.
16
+ //! Opus and HE-AAC are not supported, even with `all-formats` enabled.
17
+ //!
18
+ //! # Examples
19
+ //!
20
+ //! Generate waveform data from an audio file:
21
+ //!
22
+ //! ```no_run
23
+ //! # #[cfg(feature = "format-mp3")]
24
+ //! # {
25
+ //! use audiowaveform::{GenerateOptions, Waveform, generate_waveform_from_path};
26
+ //!
27
+ //! let waveform = generate_waveform_from_path("input.mp3", &GenerateOptions::default())?;
28
+ //! waveform.save_to_path("output.dat", None)?;
29
+ //! # }
30
+ //! # Ok::<(), audiowaveform::Error>(())
31
+ //! ```
32
+ //!
33
+ //! Render a PNG from an existing waveform file:
34
+ //!
35
+ //! ```no_run
36
+ //! # #[cfg(feature = "render")]
37
+ //! # {
38
+ //! use audiowaveform::{RenderOptions, Waveform, render_waveform_to_path};
39
+ //!
40
+ //! let waveform = Waveform::load_from_path("input.dat", None)?;
41
+ //! render_waveform_to_path(&waveform, &RenderOptions::default(), "output.png")?;
42
+ //! # }
43
+ //! # Ok::<(), audiowaveform::Error>(())
44
+ //! ```
45
+
46
+ mod audio;
47
+ mod color;
48
+ mod error;
49
+ mod format;
50
+ #[cfg(feature = "render")]
51
+ mod render;
52
+ #[cfg(feature = "wav-output")]
53
+ mod wav;
54
+ mod waveform;
55
+
56
+ pub use audio::{
57
+ GenerateOptions, PcmAudio, RawAudioConfig, RawSampleFormat, ScaleSpec, decode_raw_audio_reader,
58
+ generate_waveform_from_pcm, generate_waveform_from_raw_reader,
59
+ };
60
+ #[cfg(feature = "decode")]
61
+ pub use audio::{
62
+ decode_audio_from_path, decode_audio_from_reader, generate_waveform_from_path,
63
+ generate_waveform_from_reader,
64
+ };
65
+ pub use color::{Color, ColorScheme, WaveformColors};
66
+ pub use error::Error;
67
+ pub use format::{AudioFormat, WaveformFormat};
68
+ #[cfg(feature = "render")]
69
+ pub use image::RgbaImage;
70
+ #[cfg(feature = "render")]
71
+ pub use render::{
72
+ BarStyle, RenderOptions, RenderStyle, render_waveform, render_waveform_to_path,
73
+ write_waveform_png,
74
+ };
75
+ #[cfg(feature = "wav-output")]
76
+ pub use wav::write_pcm_as_wav;
77
+ #[cfg(all(feature = "decode", feature = "wav-output"))]
78
+ pub use wav::{transcode_audio_path_to_wav_path, transcode_audio_reader_to_wav_writer};
79
+ pub use waveform::{AmplitudeScale, Waveform, WaveformPoint};