p_chan/
lib.rs

1//! Multimedia (Audio, Raster) Channel Newtypes and Conversions
2//!
3//! Each module is enabled with a feature by the same name.
4//!
5//! The types provided by each module are `Ch8`, `Ch12`, `Ch16`, `Ch24` for
6//! integers, and `Ch32` and `Ch64` for floating-point.  Integer channels can
7//! not exceed the range of their minimum and maximum values, while
8//! floating-point channels can.  Floating-point channels can only ever be
9//! normal numbers or infinity.
10
11#![no_std]
12#![deny(
13    missing_copy_implementations,
14    missing_debug_implementations,
15    missing_docs,
16    unsafe_code
17)]
18#![warn(
19    anonymous_parameters,
20    nonstandard_style,
21    rust_2018_idioms,
22    single_use_lifetimes,
23    trivial_casts,
24    trivial_numeric_casts,
25    unreachable_pub,
26    unused_extern_crates,
27    unused_qualifications,
28    variant_size_differences
29)]
30#![doc(
31    html_logo_url = "https://raw.githubusercontent.com/AldaronLau/p-chan/v0/res/icon.png",
32    html_favicon_url = "https://raw.githubusercontent.com/AldaronLau/p-chan/v0/res/icon.png"
33)]
34
35mod conversions;
36#[cfg(any(feature = "unsigned", feature = "signed"))]
37#[macro_use]
38mod macros;
39pub mod chan;
40pub mod ops;
41
42#[cfg(feature = "signed")]
43pub mod signed {
44    //! Signed channel newtypes
45
46    macro_rules! midpoint {
47        () => {
48            /// Calculates the middle point of `self` and `rhs`.
49            ///
50            /// `midpoint(a, b)` is `(a + b) / 2` calculated without overflow,
51            /// rounded down.
52            pub const fn midpoint(self, rhs: Self) -> Self {
53                use crate::conversions::{Signed, Unsigned};
54
55                let this = Unsigned(self.0).reinterpret_with_offset();
56                let rhs = Unsigned(rhs.0).reinterpret_with_offset();
57
58                Self(Signed(this.midpoint(rhs)).reinterpret_with_offset())
59            }
60        };
61    }
62
63    ch_int!(
64        (Ch8, i8, i16, core::convert::identity, midpoint! {}),
65        doc = "8-bit signed integer (-128 to 127) channel value",
66    );
67
68    ch_int!(
69        (Ch12, i16, i32, normalize_ch12, midpoint! {}),
70        doc = "12-bit signed integer (-2\\_048 to 2\\_047) channel value",
71    );
72
73    ch_int!(
74        (Ch16, i16, i32, core::convert::identity, midpoint! {}),
75        doc = "16-bit signed integer (-32\\_768 to 32\\_767) channel value",
76    );
77
78    ch_int!(
79        (Ch24, i32, i64, normalize_ch24, midpoint! {}),
80        doc = "24-bit signed integer (-8\\_388\\_608 to 8\\_388\\_607) channel value",
81    );
82
83    ch_float!(
84        (Ch32, f32, crate::conversions::normalize_f32, -1.0, 0.0),
85        doc = "32-bit float (-1 to 1) channel value",
86    );
87
88    ch_float!(
89        (Ch64, f64, crate::conversions::normalize_f64, -1.0, 0.0),
90        doc = "64-bit float (-1 to 1) channel value",
91    );
92
93    const fn normalize_ch12(mut chan: i16) -> i16 {
94        if chan > 2_i16.pow(11) - 1 {
95            chan = 2_i16.pow(11) - 1;
96        }
97
98        if chan < -2_i16.pow(11) {
99            chan = -2_i16.pow(11);
100        }
101
102        chan
103    }
104
105    const fn normalize_ch24(mut chan: i32) -> i32 {
106        if chan > 2_i32.pow(23) - 1 {
107            chan = 2_i32.pow(23) - 1;
108        }
109
110        if chan < -2_i32.pow(23) {
111            chan = -2_i32.pow(23);
112        }
113
114        chan
115    }
116}
117
118#[cfg(feature = "unsigned")]
119pub mod unsigned {
120    //! Unsigned channel newtypes
121
122    macro_rules! midpoint {
123        () => {
124            /// Calculates the middle point of `self` and `rhs`.
125            ///
126            /// `midpoint(a, b)` is `(a + b) / 2` calculated without overflow,
127            /// rounded to zero.
128            pub const fn midpoint(self, rhs: Self) -> Self {
129                Self(self.0.midpoint(rhs.0))
130            }
131        };
132    }
133
134    ch_int!(
135        (Ch8, u8, u16, core::convert::identity, midpoint! {}),
136        doc = "8-bit (0 to 255) unsigned integer channel value",
137    );
138
139    ch_int!(
140        (Ch12, u16, u32, normalize_ch12, midpoint! {}),
141        doc = "12-bit unsigned integer (0 to 4\\_095) channel value",
142    );
143
144    ch_int!(
145        (Ch16, u16, u32, core::convert::identity, midpoint! {}),
146        doc = "16-bit unsigned integer (0 to 65\\_535) channel value",
147    );
148
149    ch_int!(
150        (Ch24, u32, u64, normalize_ch24, midpoint! {}),
151        doc = "24-bit unsigned integer (0 to 16\\_777\\_215) channel value",
152    );
153
154    ch_float!(
155        (Ch32, f32, crate::conversions::normalize_f32, 0.0, 0.5),
156        doc = "32-bit float (0 to 1) channel value",
157    );
158
159    ch_float!(
160        (Ch64, f64, crate::conversions::normalize_f64, 0.0, 0.5),
161        doc = "64-bit float (0 to 1) channel value",
162    );
163
164    const fn normalize_ch12(chan: u16) -> u16 {
165        (chan << 4) >> 4
166    }
167
168    const fn normalize_ch24(chan: u32) -> u32 {
169        (chan << 8) >> 8
170    }
171}