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.
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 ops;
40
41#[cfg(feature = "signed")]
42pub mod signed {
43    //! Signed channel newtypes
44
45    macro_rules! midpoint {
46        () => {
47            /// Calculates the middle point of `self` and `rhs`.
48            ///
49            /// `midpoint(a, b)` is `(a + b) / 2` calculated without overflow,
50            /// rounded down.
51            pub const fn midpoint(self, rhs: Self) -> Self {
52                use crate::conversions::{Signed, Unsigned};
53
54                let this = Unsigned(self.0).reinterpret_with_offset();
55                let rhs = Unsigned(rhs.0).reinterpret_with_offset();
56
57                Self(Signed(this.midpoint(rhs)).reinterpret_with_offset())
58            }
59        };
60    }
61
62    ch_int!(
63        (Ch8, i8, i16, core::convert::identity, midpoint! {}),
64        doc = "8-bit signed integer (-128 to 127) channel value",
65    );
66
67    ch_int!(
68        (Ch12, i16, i32, normalize_ch12, midpoint! {}),
69        doc = "12-bit signed integer (-2\\_048 to 2\\_047) channel value",
70    );
71
72    ch_int!(
73        (Ch16, i16, i32, core::convert::identity, midpoint! {}),
74        doc = "16-bit signed integer (-32\\_768 to 32\\_767) channel value",
75    );
76
77    ch_int!(
78        (Ch24, i32, i64, normalize_ch24, midpoint! {}),
79        doc = "24-bit signed integer (-8\\_388\\_608 to 8\\_388\\_607) channel value",
80    );
81
82    ch_float!(
83        (Ch32, f32, core::convert::identity, -1.0, 0.0),
84        doc = "32-bit float (-1 to 1) channel value",
85    );
86
87    ch_float!(
88        (Ch64, f64, core::convert::identity, -1.0, 0.0),
89        doc = "64-bit float (-1 to 1) channel value",
90    );
91
92    const fn normalize_ch12(mut chan: i16) -> i16 {
93        if chan > 2_i16.pow(11) - 1 {
94            chan = 2_i16.pow(11) - 1;
95        }
96
97        if chan < -2_i16.pow(11) {
98            chan = -2_i16.pow(11);
99        }
100
101        chan
102    }
103
104    const fn normalize_ch24(mut chan: i32) -> i32 {
105        if chan > 2_i32.pow(23) - 1 {
106            chan = 2_i32.pow(23) - 1;
107        }
108
109        if chan < -2_i32.pow(23) {
110            chan = -2_i32.pow(23);
111        }
112
113        chan
114    }
115}
116
117#[cfg(feature = "unsigned")]
118pub mod unsigned {
119    //! Unsigned channel newtypes
120
121    macro_rules! midpoint {
122        () => {
123            /// Calculates the middle point of `self` and `rhs`.
124            ///
125            /// `midpoint(a, b)` is `(a + b) / 2` calculated without overflow,
126            /// rounded to zero.
127            pub const fn midpoint(self, rhs: Self) -> Self {
128                Self(self.0.midpoint(rhs.0))
129            }
130        };
131    }
132
133    ch_int!(
134        (Ch8, u8, u16, core::convert::identity, midpoint! {}),
135        doc = "8-bit (0 to 255) unsigned integer channel value",
136    );
137
138    ch_int!(
139        (Ch12, u16, u32, normalize_ch12, midpoint! {}),
140        doc = "12-bit unsigned integer (0 to 4\\_095) channel value",
141    );
142
143    ch_int!(
144        (Ch16, u16, u32, core::convert::identity, midpoint! {}),
145        doc = "16-bit unsigned integer (0 to 65\\_535) channel value",
146    );
147
148    ch_int!(
149        (Ch24, u32, u64, normalize_ch24, midpoint! {}),
150        doc = "24-bit unsigned integer (0 to 16\\_777\\_215) channel value",
151    );
152
153    ch_float!(
154        (Ch32, f32, core::convert::identity, 0.0, 0.5),
155        doc = "32-bit float (0 to 1) channel value",
156    );
157
158    ch_float!(
159        (Ch64, f64, core::convert::identity, 0.0, 0.5),
160        doc = "64-bit float (0 to 1) channel value",
161    );
162
163    const fn normalize_ch12(chan: u16) -> u16 {
164        (chan << 4) >> 4
165    }
166
167    const fn normalize_ch24(chan: u32) -> u32 {
168        (chan << 8) >> 8
169    }
170}