Skip to content

Commit 0e61572

Browse files
committed
Support various audio formats.
1 parent b87c5c1 commit 0e61572

File tree

3 files changed

+150
-58
lines changed

3 files changed

+150
-58
lines changed

memory.x

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ MEMORY {
2525
/*
2626
* This is the bottom of the four striped banks of SRAM in the RP2040.
2727
*/
28-
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x42000 - 0x9080
28+
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x42000 - 0x9090
2929
/*
3030
* This is the top of the four striped banks of SRAM in the RP2040, plus
3131
* SRAM_BANK4 and SRAM_BANK5.
3232
*
3333
* This is carefully calculated to give us 8 KiB of stack space and ensure
3434
* the defmt buffer doesn't span across SRAM_BANK3 and SRAM_BANK4.
3535
*
36-
* 0x9080 should be the (size of .data + size of .bss + size of .uninit +
36+
* 0x9090 should be the (size of .data + size of .bss + size of .uninit +
3737
* 0x2000 for the stack).
3838
*/
39-
RAM : ORIGIN = 0x20042000 - 0x9080, LENGTH = 0x9080
39+
RAM : ORIGIN = 0x20042000 - 0x9090, LENGTH = 0x9090
4040
}
4141

4242
/*

src/i2s.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ pub struct Player {
1919
}
2020

2121
impl Player {
22-
/// Queue some samples for playback.
22+
/// Queue some 16-bit stereo samples for playback.
2323
///
24-
/// Takes as many as will fit in the FIFO. Returns how many were taken,
25-
/// which will always be a multiple of 4 because it always takes them in
26-
/// Little Endian 16-bit stereo.
24+
/// Takes as many as will fit in the FIFO. Returns how many bytes were
25+
/// taken, which will always be a multiple of 4 because it always takes them
26+
/// in Little Endian 16-bit stereo.
2727
///
2828
/// The length of `samples` must be a multiple of 4, as they should be
2929
/// 16-bit stereo pairs.
30-
pub fn play_samples_16bit_stereo_48khz(&mut self, samples: &[u8]) -> usize {
30+
pub fn play_samples_16bit_stereo(&mut self, samples: &[u8]) -> usize {
3131
let mut count = 0;
3232
for samples in samples.chunks_exact(4) {
3333
if self.fifo.ready() {
@@ -43,6 +43,30 @@ impl Player {
4343
count
4444
}
4545

46+
/// Queue some 16-bit mono samples for playback.
47+
///
48+
/// Takes as many as will fit in the FIFO. Returns how many bytes were
49+
/// taken, which will always be a multiple of 2 because it always takes them
50+
/// in Little Endian 16-bit mono, and duplicates them as they go into the
51+
/// FIFO.
52+
///
53+
/// The length of `samples` must be a multiple of 2, as they should be
54+
/// 16-bit mono samples.
55+
pub fn play_samples_16bit_mono(&mut self, samples: &[u8]) -> usize {
56+
let mut count = 0;
57+
for samples in samples.chunks_exact(2) {
58+
if self.fifo.ready() {
59+
let mono_sample = (samples[1] as u32) << 8 | (samples[0] as u32);
60+
let stereo_sample = mono_sample << 16 | mono_sample;
61+
self.fifo.enqueue(stereo_sample).unwrap();
62+
count += 2;
63+
} else {
64+
break;
65+
}
66+
}
67+
count
68+
}
69+
4670
/// Space, in stereo samples.
4771
pub fn available_space(&self) -> usize {
4872
self.fifo.capacity() - self.fifo.len()

src/main.rs

Lines changed: 118 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ struct Hardware {
174174
/// The watchdog
175175
watchdog: hal::Watchdog,
176176
/// The audio CODEC
177-
codec: tlv320aic23::Codec,
177+
audio_codec: tlv320aic23::Codec,
178178
/// PCM sample output queue
179179
audio_player: i2s::Player,
180+
/// How we are currently configured
181+
audio_config: common::audio::Config,
180182
}
181183

182184
/// Flips between true and false so we always send a unique read request
@@ -1006,32 +1008,37 @@ impl Hardware {
10061008
i2s_lr_clock: hal_pins.gpio28.into_mode(),
10071009
};
10081010

1009-
let mut codec = tlv320aic23::Codec::new(tlv320aic23::BusAddress::CsLow);
1010-
if let Err(hal::i2c::Error::Abort(code)) = codec.reset(&mut i2c.acquire_i2c()) {
1011+
let mut audio_codec = tlv320aic23::Codec::new(tlv320aic23::BusAddress::CsLow);
1012+
if let Err(hal::i2c::Error::Abort(code)) = audio_codec.reset(&mut i2c.acquire_i2c()) {
10111013
defmt::error!("CODEC did not respond: code {:?}", code);
10121014
}
1013-
codec.set_digital_interface_enabled(true);
1014-
codec.set_dac_selected(true);
1015-
codec.set_dac_mute(false);
1016-
codec.set_bypass(false);
1017-
codec.set_line_input_mute(true, tlv320aic23::Channel::Both);
1018-
codec.set_powered_on(tlv320aic23::Subsystem::AnalogDigitalConverter, true);
1019-
codec.set_powered_on(tlv320aic23::Subsystem::MicrophoneInput, true);
1020-
codec.set_powered_on(tlv320aic23::Subsystem::LineInput, true);
1021-
codec.set_headphone_output_volume(100, tlv320aic23::Channel::Both);
1022-
codec.set_sample_rate(
1023-
tlv320aic23::CONFIG_USB_44K1,
1015+
audio_codec.set_digital_interface_enabled(true);
1016+
audio_codec.set_dac_selected(true);
1017+
audio_codec.set_dac_mute(false);
1018+
audio_codec.set_bypass(false);
1019+
audio_codec.set_line_input_mute(true, tlv320aic23::Channel::Both);
1020+
audio_codec.set_powered_on(tlv320aic23::Subsystem::AnalogDigitalConverter, true);
1021+
audio_codec.set_powered_on(tlv320aic23::Subsystem::MicrophoneInput, true);
1022+
audio_codec.set_powered_on(tlv320aic23::Subsystem::LineInput, true);
1023+
// Set volume to -6dB. 73 = 0 dB, and it's 1 dB per step.
1024+
audio_codec.set_headphone_output_volume(64, tlv320aic23::Channel::Both);
1025+
audio_codec.set_sample_rate(
1026+
tlv320aic23::CONFIG_USB_48K,
10241027
tlv320aic23::LrSwap::Disabled,
10251028
tlv320aic23::LrPhase::RightOnHigh,
10261029
tlv320aic23::Mode::Controller,
10271030
tlv320aic23::InputBitLength::B16,
10281031
tlv320aic23::DataFormat::I2s,
10291032
);
1030-
if let Err(hal::i2c::Error::Abort(code)) = codec.sync(&mut i2c.acquire_i2c()) {
1033+
let audio_config = common::audio::Config {
1034+
sample_format: common::audio::SampleFormat::SixteenBitStereo,
1035+
sample_rate_hz: 48000,
1036+
};
1037+
if let Err(hal::i2c::Error::Abort(code)) = audio_codec.sync(&mut i2c.acquire_i2c()) {
10311038
defmt::error!("CODEC did not respond: code {:?}", code);
10321039
}
10331040

1034-
let sample_queue = i2s::init(pio1, resets);
1041+
let audio_player = i2s::init(pio1, resets);
10351042

10361043
(
10371044
Hardware {
@@ -1062,8 +1069,9 @@ impl Hardware {
10621069
card_state: CardState::Unplugged,
10631070
clocks,
10641071
watchdog,
1065-
codec,
1066-
audio_player: sample_queue,
1072+
audio_codec,
1073+
audio_player,
1074+
audio_config,
10671075
},
10681076
hal_pins.gpio20.into_pull_up_input(),
10691077
)
@@ -2092,43 +2100,43 @@ extern "C" fn audio_mixer_channel_get_info(
20922100
name: common::FfiString::new("LeftOut"),
20932101
direction: common::audio::Direction::Output,
20942102
max_level: 79,
2095-
current_level: hw.codec.get_headphone_output_volume().0,
2103+
current_level: hw.audio_codec.get_headphone_output_volume().0,
20962104
}),
20972105
1 => FfiOption::Some(common::audio::MixerChannelInfo {
20982106
name: common::FfiString::new("RightOut"),
20992107
direction: common::audio::Direction::Output,
21002108
max_level: 79,
2101-
current_level: hw.codec.get_headphone_output_volume().1,
2109+
current_level: hw.audio_codec.get_headphone_output_volume().1,
21022110
}),
21032111
2 => FfiOption::Some(common::audio::MixerChannelInfo {
21042112
name: common::FfiString::new("LeftIn"),
21052113
direction: common::audio::Direction::Input,
21062114
max_level: 31,
2107-
current_level: hw.codec.get_line_input_volume_steps().0,
2115+
current_level: hw.audio_codec.get_line_input_volume_steps().0,
21082116
}),
21092117
3 => FfiOption::Some(common::audio::MixerChannelInfo {
21102118
name: common::FfiString::new("RightIn"),
21112119
direction: common::audio::Direction::Input,
21122120
max_level: 31,
2113-
current_level: hw.codec.get_line_input_volume_steps().1,
2121+
current_level: hw.audio_codec.get_line_input_volume_steps().1,
21142122
}),
21152123
4 => FfiOption::Some(common::audio::MixerChannelInfo {
21162124
name: common::FfiString::new("LeftInMute"),
21172125
direction: common::audio::Direction::Input,
21182126
max_level: 1,
2119-
current_level: hw.codec.get_line_input_mute().0 as u8,
2127+
current_level: hw.audio_codec.get_line_input_mute().0 as u8,
21202128
}),
21212129
5 => FfiOption::Some(common::audio::MixerChannelInfo {
21222130
name: common::FfiString::new("RightInMute"),
21232131
direction: common::audio::Direction::Input,
21242132
max_level: 1,
2125-
current_level: hw.codec.get_line_input_mute().1 as u8,
2133+
current_level: hw.audio_codec.get_line_input_mute().1 as u8,
21262134
}),
21272135
6 => FfiOption::Some(common::audio::MixerChannelInfo {
21282136
name: common::FfiString::new("Sidetone"),
21292137
direction: common::audio::Direction::Output,
21302138
max_level: 5,
2131-
current_level: match hw.codec.get_sidetone_level() {
2139+
current_level: match hw.audio_codec.get_sidetone_level() {
21322140
tlv320aic23::Sidetone::ZeroDb => 5,
21332141
tlv320aic23::Sidetone::Minus6 => 4,
21342142
tlv320aic23::Sidetone::Minus9 => 3,
@@ -2141,37 +2149,37 @@ extern "C" fn audio_mixer_channel_get_info(
21412149
name: common::FfiString::new("MicEnable"),
21422150
direction: common::audio::Direction::Input,
21432151
max_level: 1,
2144-
current_level: hw.codec.get_audio_input() as u8,
2152+
current_level: hw.audio_codec.get_audio_input() as u8,
21452153
}),
21462154
8 => FfiOption::Some(common::audio::MixerChannelInfo {
21472155
name: common::FfiString::new("MicBoost"),
21482156
direction: common::audio::Direction::Input,
21492157
max_level: 1,
2150-
current_level: hw.codec.get_microphone_boost() as u8,
2158+
current_level: hw.audio_codec.get_microphone_boost() as u8,
21512159
}),
21522160
9 => FfiOption::Some(common::audio::MixerChannelInfo {
21532161
name: common::FfiString::new("MicMute"),
21542162
direction: common::audio::Direction::Input,
21552163
max_level: 1,
2156-
current_level: hw.codec.get_microphone_mute() as u8,
2164+
current_level: hw.audio_codec.get_microphone_mute() as u8,
21572165
}),
21582166
10 => FfiOption::Some(common::audio::MixerChannelInfo {
21592167
name: common::FfiString::new("Bypass"),
21602168
direction: common::audio::Direction::Input,
21612169
max_level: 1,
2162-
current_level: hw.codec.get_bypass() as u8,
2170+
current_level: hw.audio_codec.get_bypass() as u8,
21632171
}),
21642172
11 => FfiOption::Some(common::audio::MixerChannelInfo {
21652173
name: common::FfiString::new("DacEnable"),
21662174
direction: common::audio::Direction::Output,
21672175
max_level: 1,
2168-
current_level: hw.codec.get_dac_selected() as u8,
2176+
current_level: hw.audio_codec.get_dac_selected() as u8,
21692177
}),
21702178
12 => FfiOption::Some(common::audio::MixerChannelInfo {
21712179
name: common::FfiString::new("DacMute"),
21722180
direction: common::audio::Direction::Output,
21732181
max_level: 1,
2174-
current_level: hw.codec.get_dac_mute() as u8,
2182+
current_level: hw.audio_codec.get_dac_mute() as u8,
21752183
}),
21762184
_ => FfiOption::None,
21772185
}
@@ -2192,60 +2200,120 @@ extern "C" fn audio_mixer_channel_set_level(audio_mixer_id: u8, level: u8) -> Ap
21922200
use tlv320aic23::Channel;
21932201

21942202
match audio_mixer_id {
2195-
0 => hw.codec.set_headphone_output_volume(level, Channel::Left),
2196-
1 => hw.codec.set_headphone_output_volume(level, Channel::Right),
2197-
2 => hw.codec.set_line_input_volume_steps(level, Channel::Left),
2198-
3 => hw.codec.set_line_input_volume_steps(level, Channel::Right),
2199-
4 => hw.codec.set_line_input_mute(level == 1, Channel::Left),
2200-
5 => hw.codec.set_line_input_mute(level == 1, Channel::Right),
2201-
6 => hw.codec.set_sidetone_level(match level {
2203+
0 => hw
2204+
.audio_codec
2205+
.set_headphone_output_volume(level, Channel::Left),
2206+
1 => hw
2207+
.audio_codec
2208+
.set_headphone_output_volume(level, Channel::Right),
2209+
2 => hw
2210+
.audio_codec
2211+
.set_line_input_volume_steps(level, Channel::Left),
2212+
3 => hw
2213+
.audio_codec
2214+
.set_line_input_volume_steps(level, Channel::Right),
2215+
4 => hw
2216+
.audio_codec
2217+
.set_line_input_mute(level == 1, Channel::Left),
2218+
5 => hw
2219+
.audio_codec
2220+
.set_line_input_mute(level == 1, Channel::Right),
2221+
6 => hw.audio_codec.set_sidetone_level(match level {
22022222
5 => tlv320aic23::Sidetone::ZeroDb,
22032223
4 => tlv320aic23::Sidetone::Minus6,
22042224
3 => tlv320aic23::Sidetone::Minus9,
22052225
2 => tlv320aic23::Sidetone::Minus12,
22062226
1 => tlv320aic23::Sidetone::Minus18,
22072227
_ => tlv320aic23::Sidetone::Disabled,
22082228
}),
2209-
7 => hw.codec.set_audio_input(match level {
2229+
7 => hw.audio_codec.set_audio_input(match level {
22102230
0 => tlv320aic23::AudioInput::LineInput,
22112231
_ => tlv320aic23::AudioInput::Microphone,
22122232
}),
2213-
8 => hw.codec.set_microphone_boost(level == 1),
2214-
9 => hw.codec.set_microphone_mute(level == 1),
2215-
10 => hw.codec.set_bypass(level == 1),
2216-
11 => hw.codec.set_dac_selected(level == 1),
2217-
12 => hw.codec.set_dac_mute(level == 1),
2233+
8 => hw.audio_codec.set_microphone_boost(level == 1),
2234+
9 => hw.audio_codec.set_microphone_mute(level == 1),
2235+
10 => hw.audio_codec.set_bypass(level == 1),
2236+
11 => hw.audio_codec.set_dac_selected(level == 1),
2237+
12 => hw.audio_codec.set_dac_mute(level == 1),
22182238
_ => {
22192239
return ApiResult::Err(neotron_common_bios::Error::InvalidDevice);
22202240
}
22212241
};
2222-
if hw.codec.sync(&mut hw.i2c.acquire_i2c()).is_ok() {
2242+
if hw.audio_codec.sync(&mut hw.i2c.acquire_i2c()).is_ok() {
22232243
neotron_common_bios::FfiResult::Ok(())
22242244
} else {
22252245
ApiResult::Err(neotron_common_bios::Error::DeviceError(0))
22262246
}
22272247
}
22282248

2229-
extern "C" fn audio_output_set_config(_config: common::audio::Config) -> ApiResult<()> {
2230-
ApiResult::Err(CError::Unimplemented)
2249+
extern "C" fn audio_output_set_config(config: common::audio::Config) -> ApiResult<()> {
2250+
// We can't support 8-bit samples with this CODEC. See `audio_output_data`
2251+
// if you add any more supported sample formats, so the playback routine
2252+
// does the right thing.
2253+
match config.sample_format {
2254+
common::audio::SampleFormat::SixteenBitStereo
2255+
| common::audio::SampleFormat::SixteenBitMono => {
2256+
// Format Ok
2257+
}
2258+
_ => {
2259+
return ApiResult::Err(CError::UnsupportedConfiguration(0));
2260+
}
2261+
}
2262+
let sample_rate = match config.sample_rate_hz {
2263+
48000 => tlv320aic23::CONFIG_USB_48K,
2264+
44100 => tlv320aic23::CONFIG_USB_44K1,
2265+
32000 => tlv320aic23::CONFIG_USB_32K,
2266+
8000 => tlv320aic23::CONFIG_USB_8K,
2267+
_ => {
2268+
return ApiResult::Err(CError::UnsupportedConfiguration(1));
2269+
}
2270+
};
2271+
let mut lock = HARDWARE.lock();
2272+
let hw = lock.as_mut().unwrap();
2273+
hw.audio_codec.set_sample_rate(
2274+
sample_rate,
2275+
tlv320aic23::LrSwap::Disabled,
2276+
tlv320aic23::LrPhase::RightOnHigh,
2277+
tlv320aic23::Mode::Controller,
2278+
tlv320aic23::InputBitLength::B16,
2279+
tlv320aic23::DataFormat::I2s,
2280+
);
2281+
hw.audio_config = config;
2282+
ApiResult::Ok(())
22312283
}
22322284

22332285
extern "C" fn audio_output_get_config() -> ApiResult<common::audio::Config> {
2234-
ApiResult::Err(CError::Unimplemented)
2286+
let mut lock = HARDWARE.lock();
2287+
let hw = lock.as_mut().unwrap();
2288+
let config = hw.audio_config.clone();
2289+
ApiResult::Ok(config)
22352290
}
22362291

22372292
unsafe extern "C" fn audio_output_data(samples: FfiByteSlice) -> ApiResult<usize> {
22382293
let mut lock = HARDWARE.lock();
22392294
let hw = lock.as_mut().unwrap();
22402295
let samples = samples.as_slice();
2241-
let count = hw.audio_player.play_samples_16bit_stereo_48khz(samples);
2296+
// We only support these two kinds.
2297+
let count = match hw.audio_config.sample_format {
2298+
common::audio::SampleFormat::SixteenBitMono => {
2299+
hw.audio_player.play_samples_16bit_mono(samples)
2300+
}
2301+
common::audio::SampleFormat::SixteenBitStereo => {
2302+
hw.audio_player.play_samples_16bit_stereo(samples)
2303+
}
2304+
_ => {
2305+
return ApiResult::Err(CError::Unimplemented);
2306+
}
2307+
};
22422308
ApiResult::Ok(count)
22432309
}
22442310

22452311
extern "C" fn audio_output_get_space() -> ApiResult<usize> {
22462312
let mut lock = HARDWARE.lock();
22472313
let hw = lock.as_mut().unwrap();
2248-
// The result is in samples, where each sample is 16-bit stereo (i.e. 32-bits)
2314+
// The result is in samples, where each sample is 16-bit stereo (i.e.
2315+
// 32-bits) or 16-bit mono (i.e. 16-bit) depending on the audio
2316+
// configuration.
22492317
ApiResult::Ok(hw.audio_player.available_space())
22502318
}
22512319

0 commit comments

Comments
 (0)