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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! Audio operation and management.
#![allow(unused_imports)]
use core::ffi::c_void;
use pspsdk_macros::psp_stub;
use crate::sys::{SceError, SceIntoOkValue, SceResult, SceResultOk};
pub mod atrac;
pub mod routing;
/// Minimum value for audio sample value.
pub const AUDIO_SAMPLE_MIN: u32 = 64;
/// Maximum value for audio sample value.
pub const AUDIO_SAMPLE_MAX: u32 = 65472;
/// Representation of the PSP channel number.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AudioChannelId(u32);
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[doc(alias("SceAudioInputParams", "pspAudioInputParams"))]
pub struct AudioInputParams {
/// Automatic Level Control (ALC) configuration.
pub alto_level_control: i32,
/// The input gain (amplification level).
pub gain: i32,
/// The noise gate/reduction threshold.
pub noise: i32,
/// The hold time before decay begins (in audio processing envelope).
pub hold: i32,
/// The decay rate (how quickly the level decreases).
pub decay: i32,
/// The attack rate (how quickly the level increases).
pub attack: i32,
}
/// Possible audio formats for PSP.
#[repr(u32)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AudioFormats {
/// Channel set to stereo output.
#[doc(alias("PSP_AUDIO_FORMAT_STEREO"))]
Stereo = 0,
/// Channel set to mono output.
#[doc(alias("PSP_AUDIO_FORMAT_MONO"))]
Mono = 0x10,
}
/// Possible values for Audio output frequency.
#[repr(u32)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AudioOutputFrequency {
Khz48 = 48000,
Khz44_1 = 44100,
Khz32 = 32000,
Khz24 = 24000,
Khz22_05 = 22050,
Khz16 = 16000,
Khz12 = 12000,
Khz11_025 = 11025,
Khz8 = 8000,
}
/// Possible values for Audio input frequency.
#[repr(u32)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AudioInputFrequency {
Khz44_1 = 44100,
Khz22_05 = 22050,
Khz11_025 = 11025,
}
#[psp_stub(libname = "sceAudio", flags = 0x4009, use_crate)]
unsafe extern "C" {
/// Allocate and initialize a hardware output channel.
///
/// # Parameters
///
/// - `channel`: The channel ID to reserve. Pass [`AudioChannelId::NEXT`] to get the first
/// available channel.
/// - `sample_count`: The number of samples that can be output on the channel per output call.
/// It must be a value between [`AUDIO_SAMPLE_MIN`] and [`AUDIO_SAMPLE_MAX`], and it must be
/// aligned to 64 bytes. Use [`audio_sample_align`] to align it.
/// - `format`: The output format to use for the channel.
///
/// # Return value
///
/// The channel ID on success, an error value otherwise.
#[nid(0x5EC81C55)]
pub safe fn sceAudioChReserve(
channel: AudioChannelId, sample_count: i32, format: AudioFormats,
) -> SceResult<AudioChannelId>;
}
/// Make the given sample count a multiple of 64.
pub const fn audio_sample_align(sample_count: i32) -> i32 {
(sample_count + 63) & !63
}
impl AudioChannelId {
/// Channel 0.
pub const CHANNEL_0: AudioChannelId = unsafe { Self::from_raw_unchecked(0) };
/// Channel 1.
pub const CHANNEL_1: AudioChannelId = unsafe { Self::from_raw_unchecked(1) };
/// Channel 2.
pub const CHANNEL_2: AudioChannelId = unsafe { Self::from_raw_unchecked(2) };
/// Channel 3.
pub const CHANNEL_3: AudioChannelId = unsafe { Self::from_raw_unchecked(3) };
/// Channel 4.
pub const CHANNEL_4: AudioChannelId = unsafe { Self::from_raw_unchecked(4) };
/// Channel 5.
pub const CHANNEL_5: AudioChannelId = unsafe { Self::from_raw_unchecked(5) };
/// Channel 6.
pub const CHANNEL_6: AudioChannelId = unsafe { Self::from_raw_unchecked(6) };
/// Channel 7.
pub const CHANNEL_7: AudioChannelId = unsafe { Self::from_raw_unchecked(7) };
/// Channel value to request a the next channel on functions like [`sceAudioChReserve`].
pub const NEXT: AudioChannelId = unsafe { Self::from_raw_unchecked(0xFFFFFFFF) };
/// Create a new channel number from a raw value.
///
/// This functions checks for the value of `raw` to be a in the range of possible `SceChannel`
/// values used by the PSP OS, returning an [`None`] otherwise.
pub const fn from_raw(raw: u32) -> Option<Self> {
match raw {
0u32..=7 => Some(unsafe { Self::from_raw_unchecked(raw) }),
0xFFFFFFFF => Some(Self::NEXT),
_ => None,
}
}
/// Create a new channel number structure from a raw value without checking value range.
///
/// # Safety
///
/// Immediate language UB if `val` is not within the valid range for this
/// type, as it violates the validity invariant.
#[inline]
pub const unsafe fn from_raw_unchecked(raw: u32) -> Self {
Self(raw)
}
#[inline]
pub const fn to_inner(self) -> u32 {
// SAFETY: pattern types are always legal values of their base type
// (Not using `.0` because that has perf regressions.)
unsafe { core::mem::transmute(self) }
}
}
impl crate::private::Sealed for AudioChannelId {}
unsafe impl SceResultOk for AudioChannelId {
unsafe fn handle_ok_value(ok_value: u32) -> Result<Self, SceError> {
// On result Channel is never 0xFFFFFFFF
match ok_value {
0..=7 => Ok(unsafe { Self::from_raw_unchecked(ok_value) }),
_ => Err(SceError::INVALID_VALUE),
}
}
}
unsafe impl SceIntoOkValue for AudioChannelId {
fn into_ok_value(self) -> u32 {
self.to_inner()
}
}