YARP
Yet Another Robot Platform
Sound.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/sig/Sound.h>
11 #include <yarp/sig/Image.h>
12 #include <yarp/os/Bottle.h>
13 #include <yarp/os/PortablePair.h>
14 #include <yarp/os/LogComponent.h>
15 #include <yarp/os/LogStream.h>
16 #include <yarp/os/Time.h>
17 #include <yarp/os/Value.h>
18 #include <functional>
19 
20 #include <cstring>
21 #include <cstdio>
22 
23 using namespace yarp::sig;
24 using namespace yarp::os;
25 
26 namespace {
27 YARP_LOG_COMPONENT(SOUND, "yarp.sig.Sound")
28 }
29 
30 #define HELPER(x) (*((FlexImage*)(x)))
31 
32 Sound::Sound(size_t bytesPerSample)
33 {
34  init(bytesPerSample);
35  m_frequency = 0;
36 }
37 
38 Sound::Sound(const Sound& alt) : yarp::os::Portable()
39 {
40  init(alt.getBytesPerSample());
41  FlexImage& img1 = HELPER(implementation);
42  FlexImage& img2 = HELPER(alt.implementation);
43  img1.copy(img2);
44  m_frequency = alt.m_frequency;
45  synchronize();
46 }
47 
49 {
50  if (alt.m_channels!= m_channels)
51  {
52  yCError(SOUND, "unable to concatenate sounds with different number of channels!");
53  return *this;
54  }
55  if (alt.m_frequency!= m_frequency)
56  {
57  yCError(SOUND, "unable to concatenate sounds with different sample rate!");
58  return *this;
59  }
60 
61  Sound orig= *this;
62  this->resize(this->m_samples+alt.m_samples,m_channels);
63 
64  unsigned char* p1 = orig.getRawData();
65  unsigned char* p2 = alt.getRawData();
66  unsigned char* pout = this->getRawData();
67 
68  for (size_t ch=0; ch<m_channels; ch++)
69  {
70  size_t out1 = ch* this->getBytesPerSample() * this->m_samples;
71  size_t out2 = ch* this->getBytesPerSample() * this->m_samples + this->getBytesPerSample() * orig.m_samples;
72 
73  size_t ori1 = ch * orig.getBytesPerSample() * orig.m_samples;
74  size_t s1 = orig.getBytesPerSample() * orig.m_samples;
75 
76  size_t alt1 = ch * orig.getBytesPerSample() * alt.m_samples;
77  unsigned int s2 = alt.getBytesPerSample() * alt.m_samples;
78 
79  memcpy((void *) &pout[out1], (void *) (p1+ori1), s1);
80  memcpy((void *) &pout[out2], (void *) (p2+alt1), s2);
81  }
82 
83  this->synchronize();
84  return *this;
85 }
86 
87 const Sound& Sound::operator = (const Sound& alt)
88 {
90  FlexImage& img1 = HELPER(implementation);
91  FlexImage& img2 = HELPER(alt.implementation);
92  img1.copy(img2);
93  m_frequency = alt.m_frequency;
94  synchronize();
95  return *this;
96 }
97 
98 void Sound::synchronize()
99 {
100  FlexImage& img = HELPER(implementation);
101  m_samples = img.width();
102  m_channels = img.height();
103 }
104 
105 Sound Sound::subSound(size_t first_sample, size_t last_sample)
106 {
107  if (last_sample > this->m_samples)
108  last_sample = m_samples;
109  if (first_sample > this->m_samples)
110  first_sample = m_samples;
111  if (last_sample < first_sample)
112  last_sample = first_sample;
113 
114  Sound s;
115 
116  s.resize(last_sample-first_sample, this->m_channels);
117  s.setFrequency(this->m_frequency);
118 
119  /*
120  //faster implementation but currently not working
121  unsigned char* p1 = this->getRawData();
122  unsigned char* p2 = s.getRawData();
123  int j=0;
124  for (int i=first_sample; i<last_sample*2; i++)
125  {
126  p2[j++]=p1[i];
127  }
128  */
129 
130  //safe implementation
131  size_t j=0;
132  for (size_t i=first_sample; i<last_sample; i++)
133  {
134  for (size_t c=0; c< this->m_channels; c++)
135  s.set(this->get(i,c),j,c);
136  j++;
137  }
138 
139  s.synchronize();
140 
141  return s;
142 }
143 
144 void Sound::init(size_t bytesPerSample)
145 {
146  implementation = new FlexImage();
147  yCAssert(SOUND, implementation!=nullptr);
148 
149  yCAssert(SOUND, bytesPerSample==2); // that's all that's implemented right now
150  HELPER(implementation).setPixelCode(VOCAB_PIXEL_MONO16);
151  HELPER(implementation).setQuantum(2);
152 
153  m_samples = 0;
154  m_channels = 0;
155  this->m_bytesPerSample = bytesPerSample;
156 }
157 
159 {
160  if (implementation!=nullptr)
161  {
162  delete &HELPER(implementation);
163  implementation = nullptr;
164  }
165 }
166 
167 void Sound::resize(size_t samples, size_t m_channels)
168 {
169  FlexImage& img = HELPER(implementation);
170  img.resize(samples,m_channels);
171  synchronize();
172 }
173 
174 Sound::audio_sample Sound::get(size_t location, size_t channel) const
175 {
176  FlexImage& img = HELPER(implementation);
177  unsigned char *addr = img.getPixelAddress(location,channel);
178  if (m_bytesPerSample ==2)
179  {
180  return *(reinterpret_cast<NetUint16*>(addr));
181  }
182  else
183  {
184  yCError(SOUND, "sound only implemented for 16 bit samples");
185  }
186  return 0;
187 }
188 
190 {
191  size_t size = this->getRawDataSize();
192  unsigned char* p = this->getRawData();
193  memset(p,0,size);
194 }
195 
196 bool Sound::clearChannel(size_t chan)
197 {
198  if (chan > this->m_channels) return false;
199  for (size_t i = 0; i < this->m_samples; i++)
200  {
201  set(0, i, chan);
202  }
203  return true;
204 }
205 
206 void Sound::set(audio_sample value, size_t location, size_t channel)
207 {
208  FlexImage& img = HELPER(implementation);
209  unsigned char *addr = img.getPixelAddress(location,channel);
210  if (m_bytesPerSample ==2)
211  {
212  *(reinterpret_cast<NetUint16*>(addr)) = value;
213  return;
214  }
215  else
216  {
217  yCError(SOUND, "sound only implemented for 16 bit samples");
218  }
219 }
220 
222 {
223  return m_frequency;
224 }
225 
226 void Sound::setFrequency(int freq)
227 {
228  this->m_frequency = freq;
229 }
230 
231 bool Sound::read(ConnectionReader& connection)
232 {
233  // lousy format - fix soon!
234  FlexImage& img = HELPER(implementation);
235  Bottle bot;
236  bool ok = PortablePair<FlexImage,Bottle>::readPair(connection,img,bot);
237  m_frequency = bot.get(0).asInt32();
238  synchronize();
239  return ok;
240 }
241 
242 
243 bool Sound::write(ConnectionWriter& connection) const
244 {
245  // lousy format - fix soon!
246  FlexImage& img = HELPER(implementation);
247  Bottle bot;
248  bot.addInt32(m_frequency);
249  return PortablePair<FlexImage,Bottle>::writePair(connection,img,bot);
250 }
251 
252 unsigned char *Sound::getRawData() const
253 {
254  FlexImage& img = HELPER(implementation);
255  return img.getRawImage();
256 }
257 
258 size_t Sound::getRawDataSize() const
259 {
260  FlexImage& img = HELPER(implementation);
261  return img.getRawImageSize();
262 }
263 
264 void Sound::setSafe(audio_sample value, size_t sample, size_t channel)
265 {
266  if (isSample(sample, channel))
267  {
268  set(value, sample, channel);
269  }
270  else
271  {
272  yCError(SOUND) << "Sample out of bound:" << sample << "," << channel;
273  }
274 }
275 
276 Sound Sound::extractChannelAsSound(size_t channel_id) const
277 {
278  Sound news(this->m_bytesPerSample);
279  news.setFrequency(this->m_frequency);
280  news.resize(this->m_samples, 1);
281 
282  unsigned char* p_src = this->getRawData();
283  unsigned char* p_dst = news.getRawData();
284  size_t j = 0;
285  //pointer to the first element of the row of the matrix we need to copy
286  size_t first_sample = 0 + (this->m_samples * this->m_bytesPerSample)*channel_id;
287  //pointer to the last element of the row of the matrix we need to copy
288  size_t last_sample = first_sample + (this->m_samples * this->m_bytesPerSample);
289  for (auto i = first_sample; i < last_sample; i++)
290  {
291  p_dst[j++] = p_src[i];
292  }
293  return news;
294 }
295 
296 bool Sound::operator==(const Sound& alt) const
297 {
298  if (this->m_channels != alt.getChannels()) return false;
299  if (this->m_bytesPerSample != alt.getBytesPerSample()) return false;
300  if (this->m_frequency != alt.getFrequency()) return false;
301  if (this->m_samples != alt.getSamples()) return false;
302 
303  for (size_t ch = 0; ch < this->m_channels; ch++)
304  {
305  for (size_t s = 0; s < this->m_samples; s++)
306  {
307  if (this->getSafe(s, ch) != alt.getSafe(s, ch))
308  {
309  return false;
310  }
311  }
312  }
313 
314  return true;
315 }
316 
317 bool Sound::replaceChannel(size_t id, Sound schannel)
318 {
319  if (schannel.getChannels() != 1) return false;
320  if (this->m_samples != schannel.getSamples()) return false;
321  for (size_t s = 0; s < this->m_samples; s++)
322  {
323  this->setSafe(schannel.getSafe(s, 0), s, id);
324  }
325  return true;
326 }
327 
328 std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getChannel(size_t channel_id)
329 {
330  FlexImage& img = HELPER(implementation);
331 
332  std::vector<std::reference_wrapper<audio_sample>> vec;
333  vec.reserve(this->m_samples);
334  for (size_t t = 0; t < this->m_samples; t++)
335  {
336  unsigned char *addr = img.getPixelAddress(t, channel_id);
337  audio_sample* addr2 = reinterpret_cast<audio_sample*>(addr);
338  vec.push_back(std::ref(*addr2));
339  }
340  return vec;
341 }
342 
343 std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getInterleavedAudioRawData() const
344 {
345  FlexImage& img = HELPER(implementation);
346 
347  std::vector<std::reference_wrapper<audio_sample>> vec;
348  vec.reserve(this->m_samples*this->m_channels);
349  for (size_t t = 0; t < this->m_samples; t++)
350  {
351  for (size_t c = 0; c < this->m_channels; c++)
352  {
353  unsigned char *addr = img.getPixelAddress(t, c);
354  audio_sample* addr2 = reinterpret_cast<audio_sample*>(addr);
355  vec.push_back(std::ref(*addr2));
356  }
357  }
358  return vec;
359 }
360 
361 std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getNonInterleavedAudioRawData() const
362 {
363  FlexImage& img = HELPER(implementation);
364 
365  std::vector<std::reference_wrapper<audio_sample>> vec;
366  vec.reserve(this->m_samples*this->m_channels);
367  for (size_t c = 0; c < this->m_channels; c++)
368  {
369  for (size_t t = 0; t < this->m_samples; t++)
370  {
371  unsigned char *addr = img.getPixelAddress(t, c);
372  audio_sample* addr2 = reinterpret_cast<audio_sample*>(addr);
373  vec.push_back(std::ref(*addr2));
374  }
375  }
376  return vec;
377 }
378 
379 std::string Sound::toString() const
380 {
381  std::string s;
382  for (size_t c = 0; c < this->m_channels; c++)
383  {
384  for (size_t t = 0; t < this->m_samples; t++)
385  {
386  s += " ";
387  s += std::to_string(this->get(t, c));
388  }
389  s += '\n';
390  }
391  return s;
392 }
393 
394 bool Sound::isSample(size_t sample, size_t channel) const
395 {
396  return (sample<this->m_samples && channel<this->m_channels);
397 }
398 
400 {
401  return this->m_bytesPerSample;
402 }
403 
404 size_t Sound::getSamples() const
405 {
406  return this->m_samples;
407 }
408 
409 size_t Sound::getChannels() const
410 {
411  return this->m_channels;
412 }
413 
414 double Sound::getDuration() const
415 {
416  return (double)(this->m_samples)*(double)(1 / this->m_frequency);
417 }
LogStream.h
yarp::sig::Sound::setFrequency
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:226
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
yarp::sig::Sound::isSample
bool isSample(size_t sample, size_t channel=0) const
Check whether a sample lies within the sound.
Definition: Sound.cpp:394
yarp::sig::Sound::replaceChannel
bool replaceChannel(size_t id, Sound channel)
Replace a single channel of our current sound with a given sound constituted by a single channel The ...
Definition: Sound.cpp:317
yarp::os::Portable
This is a base class for objects that can be both read from and be written to the YARP network.
Definition: Portable.h:29
yarp::sig::Sound::getFrequency
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:221
yarp::os::PortablePair
Group a pair of objects to be sent and received together.
Definition: PortablePair.h:51
yarp::sig
Signal processing.
Definition: Image.h:25
t
float t
Definition: FfmpegWriter.cpp:74
yarp::sig::Sound::extractChannelAsSound
Sound extractChannelAsSound(size_t channel_id) const
Extract a single channel from the sound.
Definition: Sound.cpp:276
yarp::sig::Sound::write
bool write(yarp::os::ConnectionWriter &connection) const override
Write this object to a network connection.
Definition: Sound.cpp:243
yarp::sig::Sound::getSamples
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:404
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
samples
int16_t * samples
Definition: FfmpegWriter.cpp:76
yarp::sig::Image::copy
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:842
yarp::sig::Sound::getChannels
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:409
PortablePair.h
yarp::sig::Image::getRawImageSize
size_t getRawImageSize() const
Access to the internal buffer size information (this is how much memory has been allocated for the im...
Definition: Image.cpp:543
yarp::sig::Image::width
size_t width() const
Gets width of image in pixels.
Definition: Image.h:153
yarp::sig::Sound::operator+=
Sound & operator+=(const Sound &alt)
Addition assignment operator.
Definition: Sound.cpp:48
yarp::sig::Sound::Sound
Sound(size_t bytesPerSample=2)
Definition: Sound.cpp:32
yarp::sig::Sound::read
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
Definition: Sound.cpp:231
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
yarp::sig::Sound::operator==
bool operator==(const Sound &alt) const
Comparison operator.
Definition: Sound.cpp:296
yarp::sig::Sound::getNonInterleavedAudioRawData
std::vector< std::reference_wrapper< audio_sample > > getNonInterleavedAudioRawData() const
Returns a serialized version of the sound, in non-interleaved format, e.g.
Definition: Sound.cpp:361
yarp::os::ConnectionWriter
An interface for writing to a network connection.
Definition: ConnectionWriter.h:40
yarp::sig::Sound::~Sound
virtual ~Sound()
Definition: Sound.cpp:158
yarp::sig::Sound::getChannel
std::vector< std::reference_wrapper< audio_sample > > getChannel(size_t channel_id)
Definition: Sound.cpp:328
yarp::sig::FlexImage
Image class with user control of representation details.
Definition: Image.h:403
yarp::sig::Image::getPixelAddress
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition: Image.h:227
yarp::sig::Sound::getSafe
audio_sample getSafe(size_t sample, size_t channel=0) const
Definition: Sound.h:82
yarp::sig::Sound::set
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:206
yarp::sig::Image::resize
void resize(size_t imgWidth, size_t imgHeight)
Reallocate an image to be of a desired size, throwing away its current contents.
Definition: Image.cpp:466
yarp::sig::Image::height
size_t height() const
Gets height of image in pixels.
Definition: Image.h:159
yarp::os::Bottle::addInt32
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition: Bottle.cpp:143
yarp::sig::Sound::get
audio_sample get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:174
yarp::sig::Sound::setSafe
void setSafe(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:264
yarp::sig::Sound::audio_sample
short int audio_sample
Definition: Sound.h:30
yarp::sig::Sound::clearChannel
bool clearChannel(size_t channel)
set to zero all the samples of the specified channel @ param channel the channel number
Definition: Sound.cpp:196
LogComponent.h
yCAssert
#define yCAssert(component, x)
Definition: LogComponent.h:172
Image.h
yarp::os::ConnectionReader
An interface for reading from a network connection.
Definition: ConnectionReader.h:40
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
yarp::sig::Sound::getDuration
double getDuration() const
Get the duration of sound in seconds.
Definition: Sound.cpp:414
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yarp::sig::Sound::operator=
const Sound & operator=(const Sound &alt)
Assignment operator.
Definition: Sound.cpp:87
yarp::sig::Sound
Class for storing sounds.
Definition: Sound.h:28
yarp::os::NetUint16
std::uint16_t NetUint16
Definition of the NetUint16 type.
Definition: NetUint16.h:33
yarp
The main, catch-all namespace for YARP.
Definition: environment.h:18
yarp::sig::Sound::toString
std::string toString() const
Print matrix to a string.
Definition: Sound.cpp:379
yarp::sig::Sound::subSound
Sound subSound(size_t first_sample, size_t last_sample)
Returns a subpart of the sound.
Definition: Sound.cpp:105
yarp::sig::Sound::clear
void clear()
set all the samples to zero (silence)
Definition: Sound.cpp:189
yarp::sig::Sound::resize
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:167
yarp::sig::Sound::getInterleavedAudioRawData
std::vector< std::reference_wrapper< audio_sample > > getInterleavedAudioRawData() const
Returns a serialized version of the sound, in interleaved format, e.g.
Definition: Sound.cpp:343
Time.h
HELPER
#define HELPER(x)
Definition: Sound.cpp:30
yarp::sig::Sound::getBytesPerSample
size_t getBytesPerSample() const
Get the number of bytes per sample.
Definition: Sound.cpp:399
VOCAB_PIXEL_MONO16
@ VOCAB_PIXEL_MONO16
Definition: Image.h:49
Sound.h
Bottle.h
Value.h
yarp::sig::Image::getRawImage
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:534