dasp_sample/
conv.rs

1//! Pure functions and traits for converting between i8, i16, I24, i32, I48, i64, u8, u16, U24,
2//! u32, U48, u64, f32 and f64.
3//!
4//! Each conversion function is performance focused, memory-sensitive and expects that the user has
5//! validated their input prior to the function call.
6//!
7//! No conversion function will ever cast to a type with a size in bytes larger than the largest
8//! between the source and target sample types.
9//!
10//! The conversion functions do *not* check the range of incoming values for floating point values
11//! or any of the custom `I24`, `U24`, `I48` and `U48` types.
12//!
13//! Note that floating point conversions use the range -1.0 <= v < 1.0:
14//! `(1.0 as f64).to_sample::<i16>()` will overflow!
15
16use crate::types::{I24, I48, U24, U48};
17
18macro_rules! conversion_fn {
19    ($Rep:ty, $s:ident to_i8 { $body:expr }) => {
20        #[inline]
21        pub fn to_i8($s: $Rep) -> i8 {
22            $body
23        }
24    };
25
26    ($Rep:ty, $s:ident to_i16 { $body:expr }) => {
27        #[inline]
28        pub fn to_i16($s: $Rep) -> i16 {
29            $body
30        }
31    };
32
33    ($Rep:ty, $s:ident to_i24 { $body:expr }) => {
34        #[inline]
35        pub fn to_i24($s: $Rep) -> I24 {
36            $body
37        }
38    };
39
40    ($Rep:ty, $s:ident to_i32 { $body:expr }) => {
41        #[inline]
42        pub fn to_i32($s: $Rep) -> i32 {
43            $body
44        }
45    };
46
47    ($Rep:ty, $s:ident to_i48 { $body:expr }) => {
48        #[inline]
49        pub fn to_i48($s: $Rep) -> I48 {
50            $body
51        }
52    };
53
54    ($Rep:ty, $s:ident to_i64 { $body:expr }) => {
55        #[inline]
56        pub fn to_i64($s: $Rep) -> i64 {
57            $body
58        }
59    };
60
61    ($Rep:ty, $s:ident to_u8 { $body:expr }) => {
62        #[inline]
63        pub fn to_u8($s: $Rep) -> u8 {
64            $body
65        }
66    };
67
68    ($Rep:ty, $s:ident to_u16 { $body:expr }) => {
69        #[inline]
70        pub fn to_u16($s: $Rep) -> u16 {
71            $body
72        }
73    };
74
75    ($Rep:ty, $s:ident to_u24 { $body:expr }) => {
76        #[inline]
77        pub fn to_u24($s: $Rep) -> U24 {
78            $body
79        }
80    };
81
82    ($Rep:ty, $s:ident to_u32 { $body:expr }) => {
83        #[inline]
84        pub fn to_u32($s: $Rep) -> u32 {
85            $body
86        }
87    };
88
89    ($Rep:ty, $s:ident to_u48 { $body:expr }) => {
90        #[inline]
91        pub fn to_u48($s: $Rep) -> U48 {
92            $body
93        }
94    };
95
96    ($Rep:ty, $s:ident to_u64 { $body:expr }) => {
97        #[inline]
98        pub fn to_u64($s: $Rep) -> u64 {
99            $body
100        }
101    };
102
103    ($Rep:ty, $s:ident to_f32 { $body:expr }) => {
104        #[inline]
105        pub fn to_f32($s: $Rep) -> f32 {
106            $body
107        }
108    };
109
110    ($Rep:ty, $s:ident to_f64 { $body:expr }) => {
111        #[inline]
112        pub fn to_f64($s: $Rep) -> f64 {
113            $body
114        }
115    };
116}
117
118macro_rules! conversion_fns {
119    ($Rep:ty, $s:ident $fn_name:tt { $body:expr } $($rest:tt)*) => {
120        conversion_fn!($Rep, $s $fn_name { $body });
121        conversion_fns!($Rep, $($rest)*);
122    };
123    ($Rep:ty, ) => {};
124}
125
126macro_rules! conversions {
127    ($T:ident, $mod_name:ident { $($rest:tt)* }) => {
128        pub mod $mod_name {
129            use $crate::types::{I24, U24, I48, U48};
130            conversion_fns!($T, $($rest)*);
131        }
132    };
133}
134
135conversions!(i8, i8 {
136    s to_i16 { (s as i16) << 8 }
137    s to_i24 { I24::new_unchecked((s as i32) << 16) }
138    s to_i32 { (s as i32) << 24 }
139    s to_i48 { I48::new_unchecked((s as i64) << 40) }
140    s to_i64 { (s as i64) << 56 }
141    s to_u8 {
142        if s < 0 {
143            // 128i8 overflows, so we must use 127 + 1 instead.
144            (s + 127 + 1) as u8
145        } else {
146            (s as u8) + 128
147        }
148    }
149    s to_u16 {
150        if s < 0 {
151            ((s + 127 + 1) as u16) << 8
152        } else {
153            (s as u16 + 128) << 8
154        }
155    }
156    s to_u24 {
157        U24::new_unchecked((s as i32 + 128) << 16)
158    }
159    s to_u32 {
160        if s < 0 {
161            ((s + 127 + 1) as u32) << 24
162        } else {
163            (s as u32 + 128) << 24
164        }
165    }
166    s to_u48 {
167        U48::new_unchecked((s as i64 + 128) << 40)
168    }
169    s to_u64 {
170        if s < 0 {
171            ((s + 127 + 1) as u64) << 56
172        } else {
173            (s as u64 + 128) << 56
174        }
175    }
176    s to_f32 {
177        s as f32 / 128.0
178    }
179    s to_f64 {
180        s as f64 / 128.0
181    }
182});
183
184conversions!(i16, i16 {
185    s to_i8 { (s >> 8) as i8 }
186    s to_i24 { I24::new_unchecked((s as i32) << 8) }
187    s to_i32 { (s as i32) << 16 }
188    s to_i48 { I48::new_unchecked((s as i64) << 32) }
189    s to_i64 { (s as i64) << 48 }
190    s to_u8 {
191        super::i8::to_u8(to_i8(s))
192    }
193    s to_u16 {
194        if s < 0 {
195            // 32_768i16 overflows, so we must use + 1 instead.
196            (s + 32_767 + 1) as u16
197        } else {
198            s as u16 + 32_768
199        }
200    }
201    s to_u24 {
202        if s < 0 {
203            U24::new_unchecked(((s + 32_767 + 1) as i32) << 8)
204        } else {
205            U24::new_unchecked((s as i32 + 32_768) << 8)
206        }
207    }
208    s to_u32 {
209        if s < 0 {
210            ((s + 32_767 + 1) as u32) << 16
211        } else {
212            ((s as u32) + 32_768) << 16
213        }
214    }
215    s to_u48 {
216        if s < 0 {
217            U48::new_unchecked(((s + 32_767 + 1) as i64) << 32)
218        } else {
219            U48::new_unchecked((s as i64 + 32_768) << 32)
220        }
221    }
222    s to_u64 {
223        if s < 0 {
224            ((s + 32_767 + 1) as u64) << 48
225        } else {
226            ((s as u64) + 32_768) << 48
227        }
228    }
229    s to_f32 {
230        s as f32 / 32_768.0
231    }
232    s to_f64 {
233        s as f64 / 32_768.0
234    }
235});
236
237conversions!(I24, i24 {
238    s to_i8 { (s.inner() >> 16) as i8 }
239    s to_i16 { (s.inner() >> 8) as i16 }
240    s to_i32 { s.inner() << 8 }
241    s to_i48 { I48::new_unchecked((s.inner() as i64) << 24) }
242    s to_i64 { (s.inner() as i64) << 40 }
243    s to_u8 {
244        super::i8::to_u8(to_i8(s))
245    }
246    s to_u16 {
247        super::i16::to_u16(to_i16(s))
248    }
249    s to_u24 {
250        U24::new_unchecked(s.inner() + 8_388_608)
251    }
252    s to_u32 {
253        ((s.inner() + 8_388_608) as u32) << 8
254    }
255    s to_u48 {
256        U48::new_unchecked((s.inner() as i64 + 8_388_608) << 24)
257    }
258    s to_u64 {
259        ((s.inner() + 8_388_608) as u64) << 40
260    }
261    s to_f32 {
262        s.inner() as f32 / 8_388_608.0
263    }
264    s to_f64 {
265        s.inner() as f64 / 8_388_608.0
266    }
267});
268
269conversions!(i32, i32 {
270    s to_i8 { (s >> 24) as i8 }
271    s to_i16 { (s >> 16) as i16 }
272    s to_i24 { I24::new_unchecked(s >> 8) }
273    s to_i48 { I48::new_unchecked((s as i64) << 16) }
274    s to_i64 { (s as i64) << 32 }
275    s to_u8 {
276        super::i8::to_u8(to_i8(s))
277    }
278    s to_u16 {
279        super::i16::to_u16(to_i16(s))
280    }
281    s to_u24 {
282        super::i24::to_u24(to_i24(s))
283    }
284    s to_u32 {
285        if s < 0 {
286            (s + 2_147_483_647 + 1) as u32
287        } else {
288            s as u32 + 2_147_483_648
289        }
290    }
291    s to_u48 {
292        U48::new_unchecked((s as i64 + 2_147_483_648) << 16)
293    }
294    s to_u64 {
295        if s < 0 {
296            ((s + 2_147_483_647 + 1) as u64) << 32
297        } else {
298            (s as u64) + 2_147_483_648 << 32
299        }
300    }
301    s to_f32 {
302        s as f32 / 2_147_483_648.0
303    }
304    s to_f64 {
305        s as f64 / 2_147_483_648.0
306    }
307});
308
309conversions!(I48, i48 {
310    s to_i8 { (s.inner() >> 40) as i8 }
311    s to_i16 { (s.inner() >> 32) as i16 }
312    s to_i24 { I24::new_unchecked((s.inner() >> 24) as i32) }
313    s to_i32 { (s.inner() >> 16) as i32 }
314    s to_i64 { s.inner() << 16 }
315    s to_u8 {
316        super::i8::to_u8(to_i8(s))
317    }
318    s to_u16 {
319        super::i16::to_u16(to_i16(s))
320    }
321    s to_u24 {
322        super::i24::to_u24(to_i24(s))
323    }
324    s to_u32 {
325        super::i32::to_u32(to_i32(s))
326    }
327    s to_u48 {
328        U48::new_unchecked(s.inner() + 140_737_488_355_328)
329    }
330    s to_u64 {
331        ((s.inner() + 140_737_488_355_328) as u64) << 16
332    }
333    s to_f32 {
334        s.inner() as f32 / 140_737_488_355_328.0
335    }
336    s to_f64 {
337        s.inner() as f64 / 140_737_488_355_328.0
338    }
339});
340
341conversions!(i64, i64 {
342    s to_i8 { (s >> 56) as i8 }
343    s to_i16 { (s >> 48) as i16 }
344    s to_i24 { I24::new_unchecked((s >> 40) as i32) }
345    s to_i32 { (s >> 32) as i32 }
346    s to_i48 { I48::new_unchecked(s >> 16) }
347    s to_u8 {
348        super::i8::to_u8(to_i8(s))
349    }
350    s to_u16 {
351        super::i16::to_u16(to_i16(s))
352    }
353    s to_u24 {
354        super::i24::to_u24(to_i24(s))
355    }
356    s to_u32 {
357        super::i32::to_u32(to_i32(s))
358    }
359    s to_u48 {
360        super::i48::to_u48(to_i48(s))
361    }
362    s to_u64 {
363        if s < 0 {
364            (s + 9_223_372_036_854_775_807 + 1) as u64
365        } else {
366            s as u64 + 9_223_372_036_854_775_808
367        }
368    }
369    s to_f32 {
370        s as f32 / 9_223_372_036_854_775_808.0
371    }
372    s to_f64 {
373        s as f64 / 9_223_372_036_854_775_808.0
374    }
375});
376
377conversions!(u8, u8 {
378    s to_i8 {
379        if s < 128 {
380            s as i8 - 127 - 1
381        } else {
382            (s - 128) as i8
383        }
384    }
385    s to_i16 {
386        (s as i16 - 128) << 8
387    }
388    s to_i24 {
389        I24::new_unchecked((s as i32 - 128) << 16)
390    }
391    s to_i32 {
392        (s as i32 - 128) << 24
393    }
394    s to_i48 {
395        I48::new_unchecked((s as i64 - 128) << 40)
396    }
397    s to_i64 {
398        (s as i64 - 128) << 56
399    }
400    s to_u16 { (s as u16) << 8 }
401    s to_u24 { U24::new_unchecked((s as i32) << 16) }
402    s to_u32 { (s as u32) << 24 }
403    s to_u48 { U48::new_unchecked((s as i64) << 40) }
404    s to_u64 { (s as u64) << 56 }
405    s to_f32 { super::i8::to_f32(to_i8(s)) }
406    s to_f64 { super::i8::to_f64(to_i8(s)) }
407});
408
409conversions!(u16, u16 {
410    s to_i8 { super::u8::to_i8(to_u8(s)) }
411    s to_i16 {
412        if s < 32_768 {
413            s as i16 - 32_767 - 1
414        } else {
415            (s - 32_768) as i16
416        }
417    }
418    s to_i24 {
419        I24::new_unchecked((s as i32 - 32_768) << 8)
420    }
421    s to_i32 {
422        (s as i32 - 32_768) << 16
423    }
424    s to_i48 {
425        I48::new_unchecked((s as i64 - 32_768) << 32)
426    }
427    s to_i64 {
428        (s as i64 - 32_768) << 48
429    }
430    s to_u8 { (s >> 8) as u8 }
431    s to_u24 { U24::new_unchecked((s as i32) << 8) }
432    s to_u32 { (s as u32) << 16 }
433    s to_u48 { U48::new_unchecked((s as i64) << 32) }
434    s to_u64 { (s as u64) << 48 }
435    s to_f32 { super::i16::to_f32(to_i16(s)) }
436    s to_f64 { super::i16::to_f64(to_i16(s)) }
437});
438
439conversions!(U24, u24 {
440    s to_i8 { super::u8::to_i8(to_u8(s)) }
441    s to_i16 { super::u16::to_i16(to_u16(s)) }
442    s to_i24 {
443        I24::new_unchecked(s.inner() - 8_388_608)
444    }
445    s to_i32 {
446        (s.inner() - 8_388_608) << 8
447    }
448    s to_i48 {
449        I48::new_unchecked(((s.inner() as i64) - 8_388_608) << 24)
450    }
451    s to_i64 {
452        (s.inner() as i64 - 8_388_608) << 40
453    }
454    s to_u8 { (s.inner() >> 16) as u8 }
455    s to_u16 { (s.inner() >> 8) as u16 }
456    s to_u32 { (s.inner() as u32) << 8 }
457    s to_u48 { U48::new_unchecked((s.inner() as i64) << 24) }
458    s to_u64 { (s.inner() as u64) << 40 }
459    s to_f32 { super::i24::to_f32(to_i24(s)) }
460    s to_f64 { super::i24::to_f64(to_i24(s)) }
461});
462
463conversions!(u32, u32 {
464    s to_i8 { super::u8::to_i8(to_u8(s)) }
465    s to_i16 { super::u16::to_i16(to_u16(s)) }
466    s to_i24 { super::u24::to_i24(to_u24(s)) }
467    s to_i32 {
468        if s < 2_147_483_648 {
469            s as i32 - 2_147_483_647 - 1
470        } else {
471            (s - 2_147_483_648) as i32
472        }
473    }
474    s to_i48 {
475        I48::new_unchecked((s as i64 - 2_147_483_648) << 16)
476    }
477    s to_i64 {
478        (s as i64 - 2_147_483_648) << 32
479    }
480    s to_u8 { (s >> 24) as u8 }
481    s to_u16 { (s >> 16) as u16 }
482    s to_u24 { U24::new_unchecked((s >> 8) as i32) }
483    s to_u48 { U48::new_unchecked((s as i64) << 16) }
484    s to_u64 { (s as u64) << 32 }
485    s to_f32 { super::i32::to_f32(to_i32(s)) }
486    s to_f64 { super::i32::to_f64(to_i32(s)) }
487});
488
489conversions!(U48, u48 {
490    s to_i8 { super::u8::to_i8(to_u8(s)) }
491    s to_i16 { super::u16::to_i16(to_u16(s)) }
492    s to_i24 { super::u24::to_i24(to_u24(s)) }
493    s to_i32 { super::u32::to_i32(to_u32(s)) }
494    s to_i48 {
495        I48::new_unchecked(s.inner() - 140_737_488_355_328)
496    }
497    s to_i64 {
498        (s.inner() - 140_737_488_355_328) << 16
499    }
500    s to_u8 { (s.inner() >> 40) as u8 }
501    s to_u16 { (s.inner() >> 32) as u16 }
502    s to_u24 { U24::new_unchecked((s.inner() >> 24) as i32) }
503    s to_u32 { (s.inner() >> 16) as u32 }
504    s to_u64 { (s.inner() as u64) << 16 }
505    s to_f32 { super::i48::to_f32(to_i48(s)) }
506    s to_f64 { super::i48::to_f64(to_i48(s)) }
507});
508
509conversions!(u64, u64 {
510    s to_i8 { super::u8::to_i8(to_u8(s)) }
511    s to_i16 { super::u16::to_i16(to_u16(s)) }
512    s to_i24 { super::u24::to_i24(to_u24(s)) }
513    s to_i32 { super::u32::to_i32(to_u32(s)) }
514    s to_i48 { super::u48::to_i48(to_u48(s)) }
515    s to_i64 {
516        if s < 9_223_372_036_854_775_808 {
517            s as i64 - 9_223_372_036_854_775_807 - 1
518        } else {
519            (s - 9_223_372_036_854_775_808) as i64
520        }
521    }
522    s to_u8 { (s >> 56) as u8 }
523    s to_u16 { (s >> 48) as u16 }
524    s to_u24 { U24::new_unchecked((s >> 40) as i32) }
525    s to_u32 { (s >> 32) as u32 }
526    s to_u48 { U48::new_unchecked((s >> 16) as i64) }
527    s to_f32 { super::i64::to_f32(to_i64(s)) }
528    s to_f64 { super::i64::to_f64(to_i64(s)) }
529});
530
531// The following conversions assume `-1.0 <= s < 1.0` (note that +1.0 is excluded) and will
532// overflow otherwise.
533conversions!(f32, f32 {
534    s to_i8 { (s * 128.0) as i8 }
535    s to_i16 { (s * 32_768.0) as i16 }
536    s to_i24 { I24::new_unchecked((s * 8_388_608.0) as i32) }
537    s to_i32 { (s * 2_147_483_648.0) as i32 }
538    s to_i48 { I48::new_unchecked((s * 140_737_488_355_328.0) as i64) }
539    s to_i64 { (s * 9_223_372_036_854_775_808.0) as i64 }
540    s to_u8 { super::i8::to_u8(to_i8(s)) }
541    s to_u16 { super::i16::to_u16(to_i16(s)) }
542    s to_u24 { super::i24::to_u24(to_i24(s)) }
543    s to_u32 { super::i32::to_u32(to_i32(s)) }
544    s to_u48 { super::i48::to_u48(to_i48(s)) }
545    s to_u64 { super::i64::to_u64(to_i64(s)) }
546    s to_f64 { s as f64 }
547});
548
549// The following conversions assume `-1.0 <= s < 1.0` (note that +1.0 is excluded) and will
550// overflow otherwise.
551conversions!(f64, f64 {
552    s to_i8 { (s * 128.0) as i8 }
553    s to_i16 { (s * 32_768.0) as i16 }
554    s to_i24 { I24::new_unchecked((s * 8_388_608.0) as i32) }
555    s to_i32 { (s * 2_147_483_648.0) as i32 }
556    s to_i48 { I48::new_unchecked((s * 140_737_488_355_328.0) as i64) }
557    s to_i64 { (s * 9_223_372_036_854_775_808.0) as i64 }
558    s to_u8 { super::i8::to_u8(to_i8(s)) }
559    s to_u16 { super::i16::to_u16(to_i16(s)) }
560    s to_u24 { super::i24::to_u24(to_i24(s)) }
561    s to_u32 { super::i32::to_u32(to_i32(s)) }
562    s to_u48 { super::i48::to_u48(to_i48(s)) }
563    s to_u64 { super::i64::to_u64(to_i64(s)) }
564    s to_f32 { s as f32 }
565});
566
567/// Similar to the std `From` trait, but specifically for converting between sample types.
568///
569/// We use this trait to be generic over the `Sample::to_sample` and `Sample::from_sample` methods.
570pub trait FromSample<S> {
571    fn from_sample_(s: S) -> Self;
572}
573
574impl<S> FromSample<S> for S {
575    #[inline]
576    fn from_sample_(s: S) -> Self {
577        s
578    }
579}
580
581/// Implement the `FromSample` trait for the given types.
582macro_rules! impl_from_sample {
583    ($T:ty, $fn_name:ident from $({$U:ident: $Umod:ident})*) => {
584        $(
585            impl FromSample<$U> for $T {
586                #[inline]
587                fn from_sample_(s: $U) -> Self {
588                    self::$Umod::$fn_name(s)
589                }
590            }
591        )*
592    };
593}
594
595impl_from_sample! {i8, to_i8 from
596    {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
597    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
598    {f32:f32} {f64:f64}
599}
600
601impl_from_sample! {i16, to_i16 from
602    {i8:i8} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
603    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
604    {f32:f32} {f64:f64}
605}
606
607impl_from_sample! {I24, to_i24 from
608    {i8:i8} {i16:i16} {i32:i32} {I48:i48} {i64:i64}
609    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
610    {f32:f32} {f64:f64}
611}
612
613impl_from_sample! {i32, to_i32 from
614    {i8:i8} {i16:i16} {I24:i24} {I48:i48} {i64:i64}
615    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
616    {f32:f32} {f64:f64}
617}
618
619impl_from_sample! {I48, to_i48 from
620    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {i64:i64}
621    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
622    {f32:f32} {f64:f64}
623}
624
625impl_from_sample! {i64, to_i64 from
626    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48}
627    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
628    {f32:f32} {f64:f64}
629}
630
631impl_from_sample! {u8, to_u8 from
632    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
633    {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
634    {f32:f32} {f64:f64}
635}
636
637impl_from_sample! {u16, to_u16 from
638    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
639    {u8:u8} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
640    {f32:f32} {f64:f64}
641}
642
643impl_from_sample! {U24, to_u24 from
644    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
645    {u8:u8} {u16:u16} {u32:u32} {U48:u48} {u64:u64}
646    {f32:f32} {f64:f64}
647}
648
649impl_from_sample! {u32, to_u32 from
650    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
651    {u8:u8} {u16:u16} {U24:u24} {U48:u48} {u64:u64}
652    {f32:f32} {f64:f64}
653}
654
655impl_from_sample! {U48, to_u48 from
656    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
657    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {u64:u64}
658    {f32:f32} {f64:f64}
659}
660
661impl_from_sample! {u64, to_u64 from
662    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
663    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48}
664    {f32:f32} {f64:f64}
665}
666
667impl_from_sample! {f32, to_f32 from
668    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
669    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
670    {f64:f64}
671}
672
673impl_from_sample! {f64, to_f64 from
674    {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64}
675    {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64}
676    {f32:f32}
677}
678
679/// Similar to the std `Into` trait, but specifically for converting between sample types.
680///
681/// This trait has a blanket implementation for all types that implement
682/// [`FromSample`](./trait.FromSample.html).
683pub trait ToSample<S> {
684    fn to_sample_(self) -> S;
685}
686
687impl<T, U> ToSample<U> for T
688where
689    U: FromSample<T>,
690{
691    #[inline]
692    fn to_sample_(self) -> U {
693        U::from_sample_(self)
694    }
695}
696
697/// Sample types which may be converted to and from some type `S`.
698pub trait Duplex<S>: FromSample<S> + ToSample<S> {}
699impl<S, T> Duplex<S> for T where T: FromSample<S> + ToSample<S> {}