2 #include <ossia/audio/drwav_write_handle.hpp>
3 #include <ossia/network/value/detail/value_conversion_impl.hpp>
7 #include <AvndProcesses/AddressTools.hpp>
8 #include <halp/audio.hpp>
9 #include <halp/callback.hpp>
19 halp_meta(name,
"Audio recorder")
20 halp_meta(author,
"ossia team")
21 halp_meta(category,
"Audio/Recording")
22 halp_meta(description,
"Records audio to a file")
23 halp_meta(c_name,
"avnd_audio_recorder")
26 "https://ossia.io/score-docs/processes/audio-utilities.html#audio-recorder")
27 halp_meta(uuid,
"4463dddc-6acf-4106-a680-fed67d8030da")
29 using audio_buffer = boost::container::vector<double>;
34 ossia::drwav_write_handle f;
36 std::string actual_filename;
39 bool must_record =
false;
46 auto fname = QByteArray::fromStdString(this->filename);
47 fname.replace(
"%t", QDateTime::currentDateTimeUtc().toString().toUtf8());
48 actual_filename = fname.toStdString();
49 f.open(actual_filename, channels, rate, 16);
54 bool must_reply =
false;
55 if(f.is_open() && f.written_frames() > 0)
64 void write(
int frames, audio_buffer& data)
66 int these_channels = data.size() / frames;
67 if(these_channels != channels)
69 channels = these_channels;
78 const double** arr = (
const double**)alloca(channels *
sizeof(
double*));
79 for(
int c = 0; c < channels; ++c)
80 arr[c] = data.data() + c * frames;
83 f.write_pcm_frames(frames, arr);
86 std::shared_ptr<recorder_thread> impl = std::make_shared<recorder_thread>();
96 swap(
self.filename, path);
98 self.must_record = must_record;
109 self.write(frames, data);
113 using worker_message = ossia::variant<reset_message, process_message>;
117 std::function<void(std::shared_ptr<recorder_thread>, worker_message)> request;
119 work(std::shared_ptr<recorder_thread> t, worker_message&& mess)
121 bool reply = ossia::visit(
122 [&]<
typename M>(M&& msg) {
return std::forward<M>(msg)(*t); },
126 return [filename = t->actual_filename](
AudioRecorder&
self)
mutable {
128 swap(
self.filename_to_output, filename);
141 halp::dynamic_audio_bus<
"Audio",
double> audio;
142 struct : halp::lineedit<
"File pattern",
"">
144 void update(AudioRecorder&
self) {
self.update(); }
147 struct : halp::toggle<
"Record">
149 void update(AudioRecorder&
self)
163 halp::callback<
"Filename", std::string> finished;
166 int current_rate = 0;
167 void prepare(halp::setup s) { current_rate = s.rate; }
171 worker.request(impl, reset_message{inputs.filename, current_rate, inputs.record});
174 void operator()(
int frames)
176 if(!std::exchange(started,
true))
179 data.resize(inputs.audio.channels * frames, boost::container::default_init);
180 for(
int c = 0; c < inputs.audio.channels; c++)
182 double* src = inputs.audio.samples[c];
183 double* ptr = data.data() + c * frames;
184 for(
int i = 0; i < frames; i++)
188 worker.request(impl, process_message{frames, std::move(data)});
190 if(!filename_to_output.empty())
192 outputs.finished(filename_to_output);
193 filename_to_output.clear();
198 std::optional<int64_t> first_message_sent_pos;
199 std::optional<int64_t> last_message_sent_pos;
202 std::string filename_to_output;