1919
2020using executorch::extension::llm::kOneOverIntMax ;
2121using executorch::extension::llm::kOneOverShortMax ;
22+ using executorch::extension::llm::kWavFormatIeeeFloat ;
2223using executorch::extension::llm::load_wav_audio_data;
2324using executorch::extension::llm::load_wav_header;
2425using executorch::extension::llm::WavHeader;
2526using executorch::extension::testing::TempFile;
2627
2728namespace {
2829
30+ // WAV file format constants
31+ constexpr uint32_t kWavHeaderSizeBeforeData = 36 ;
32+ constexpr uint32_t kWavHeaderSizeWithData = 44 ;
33+
2934// Test fixture to ensure PAL initialization
3035class WavLoaderTest : public ::testing::Test {
3136 protected:
@@ -51,20 +56,27 @@ void append_le32(std::vector<uint8_t>& out, uint32_t value) {
5156 out.push_back (static_cast <uint8_t >((value >> 24 ) & 0xFF ));
5257}
5358
59+ void append_float (std::vector<uint8_t >& out, float value) {
60+ const auto * bytes = reinterpret_cast <const uint8_t *>(&value);
61+ for (size_t i = 0 ; i < sizeof (float ); ++i) {
62+ out.push_back (bytes[i]);
63+ }
64+ }
65+
5466std::vector<uint8_t > make_pcm_wav_bytes (
5567 int bits_per_sample,
5668 const std::vector<int32_t >& samples,
5769 uint16_t num_channels = 1 ,
5870 uint32_t sample_rate = 16000 ) {
59- const size_t bytes_per_sample = static_cast <size_t >(bits_per_sample / 8 );
60- const uint32_t subchunk2_size =
71+ const auto bytes_per_sample = static_cast <size_t >(bits_per_sample / 8 );
72+ const auto subchunk2_size =
6173 static_cast <uint32_t >(samples.size () * bytes_per_sample);
6274 const uint32_t byte_rate = sample_rate * num_channels * bytes_per_sample;
6375 const uint16_t block_align = num_channels * bytes_per_sample;
64- const uint32_t chunk_size = 36 + subchunk2_size;
76+ const auto chunk_size = kWavHeaderSizeBeforeData + subchunk2_size;
6577
6678 std::vector<uint8_t > bytes;
67- bytes.reserve (44 + subchunk2_size);
79+ bytes.reserve (kWavHeaderSizeWithData + subchunk2_size);
6880
6981 append_bytes (bytes, " RIFF" );
7082 append_le32 (bytes, chunk_size);
@@ -91,6 +103,75 @@ std::vector<uint8_t> make_pcm_wav_bytes(
91103 return bytes;
92104}
93105
106+ std::vector<uint8_t > make_float_wav_bytes (
107+ const std::vector<float >& samples,
108+ uint16_t num_channels = 1 ,
109+ uint32_t sample_rate = 16000 ) {
110+ const auto bytes_per_sample = sizeof (float );
111+ const auto subchunk2_size =
112+ static_cast <uint32_t >(samples.size () * bytes_per_sample);
113+ const uint32_t byte_rate = sample_rate * num_channels * bytes_per_sample;
114+ const uint16_t block_align = num_channels * bytes_per_sample;
115+ const auto chunk_size = kWavHeaderSizeBeforeData + subchunk2_size;
116+
117+ std::vector<uint8_t > bytes;
118+ bytes.reserve (kWavHeaderSizeWithData + subchunk2_size);
119+
120+ append_bytes (bytes, " RIFF" );
121+ append_le32 (bytes, chunk_size);
122+ append_bytes (bytes, " WAVE" );
123+ append_bytes (bytes, " fmt " );
124+ append_le32 (bytes, 16 );
125+ append_le16 (bytes, 3 ); // AudioFormat IEEE Float
126+ append_le16 (bytes, num_channels);
127+ append_le32 (bytes, sample_rate);
128+ append_le32 (bytes, byte_rate);
129+ append_le16 (bytes, block_align);
130+ append_le16 (bytes, 32 ); // bits per sample
131+ append_bytes (bytes, " data" );
132+ append_le32 (bytes, subchunk2_size);
133+
134+ for (float sample : samples) {
135+ append_float (bytes, sample);
136+ }
137+
138+ return bytes;
139+ }
140+
141+ std::vector<uint8_t > make_wav_bytes_with_format (
142+ uint16_t audio_format,
143+ int bits_per_sample,
144+ const std::vector<uint8_t >& sample_data,
145+ uint16_t num_channels = 1 ,
146+ uint32_t sample_rate = 16000 ) {
147+ const auto bytes_per_sample = static_cast <size_t >(bits_per_sample / 8 );
148+ const auto subchunk2_size = static_cast <uint32_t >(sample_data.size ());
149+ const uint32_t byte_rate = sample_rate * num_channels * bytes_per_sample;
150+ const uint16_t block_align = num_channels * bytes_per_sample;
151+ const auto chunk_size = kWavHeaderSizeBeforeData + subchunk2_size;
152+
153+ std::vector<uint8_t > bytes;
154+ bytes.reserve (kWavHeaderSizeWithData + subchunk2_size);
155+
156+ append_bytes (bytes, " RIFF" );
157+ append_le32 (bytes, chunk_size);
158+ append_bytes (bytes, " WAVE" );
159+ append_bytes (bytes, " fmt " );
160+ append_le32 (bytes, 16 );
161+ append_le16 (bytes, audio_format);
162+ append_le16 (bytes, num_channels);
163+ append_le32 (bytes, sample_rate);
164+ append_le32 (bytes, byte_rate);
165+ append_le16 (bytes, block_align);
166+ append_le16 (bytes, static_cast <uint16_t >(bits_per_sample));
167+ append_bytes (bytes, " data" );
168+ append_le32 (bytes, subchunk2_size);
169+
170+ bytes.insert (bytes.end (), sample_data.begin (), sample_data.end ());
171+
172+ return bytes;
173+ }
174+
94175} // namespace
95176
96177TEST_F (WavLoaderTest, LoadHeaderParsesPcmMetadata) {
@@ -153,3 +234,31 @@ TEST_F(WavLoaderTest, LoadHeaderReturnsNullWhenMagicMissing) {
153234 std::unique_ptr<WavHeader> header = load_wav_header (file.path ());
154235 EXPECT_EQ (header, nullptr );
155236}
237+
238+ TEST_F (WavLoaderTest, LoadAudioDataFloatFormatReadsDirectly) {
239+ const std::vector<float > samples = {0 .0f , 0 .5f , -0 .5f , 1 .0f , -1 .0f };
240+ const std::vector<uint8_t > wav_bytes = make_float_wav_bytes (samples);
241+ TempFile file (wav_bytes.data (), wav_bytes.size ());
242+
243+ std::unique_ptr<WavHeader> header = load_wav_header (file.path ());
244+ ASSERT_NE (header, nullptr );
245+ EXPECT_EQ (header->AudioFormat , kWavFormatIeeeFloat );
246+ EXPECT_EQ (header->bitsPerSample , 32 );
247+
248+ std::vector<float > audio = load_wav_audio_data (file.path ());
249+ ASSERT_EQ (audio.size (), samples.size ());
250+
251+ for (size_t i = 0 ; i < samples.size (); ++i) {
252+ EXPECT_FLOAT_EQ (audio[i], samples[i]);
253+ }
254+ }
255+
256+ TEST_F (WavLoaderTest, LoadAudioDataRejectsUnsupportedFormat) {
257+ const std::vector<uint8_t > sample_data = {0 , 0 , 0 , 0 };
258+ const std::vector<uint8_t > wav_bytes =
259+ make_wav_bytes_with_format (0x0006 , 16 , sample_data);
260+ TempFile file (wav_bytes.data (), wav_bytes.size ());
261+
262+ EXPECT_DEATH (
263+ { load_wav_audio_data (file.path ()); }, " Unsupported audio format" );
264+ }
0 commit comments