YARP
Yet Another Robot Platform
audioToFileDevice.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: LGPL-2.1-or-later
4 */
5
6#include "audioToFileDevice.h"
7
8#include <yarp/os/Thread.h>
9#include <yarp/os/Time.h>
10#include <yarp/os/Stamp.h>
12#include <yarp/os/LogStream.h>
13
14#include <mutex>
15#include <string>
16
17
18using namespace yarp::os;
19using namespace yarp::dev;
20using namespace yarp::sig;
21
22namespace {
23YARP_LOG_COMPONENT(AUDIOTOFILE, "yarp.device.audioToFileDevice")
24}
25
27 m_audio_filename("audio_out.wav")
28{
29}
30
32{
33 close();
34}
35
37{
38 if (config.check("help"))
39 {
40 yCInfo(AUDIOTOFILE, "Some examples:");
41 yCInfo(AUDIOTOFILE, "yarpdev --device audioToFileDevice --help");
42 yCInfo(AUDIOTOFILE, "yarpdev --device AudioPlayerWrapper --subdevice audioToFileDevice --start");
43 yCInfo(AUDIOTOFILE, "yarpdev --device AudioPlayerWrapper --subdevice audioToFileDevice --start --file_name audio_out.wav --save_mode overwrite_file");
44 yCInfo(AUDIOTOFILE, "save_mode can be overwrite_file, append_file, rename_file, break_file");
45 yCInfo(AUDIOTOFILE, "use --add_marker option to add a marker at the beginning and at the ending of each received waveform");
46 return false;
47 }
48
49 bool b = configurePlayerAudioDevice(config.findGroup("AUDIO_BASE"), "audioToFileDevice");
50 if (!b) { return false; }
51
52 if (config.check("file_name"))
53 {
54 m_audio_filename=config.find("file_name").asString();
55 yCInfo(AUDIOTOFILE) << "Audio will be saved on exit to file:" << m_audio_filename;
56 }
57 else
58 {
59 yCInfo(AUDIOTOFILE) << "No `file_name` option specified. Audio will be saved on exit to default file:" << m_audio_filename;
60 }
61
62 if (config.check("add_marker")) {m_add_marker=true; yCInfo(AUDIOTOFILE) << "Audio marker option enabled";}
63
64 if (config.find("save_mode").toString() == "overwrite_file") { m_save_mode = save_mode_t::save_overwrite_file;}
65 else if (config.find("save_mode").toString() == "append_data") { m_save_mode = save_mode_t::save_append_data; }
66 else if (config.find("save_mode").toString() == "rename_file") { m_save_mode = save_mode_t::save_rename_file; }
67 else if (config.find("save_mode").toString() == "break_file") { m_save_mode = save_mode_t::save_break_file; }
68 else if (config.check("save_mode")) { yError() << "Unsupported value for save_mode parameter"; return false; }
69
70 if (m_save_mode == save_mode_t::save_overwrite_file) { yCInfo(AUDIOTOFILE) << "overwrite_file mode selected. File will be saved both on exit and on stop"; }
71 else if (m_save_mode == save_mode_t::save_append_data) { yCInfo(AUDIOTOFILE) << "append_data mode selected. File will be saved on exit only"; }
72 else if (m_save_mode == save_mode_t::save_rename_file) { yCInfo(AUDIOTOFILE) << "rename_file mode selected. File will be saved both on exit and on stop"; }
73 else if (m_save_mode == save_mode_t::save_break_file) { yCInfo(AUDIOTOFILE) << "break_file mode selected."; }
74 else { return false; }
75
76 return true;
77}
78
79void audioToFileDevice::save_to_file()
80{
81 //of the buffer is empty, there is nothing to save
82 if (m_sounds.size() == 0) {
83 return;
84 }
85
86 //we need to set the number of channels and the frequency before calling the
87 //concatenation operator
88 m_audioFile.setFrequency(m_sounds.front().getFrequency());
89 m_audioFile.resize(0, m_sounds.front().getChannels());
90 while (!m_sounds.empty())
91 {
92 yarp::sig::Sound curr_sound = m_sounds.front();
93 size_t ss_size = curr_sound.getSamples();
94 size_t ch_size = curr_sound.getChannels();
95
96 if (!m_add_marker)
97 {
98 m_audioFile += curr_sound;
99 }
100 else
101 {
102 //if required, create a sound with a marker at the beginning and at the end
103 yarp::sig::Sound marked_sound;
104 marked_sound.setFrequency(curr_sound.getFrequency());
105 marked_sound.resize(ss_size + 5, ch_size);
106
107 for (size_t c = 0; c < ch_size; c++)
108 {
109 for (size_t i = 0; i < ss_size; i++)
110 {
111 marked_sound.set(curr_sound.get(i, c), i, c);
112 }
113 for (size_t i = ss_size; i < ss_size + 5; i++)
114 {
115 marked_sound.set(32000, i, c);
116 }
117 marked_sound.set(-32000, 0, c);
118 }
119
120 m_audioFile += marked_sound;
121 }
122 m_sounds.pop_front();
123 }
124
125 //remove the extension .wav from the filename
126 size_t lastindex = m_audio_filename.find_last_of(".");
127 std::string trunc_filename = m_audio_filename.substr(0, lastindex);
128 std::string trunc_extension =".wav";
129 if (lastindex!= std::string::npos)
130 {
131 trunc_extension = m_audio_filename.substr(lastindex, std::string::npos);
132 }
133
134 if (m_save_mode == save_mode_t::save_rename_file ||
135 m_save_mode == save_mode_t::save_break_file)
136 {
137 trunc_filename = trunc_filename +std::to_string(m_filename_counter++);
138 }
139
140 std::string complete_filename = trunc_filename + trunc_extension;
141 bool ok = yarp::sig::file::write(m_audioFile, complete_filename.c_str());
142 if (ok)
143 {
144 yCDebug(AUDIOTOFILE) << "Wrote audio to:" << complete_filename;
145 }
146}
147
149{
150 save_to_file();
151 return true;
152}
153
155{
156 std::lock_guard<std::recursive_mutex> lock(m_mutex);
157 yCDebug(AUDIOTOFILE) << "start";
158 m_playback_enabled = true;
159 if (m_save_mode != save_mode_t::save_append_data)
160 {
161 m_sounds.clear();
162 }
163 return true;
164}
165
167{
168 std::lock_guard<std::recursive_mutex> lock(m_mutex);
169 yCDebug(AUDIOTOFILE) << "stop";
170 m_playback_enabled = false;
171 if (m_save_mode != save_mode_t::save_append_data)
172 {
173 save_to_file();
174 }
175 return true;
176}
177
179{
180 std::lock_guard<std::recursive_mutex> lock(m_mutex);
181 if (m_save_mode == save_break_file)
182 {
183 m_sounds.push_back(sound);
184 save_to_file();
185 return true;
186 }
188 {
189 m_sounds.push_back(sound);
190 }
191 return true;
192}
193
195{
196 std::lock_guard<std::recursive_mutex> lock(m_mutex);
197 if (gain > 0)
198 {
199 m_hw_gain = gain;
200 return true;
201 }
202 return false;
203}
204
206{
207 yCError(AUDIOTOFILE, "configureDeviceAndStart() Not yet implemented");
208 return true;
209}
210
212{
213 yCError(AUDIOTOFILE, "interruptDeviceAndClose() Not yet implemented");
214 return true;
215}
216
218{
219 yCError(AUDIOTOFILE, "waitUntilPlaybackStreamIsComplete() Not yet implemented");
220 return;
221}
#define yError(...)
Definition: Log.h:356
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
virtual bool renderSound(const yarp::sig::Sound &sound) override
Render a sound using a device (i.e.
virtual bool configureDeviceAndStart() override
virtual bool interruptDeviceAndClose() override
bool close() override
Close the DeviceDriver.
virtual void waitUntilPlaybackStreamIsComplete() override
virtual bool setHWGain(double gain) override
Sets the hardware gain of the playback device (if supported by the hardware)
virtual bool startPlayback() override
Start the playback.
virtual bool stopPlayback() override
Stop the playback.
~audioToFileDevice() override
bool configurePlayerAudioDevice(yarp::os::Searchable &config, std::string device_name)
A base class for nested structures that can be searched.
Definition: Searchable.h:63
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:356
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition: Sound.h:25
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:229
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:424
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:168
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:224
audio_sample get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:175
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:209
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:419
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
std::string to_string(IntegerType x)
Definition: numeric.h:115
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:1091