YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Sound.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <yarp/sig/Sound.h>
8#include <yarp/os/Bottle.h>
11#include <yarp/os/LogStream.h>
12#include <yarp/os/Time.h>
13#include <yarp/os/Value.h>
14#include <functional>
15
18
19#include <cstring>
20#include <cstdio>
21#include <vector>
22
23using namespace yarp::sig;
24using namespace yarp::os;
25
26namespace {
27YARP_LOG_COMPONENT(SOUND, "yarp.sig.Sound")
28}
29
30#ifndef NetUint8
31#define NetUint8 unsigned char
32#endif
33
34#ifndef NetUint16
35#define NetUint16 short unsigned int
36#endif
37
58
59Sound::Sound(size_t bytesPerSample)
60{
61 init(bytesPerSample);
62 m_frequency = 0;
63
64}
65
67{
68 init(alt.m_bytesPerSample);
69 m_frequency = alt.m_frequency;
70 m_channels = alt.m_channels;
71 m_samples = alt.m_samples;
72 if (m_bytesPerSample == 1)
73 {
74 *(std::vector<NetUint8>*)(implementation) = *(std::vector<NetUint8>*)(alt.implementation);
75 }
76 if (m_bytesPerSample == 2)
77 {
78 *(std::vector<NetUint16>*)(implementation) = *(std::vector<NetUint16>*)(alt.implementation);
79 }
80 else
81 {
82 yCError(SOUND, "sound only implemented for 8-16 bit samples");
83 yCAssert(SOUND,false); // that's all that's implemented right now
84 }
85}
86
87void Sound::overwrite(const Sound& alt, size_t offset, size_t len)
88{
89 if (alt.m_channels != m_channels)
90 {
91 yCError(SOUND, "unable to concatenate sounds with different number of channels!");
92 return;
93 }
94 if (alt.m_frequency != m_frequency)
95 {
96 yCError(SOUND, "unable to concatenate sounds with different sample rate!");
97 return;
98 }
99
100 size_t current_size = (*this).getSamples();
101 size_t alt_size = alt.getSamples();
102 if (len == 0) len = alt_size;
103 if ( offset + len > current_size)
104 {
105 len = current_size - offset;
106 }
107
108 for (size_t ch = 0; ch < m_channels; ch++)
109 {
110 size_t pdst = ch * this->getBytesPerSample() * this->m_samples + offset* this->getBytesPerSample();
111 unsigned char* dst = &this->getRawData()[pdst];
112 size_t psrc = ch * this->getBytesPerSample() * alt.m_samples;
113 unsigned char* src = &alt.getRawData()[psrc];
114 memcpy((void*) dst, (void*) src, len * this->m_bytesPerSample);
115 }
116}
117
119{
120 if (alt.m_channels!= m_channels)
121 {
122 yCError(SOUND, "unable to concatenate sounds with different number of channels!");
123 return *this;
124 }
125 if (alt.m_frequency!= m_frequency)
126 {
127 yCError(SOUND, "unable to concatenate sounds with different sample rate!");
128 return *this;
129 }
130
131 Sound orig= *this;
132 this->resize(this->m_samples+alt.m_samples,m_channels);
133
134 unsigned char* orig_start = orig.getRawData();
135 unsigned char* alt_start = alt.getRawData();
136 unsigned char* pout = this->getRawData();
137 size_t orig_singlechannel_size = orig.getBytesPerSample() * orig.m_samples;
138 size_t alt_singlechannel_size = alt.getBytesPerSample() * alt.m_samples;
139
140 for (size_t ch=0; ch<m_channels; ch++)
141 {
142 size_t out1 = ch* this->getBytesPerSample() * this->m_samples;
143 size_t out2 = ch* this->getBytesPerSample() * this->m_samples + this->getBytesPerSample() * orig.m_samples;
144
145 size_t orig_pointer = ch * orig.getBytesPerSample() * orig.m_samples;
146 size_t alt_pointer = ch * orig.getBytesPerSample() * alt.m_samples;
147
149 memcpy((void *) &pout[out2], (void *) (alt_start + alt_pointer), alt_singlechannel_size);
150 }
151
152 return *this;
153}
154
156{
157 init(alt.m_bytesPerSample);
158 m_frequency = alt.m_frequency;
159 m_channels = alt.m_channels;
160 m_samples = alt.m_samples;
161
162 if (m_bytesPerSample == 1)
163 {
164 *(std::vector<NetUint8>*)(implementation) = *(std::vector<NetUint8>*)(alt.implementation);
165 return *this;
166 }
167 else if (m_bytesPerSample == 2)
168 {
169 *(std::vector<NetUint16>*)(implementation) = *(std::vector<NetUint16>*)(alt.implementation);
170 return *this;
171 }
172
173 yCError(SOUND, "sound only implemented for 8-16 bit samples");
174 yCAssert(SOUND, false); // that's all that's implemented right now
175 return *this;
176}
177
179{
180 if (last_sample > this->m_samples) {
181 last_sample = m_samples;
182 }
183 if (first_sample > this->m_samples) {
184 first_sample = m_samples;
185 }
188 }
189
190 Sound s;
191
192 s.resize(last_sample-first_sample, this->m_channels);
193 s.setFrequency(this->m_frequency);
194
195 /*
196 //faster implementation but currently not working
197 unsigned char* p1 = this->getRawData();
198 unsigned char* p2 = s.getRawData();
199 int j=0;
200 for (int i=first_sample; i<last_sample*2; i++)
201 {
202 p2[j++]=p1[i];
203 }
204 */
205
206 //safe implementation
207 size_t j=0;
208 for (size_t i=first_sample; i<last_sample; i++)
209 {
210 for (size_t c = 0; c < this->m_channels; c++) {
211 s.set(this->get(i, c), j, c);
212 }
213 j++;
214 }
215 return s;
216}
217
218void Sound::init(size_t bytesPerSample)
219{
220 delete_implementation();
221 if (bytesPerSample == 1)
222 {
223 implementation = new std::vector<NetUint8>;
224 }
225 else if (bytesPerSample==2)
226 {
227 implementation = new std::vector<NetUint16>;
228 }
229 else
230 {
231 yCError(SOUND, "sound only implemented for 8-16 bit samples");
232 yCAssert(SOUND, false); // that's all that's implemented right now
233 }
234
235 yCAssert(SOUND, implementation!=nullptr);
236 m_samples = 0;
237 m_channels = 1;
238 this->m_bytesPerSample = bytesPerSample;
239}
240
241void Sound::delete_implementation()
242{
243 if (implementation != nullptr)
244 {
245 if (m_bytesPerSample == 1)
246 {
247 std::vector<NetUint8>*p = (std::vector<NetUint8>*)(implementation);
248 delete p;
249 implementation = nullptr;
250 }
251 else if (m_bytesPerSample == 2)
252 {
253 std::vector<NetUint16>* p = (std::vector<NetUint16>*)(implementation);
254 delete p;
255 implementation = nullptr;
256 }
257 else
258 {
259 yCError(SOUND, "sound only implemented for 8-16 bit samples");
260 yCAssert(SOUND, false); // that's all that's implemented right now
261 }
262 }
263}
264
266{
267 delete_implementation();
268}
269
270void Sound::resize(size_t samples, size_t channels)
271{
272 delete_implementation();
273 if (m_bytesPerSample == 1)
274 {
275 implementation = new std::vector<NetUint8>;
276 ((std::vector<NetUint8>*)(implementation))->resize(samples * channels);
277 m_channels = channels;
278 m_samples = samples;
279 }
280 else if (m_bytesPerSample == 2)
281 {
282 implementation = new std::vector<NetUint16>;
283 ((std::vector<NetUint16>*)(implementation))->resize(samples*channels);
284 m_channels=channels;
285 m_samples=samples;
286 }
287 else
288 {
289 yCError(SOUND, "sound only implemented for 8-16 bit samples");
290 yCAssert(SOUND, false); // that's all that's implemented right now
291 }
292}
293
295{
296 if (m_bytesPerSample == 1)
297 {
298 auto* pp = ((std::vector<NetUint8>*)(implementation));
299 NetUint8* addr = pp->data() + location + channel * this->m_samples;
300 return *(reinterpret_cast<NetUint8*>(addr));
301 }
302 else if (m_bytesPerSample == 2)
303 {
304 auto* pp = ((std::vector<NetUint16>*)(implementation));
305 NetUint16* addr = pp->data() + location + channel * this->m_samples;
306 return *(reinterpret_cast<NetUint16*>(addr));
307 }
308 else
309 {
310 yCError(SOUND, "sound only implemented for 8-16 bit samples");
311 }
312 return 0;
313}
314
316{
317 size_t size = this->getRawDataSize();
318 unsigned char* p = this->getRawData();
319 memset(p,0,size);
320}
321
323{
324 if (chan > this->m_channels) {
325 return false;
326 }
327 for (size_t i = 0; i < this->m_samples; i++)
328 {
329 set(0, i, chan);
330 }
331 return true;
332}
333
334void Sound::set(audio_sample value, size_t location, size_t channel)
335{
336 if (m_bytesPerSample == 1)
337 {
338 auto* pp = ((std::vector<NetUint8>*)(implementation));
339 NetUint8* addr = pp->data() + location +channel * this->m_samples;
340 *(reinterpret_cast<NetUint8*>(addr)) = value;
341 return;
342 }
343 else if (m_bytesPerSample == 2)
344 {
345 auto* pp = ((std::vector<NetUint16>*)(implementation));
346 NetUint16* addr = pp->data() + location + channel * this->m_samples;
347 *(reinterpret_cast<NetUint16*>(addr)) = value;
348 return;
349 }
350 else
351 {
352 yCError(SOUND, "sound only implemented for 8-16 bit samples");
353 }
354}
355
357{
358 return m_frequency;
359}
360
362{
363 this->m_frequency = freq;
364}
365
367{
368 connection.convertTextMode();
369 SoundHeader header;
370 bool ok = connection.expectBlock((char*)&header, sizeof(header));
371 if (!ok) {
372 return false;
373 }
374
375 init(header.bytesPerSample);
376 m_frequency = header.frequency;
377 m_channels = header.channelsSize;
378 m_samples = header.samplesSize;
379 size_t data_size = header.listLen;
380
381 if (data_size != m_channels * m_samples)
382 {
383 return false;
384 }
385
386 auto* pp = ((std::vector<NetUint16>*)(implementation));
387 pp->resize(data_size);
388 for (size_t l = 0; l < data_size; l++)
389 {
390 pp->at(l) = connection.expectInt16();
391 }
392 return true;
393}
394
395
397{
398 SoundHeader header;
400 header.outerListLen = 5;
402 header.samplesSize = m_samples;
404 header.bytesPerSample = m_bytesPerSample;
406 header.channelsSize = m_channels;
408 header.frequency = m_frequency;
409
410 auto* pp = ((std::vector<NetUint16>*)(implementation));
411 size_t siz = pp->size();
413 header.listLen = siz; //this must be equal to m_samples*m_channels
414 //BOTTLE_TAG_LIST is special and must be followed by its size.
415 connection.appendBlock((char*)&header, sizeof(header));
416 for (size_t l = 0; l < pp->size(); l++) {
417 connection.appendInt16(pp->at(l));
418 }
419
420 connection.convertTextMode();
421 return true;
422}
423
424unsigned char *Sound::getRawData() const
425{
426 if (m_bytesPerSample == 1)
427 {
428 auto* pp = ((std::vector<NetUint8>*)(implementation));
429 NetUint8* addr = pp->data();
430 return addr;
431 }
432 else if (m_bytesPerSample == 2)
433 {
434 auto* pp = ((std::vector<NetUint16>*)(implementation));
435 NetUint16* addr = pp->data();
436 return (unsigned char*)(addr);
437 }
438
439 yCError(SOUND, "sound only implemented for 8-16 bit samples");
440 yCAssert(SOUND, false); // that's all that's implemented right now
441}
442
443size_t Sound::getRawDataSize() const
444{
445 return this->m_bytesPerSample*this->m_channels*this->m_samples;
446}
447
448void Sound::setSafe(audio_sample value, size_t sample, size_t channel)
449{
450 if (isSample(sample, channel))
451 {
452 set(value, sample, channel);
453 }
454 else
455 {
456 yCError(SOUND) << "Sample out of bound:" << sample << "," << channel;
457 }
458}
459
461{
462 Sound news(this->m_bytesPerSample);
463 news.setFrequency(this->m_frequency);
464 news.resize(this->m_samples, 1);
465
466 unsigned char* p_src = this->getRawData();
467 unsigned char* p_dst = news.getRawData();
468 size_t j = 0;
469 //pointer to the first element of the row of the matrix we need to copy
470 size_t first_sample = 0 + (this->m_samples * this->m_bytesPerSample)*channel_id;
471 //pointer to the last element of the row of the matrix we need to copy
472 size_t last_sample = first_sample + (this->m_samples * this->m_bytesPerSample);
473 for (auto i = first_sample; i < last_sample; i++)
474 {
475 p_dst[j++] = p_src[i];
476 }
477 return news;
478}
479
480bool Sound::operator==(const Sound& alt) const
481{
482 if (this->m_channels != alt.getChannels()) {
483 return false;
484 }
485 if (this->m_bytesPerSample != alt.getBytesPerSample()) {
486 return false;
487 }
488 if (this->m_frequency != alt.getFrequency()) {
489 return false;
490 }
491 if (this->m_samples != alt.getSamples()) {
492 return false;
493 }
494
495 for (size_t ch = 0; ch < this->m_channels; ch++)
496 {
497 for (size_t s = 0; s < this->m_samples; s++)
498 {
499 if (this->getSafe(s, ch) != alt.getSafe(s, ch))
500 {
501 return false;
502 }
503 }
504 }
505
506 return true;
507}
508
510{
511 if (schannel.getChannels() != 1) {
512 return false;
513 }
514 if (this->m_samples != schannel.getSamples()) {
515 return false;
516 }
517 for (size_t s = 0; s < this->m_samples; s++)
518 {
519 this->setSafe(schannel.getSafe(s, 0), s, id);
520 }
521 return true;
522}
523
524std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getChannel(size_t channel_id)
525{
526 auto* pp = ((std::vector<NetUint16>*)(implementation))->data() + channel_id*m_samples;
527
528 std::vector<std::reference_wrapper<audio_sample>> vec;
529 vec.reserve(this->m_samples);
530 for (size_t t = 0; t < this->m_samples; t++)
531 {
532 unsigned char *addr = (unsigned char* )(pp);
533 audio_sample* addr2 = reinterpret_cast<audio_sample*>(addr);
534 vec.push_back(std::ref(*addr2));
535 }
536 return vec;
537}
538
539std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getInterleavedAudioRawData() const
540{
541 auto* pp = ((std::vector<NetUint16>*)(implementation))->data();
542
543 std::vector<std::reference_wrapper<audio_sample>> vec;
544 vec.reserve(this->m_samples*this->m_channels);
545 for (size_t t = 0; t < this->m_samples; t++)
546 {
547 for (size_t c = 0; c < this->m_channels; c++)
548 {
549 audio_sample* addr = (audio_sample*)(pp) + t + c*m_samples;
550 vec.push_back(std::ref(*addr));
551 }
552 }
553 return vec;
554}
555
556std::vector<std::reference_wrapper<Sound::audio_sample>> Sound::getNonInterleavedAudioRawData() const
557{
558 auto* pp = ((std::vector<NetUint16>*)(implementation))->data();
559
560 std::vector<std::reference_wrapper<audio_sample>> vec;
561 vec.reserve(this->m_samples*this->m_channels);
562 for (size_t c = 0; c < this->m_channels; c++)
563 {
564 for (size_t t = 0; t < this->m_samples; t++)
565 {
566 audio_sample* addr = (audio_sample*)(pp)+ t + c * m_samples;
567 vec.push_back(std::ref(*addr));
568 }
569 }
570 return vec;
571}
572
573std::string Sound::toString() const
574{
575 std::string s;
576 for (size_t c = 0; c < this->m_channels; c++)
577 {
578 for (size_t t = 0; t < this->m_samples; t++)
579 {
580 s += " ";
581 s += std::to_string(this->get(t, c));
582 }
583 s += '\n';
584 }
585 return s;
586}
587
588bool Sound::isSample(size_t sample, size_t channel) const
589{
590 return (sample<this->m_samples && channel<this->m_channels);
591}
592
594{
595 return this->m_bytesPerSample;
596}
597
598size_t Sound::getSamples() const
599{
600 return this->m_samples;
601}
602
603size_t Sound::getChannels() const
604{
605 return this->m_channels;
606}
607
608double Sound::getDuration() const
609{
610 return (double)(this->m_samples)*(double)(1 / this->m_frequency);
611}
612
614{
615 size_t maxsampleid = 0;
618 double gain = 1 / (maxsamplevalue / 32767.0);
620}
621
623{
624 size_t maxsampleid = 0;
625 size_t maxchannelid = 0;
628 double gain = 1 / (maxsamplevalue/32767.0);
629 amplify(gain);
630}
631
632void Sound::amplifyChannel(size_t channel, double gain)
633{
634 unsigned char* pc = this->getRawData();
635 audio_sample* p = reinterpret_cast<audio_sample*>(pc);
636 p+= this->m_samples * channel;
637
638 for (size_t t = 0; t < this->m_samples; t++, p++)
639 {
640 double amplified_value = (*p) * gain;
641 *p = (int)(amplified_value); //should i limit this range
642 }
643}
644
645void Sound::amplify(double gain)
646{
647 for (size_t c = 0; c < this->m_channels; c++)
648 {
649 amplifyChannel(c,gain);
650 }
651}
652
654{
655 sampleId = 0;
656 sampleValue = 0;
657 unsigned char* pc = this->getRawData();
658 audio_sample* p = reinterpret_cast<audio_sample*>(pc);
659 p += this->m_samples * channelId;
660
661 for (size_t t = 0; t < this->m_samples; t++, p++)
662 {
663 if (*p > sampleValue)
664 {
665 sampleValue = (*p);
666 sampleId= t;
667 }
668 }
669}
670
#define BOTTLE_TAG_INT16
Definition Bottle.h:20
#define BOTTLE_TAG_INT32
Definition Bottle.h:21
#define BOTTLE_TAG_LIST
Definition Bottle.h:28
int16_t * samples
float t
yarp::os::NetInt32 listTag
Definition Sound.cpp:52
yarp::os::NetInt32 frequency
Definition Sound.cpp:51
yarp::os::NetInt32 samplesSizeTag
Definition Sound.cpp:44
yarp::os::NetInt32 frequencyTag
Definition Sound.cpp:50
yarp::os::NetInt32 bytesPerSample
Definition Sound.cpp:49
SoundHeader()=default
yarp::os::NetInt32 listLen
Definition Sound.cpp:53
yarp::os::NetInt32 outerListTag
Definition Sound.cpp:42
yarp::os::NetInt32 samplesSize
Definition Sound.cpp:45
yarp::os::NetInt32 channelsSizeTag
Definition Sound.cpp:46
yarp::os::NetInt32 channelsSize
Definition Sound.cpp:47
yarp::os::NetInt32 outerListLen
Definition Sound.cpp:43
yarp::os::NetInt32 bytesPerSampleTag
Definition Sound.cpp:48
A mini-server for performing network communication in the background.
An interface for reading from a network connection.
An interface for writing to a network connection.
This is a base class for objects that can be both read from and be written to the YARP network.
Definition Portable.h:25
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition Sound.h:25
void setSafe(audio_sample value, size_t sample, size_t channel=0)
Definition Sound.cpp:448
Sound extractChannelAsSound(size_t channel_id) const
Extract a single channel from the sound.
Definition Sound.cpp:460
virtual ~Sound()
Definition Sound.cpp:265
bool isSample(size_t sample, size_t channel=0) const
Check whether a sample lies within the sound.
Definition Sound.cpp:588
bool clearChannel(size_t channel)
set to zero all the samples of the specified channel @ param channel the channel number
Definition Sound.cpp:322
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition Sound.cpp:361
Sound subSound(size_t first_sample, size_t last_sample)
Returns a subpart of the sound.
Definition Sound.cpp:178
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:556
const Sound & operator=(const Sound &alt)
Assignment operator.
Definition Sound.cpp:155
void amplifyChannel(size_t channel, double gain)
Amplify a specific channel of the sound.
Definition Sound.cpp:632
size_t getBytesPerSample() const
Get the number of bytes per sample.
Definition Sound.cpp:593
std::vector< std::reference_wrapper< audio_sample > > getInterleavedAudioRawData() const
Returns a serialized version of the sound, in interleaved format, e.g.
Definition Sound.cpp:539
double getDuration() const
Get the duration of sound in seconds.
Definition Sound.cpp:608
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
Definition Sound.cpp:366
size_t getChannels() const
Get the number of channels of the sound.
Definition Sound.cpp:603
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:509
void normalize()
Normalize a sound (the peak is searched among all channels)
Definition Sound.cpp:622
bool write(yarp::os::ConnectionWriter &connection) const override
Write this object to a network connection.
Definition Sound.cpp:396
void amplify(double gain)
amplify a sound
Definition Sound.cpp:645
void clear()
set all the samples to zero (silence)
Definition Sound.cpp:315
Sound(size_t bytesPerSample=2)
Definition Sound.cpp:59
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition Sound.cpp:270
void normalizeChannel(size_t channel)
Normalize a specific channel of the sound.
Definition Sound.cpp:613
void findPeak(size_t &channelId, size_t &sampleId, audio_sample &sampleValue) const
find the peak in a sound
Definition Sound.cpp:671
int getFrequency() const
Get the frequency of the sound (i.e.
Definition Sound.cpp:356
std::string toString() const
Print matrix to a string.
Definition Sound.cpp:573
void overwrite(const Sound &alt, size_t offset=0, size_t len=0)
It overwrites the sound with another sound, starting from a specified offset.
Definition Sound.cpp:87
audio_sample get(size_t sample, size_t channel=0) const
Definition Sound.cpp:294
std::vector< std::reference_wrapper< audio_sample > > getChannel(size_t channel_id)
Definition Sound.cpp:524
Sound & operator+=(const Sound &alt)
Addition assignment operator.
Definition Sound.cpp:118
bool operator==(const Sound &alt) const
Comparison operator.
Definition Sound.cpp:480
void set(audio_sample value, size_t sample, size_t channel=0)
Definition Sound.cpp:334
size_t getSamples() const
Get the number of samples contained in the sound.
Definition Sound.cpp:598
audio_sample getSafe(size_t sample, size_t channel=0) const
Definition Sound.h:88
void findPeakInChannel(size_t channelId, size_t &sampleId, audio_sample &sampleValue) const
find the peak in a specific channel of the sound
Definition Sound.cpp:653
#define yCError(component,...)
#define yCAssert(component, x)
#define YARP_LOG_COMPONENT(name,...)
An interface to the operating system, including Port based communication.
std::uint16_t NetUint16
Definition of the NetUint16 type.
Definition NetUint16.h:29
std::int32_t NetInt32
Definition of the NetInt32 type.
Definition NetInt32.h:29
std::uint8_t NetUint8
Definition of the NetUint8 type.
Definition NetUint8.h:14
The main, catch-all namespace for YARP.
Definition dirs.h:16
#define YARP_END_PACK
Ends 1 byte packing for structs/classes.
Definition system.h:193
#define YARP_BEGIN_PACK
Starts 1 byte packing for structs/classes.
Definition system.h:192