MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ reconstruct_grains_additive_stream

const ComputationGrammar::Rule::Executor MayaFlux::Yantra::Granular::reconstruct_grains_additive_stream

Grammar rule executor — OLA reconstruct into DynamicSoundStream.

Definition at line 270 of file GranularWorkflow.cpp.

271 {
272 auto datum = safe_any_cast_or_throw<Datum<Kakshya::RegionGroup>>(input);
273 const auto& regions = datum.data.regions;
274
275 if (regions.empty()) {
276 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::ComputeMatrix,
277 std::source_location::current(), "reconstruct_grains_additive_stream: RegionGroup contains no grains");
278 }
279
280 if (!datum.container || !*datum.container) {
281 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::ComputeMatrix,
282 std::source_location::current(), "reconstruct_grains_additive_stream: no source container in datum");
283 }
284
285 auto source = *datum.container;
286 const auto num_ch = static_cast<uint32_t>(source->get_structure().get_channel_count());
287 const uint32_t sample_rate = [&]() -> uint32_t {
288 if (auto sc = std::dynamic_pointer_cast<Kakshya::SoundStreamContainer>(source))
289 return sc->get_sample_rate();
290 return 48000U;
291 }();
292
293 const auto grain_sz = safe_any_cast_or_default<uint32_t>(
294 datum.data.get_attribute<uint32_t>("grain_size").has_value()
295 ? std::any(datum.data.get_attribute<uint32_t>("grain_size").value())
296 : std::any {},
297 1024U);
298 const auto hop_sz = safe_any_cast_or_default<uint32_t>(
299 datum.data.get_attribute<uint32_t>("hop_size").has_value()
300 ? std::any(datum.data.get_attribute<uint32_t>("hop_size").value())
301 : std::any {},
302 grain_sz);
303
304 const auto taper = safe_any_cast_or_default<GrainTaper>(
305 ctx.execution_metadata.contains("grain_taper")
306 ? ctx.execution_metadata.at("grain_taper")
307 : std::any {},
308 GrainTaper {});
309
310 const uint64_t out_frames = hop_sz * regions.size() + grain_sz;
311 std::vector<std::vector<double>> channel_data(num_ch, std::vector<double>(out_frames, 0.0));
312
313 Kakshya::iterate_region_channels(regions, source, num_ch, {},
314 [&](size_t gi, uint32_t ch, std::span<double> samples) {
315 std::vector<double> grain(samples.begin(), samples.end());
316 if (taper)
317 taper(grain);
318 const uint64_t offset = gi * hop_sz;
319 for (uint64_t i = 0; i < grain.size() && offset + i < out_frames; ++i)
320 channel_data[ch][offset + i] += grain[i];
321 });
322
323 auto stream = std::make_shared<Kakshya::DynamicSoundStream>(sample_rate, num_ch);
324
325 std::vector<std::span<const double>> spans;
326 spans.reserve(num_ch);
327 for (auto& ch : channel_data)
328 spans.emplace_back(ch);
329
330 stream->write_frames(spans, 0);
331
332 return Datum<std::shared_ptr<Kakshya::SignalSourceContainer>> {
333 std::dynamic_pointer_cast<Kakshya::SignalSourceContainer>(stream), {}
334 };
335};

Referenced by make_granular_matrix().