22 #include "MASpeakerController.hpp" 24 #include "types/MAAudio.hpp" 25 #include "types/MARobotState.hpp" 26 #include "sound/MASoundDatabase.hpp" 27 #include "MABehaviorManager.hpp" 30 #include <MCTimer.hpp> 40 typedef boost::unordered_map<std::string, MA::SoundBaseSPtr> SoundDataMap;
43 typedef std::pair<std::string, int> FutureSoundDescriptor;
45 typedef boost::unordered_map<int, FutureSoundDescriptor> FutureSoundMap;
56 void CheckStaticSpeakerControllerVariables(
bool reset_if_exists)
58 if (unlikely(!PlaybackID.get()))
60 PlaybackID.reset(
new int);
62 Sounds.reset(
new SoundDataMap);
63 FutureSounds.reset(
new FutureSoundMap);
64 PreloadedSounds.reset(
new MC::StringList);
70 FutureSounds->clear();
71 PreloadedSounds->clear();
76 MASpeakerController::MASpeakerController() :
MAController(
MA::SpeakerController), BufferSize(512)
78 CheckStaticSpeakerControllerVariables(
true);
79 if (MA::Speaker.
get())
81 MC_WARNING(
"The global speaker controller is overridden.");
83 MA::Speaker.reset(
this);
87 MASpeakerController::~MASpeakerController()
89 if (MA::Speaker.
get() ==
this)
91 MA::Speaker.release();
95 for (
auto iter = Sounds->begin(); iter != Sounds->end();)
101 iter = Sounds->erase(iter);
103 if (iter == Sounds->end())
115 state.
Audio->SpeakerVolume = (int)SpeakerDevice->GetVolume();
116 state.
Audio->RemainingPlaybackTime = (int)GetRemainingPlaybackTime();
117 state.
Audio->EffectsPlayed = (int)IsOnlyEffectsPlayed();
124 return MA::DeviceList();
131 CheckStaticSpeakerControllerVariables(
false);
132 FutureSounds->insert(std::make_pair(
id, FutureSoundDescriptor(name, duration)));
138 return Playbacks.empty();
148 MA::SoundDatabase->SwitchProfile();
150 for (
unsigned int i = 0; i < PreloadedSounds->size(); ++i)
151 Preload((*PreloadedSounds)[i]);
158 return MA::SoundDatabase->GetProfileName();
168 MA::SoundDatabase->SetProfileName(profile_name);
170 for (
unsigned int i = 0; i < PreloadedSounds->size(); ++i)
171 Preload((*PreloadedSounds)[i]);
198 std::string FileName = MA::SoundDatabase->GetSoundFileName(name);
200 if (FileName.empty())
202 MC_WARNING(
"File is not found: %s", name.c_str());
205 if (!(*Sounds)[FileName])
207 MA::SoundBaseSPtr NewSoundFile(MA::SoundDatabase->GetSoundFile(FileName,
true));
209 PreloadedSounds->push_back(name);
211 if (!NewSoundFile->IsValid())
215 (*Sounds)[FileName] = NewSoundFile;
217 MC_LOG(
"Preload a sound file: %s", FileName.c_str());
225 auto Iter = std::find(PreloadedSounds->begin(), PreloadedSounds->end(), name);
227 if (Iter != PreloadedSounds->end())
229 PreloadedSounds->erase(Iter);
231 std::string FileName = MA::SoundDatabase->GetSoundFileName(name);
232 auto FileIter = Sounds->find(FileName);
235 if (FileIter != Sounds->end())
237 SoundDataPtr = FileIter->second.get();
238 Sounds->erase(FileIter);
242 for (
auto iter = Playbacks.begin(); iter != Playbacks.end(); ++iter)
244 if (iter->first.get() == SoundDataPtr)
246 Playbacks.erase(iter);
251 MC_LOG(
"Preloaded sound freed: %s", name.c_str());
257 std::string FileName = MA::SoundDatabase->GetSoundFileName(name);
259 if (FileName.empty())
261 MC_WARNING(
"Sound file is not found: %s", name.c_str());
264 if (!(*Sounds)[FileName])
266 MA::SoundBaseSPtr NewSoundFile(MA::SoundDatabase->GetSoundFile(FileName,
false));
269 if (!NewSoundFile->IsValid())
273 (*Sounds)[FileName] = NewSoundFile;
275 return Play((*Sounds)[FileName]);
287 MA::PlaybackDescriptor PlaybackDescriptor;
288 const auto Iter = FutureSounds->find(*PlaybackID);
290 PlaybackDescriptor.get<0>() = *PlaybackID;
294 if (Iter != FutureSounds->end() && Iter->second.first == sound->GetDisplayName())
296 PlaybackDescriptor.get<3>() = Iter->second.second;
298 Playbacks.insert(std::make_pair(sound, PlaybackDescriptor));
301 MC_LOG(
"Play a sound file: %s (id: %d)", sound->GetDisplayName().c_str(), *PlaybackID);
309 if (Playbacks.empty())
312 for (
auto& playback : Playbacks)
314 const MA::PlaybackDescriptor& Descriptor = playback.second;
316 if (Descriptor.get<0>() == playback_id)
325 if (Playbacks.empty())
328 for (
auto& playback : Playbacks)
330 if (playback.first.get() && playback.first->GetDisplayName() == sound_name)
339 SpeakerDevice->SetVolumeState(new_volume);
343 void MASpeakerController::MixNextBuffer(int16_t* target_buffer,
bool limit_non_cached)
346 bool NonCachedSample =
false;
347 int32_t TempBuffer[BufferSize];
350 memset(target_buffer, 0, BufferSize*
sizeof(int16_t));
351 memset(&TempBuffer[0], 0, BufferSize*
sizeof(int32_t));
353 for (
auto iter = Playbacks.begin(); iter != Playbacks.end();)
355 MA::PlaybackDescriptor& Descriptor = iter->second;
358 if (iter->first->IsCached() || !NonCachedSample)
359 iter->first->AddToBuffer(Descriptor.get<1>(), BufferSize, TempBuffer);
360 if (!iter->first->IsCached() && limit_non_cached)
361 NonCachedSample =
true;
363 Descriptor.get<1>() += BufferSize;
366 if ((iter->first->GetSize() <= Descriptor.get<1>() &&
368 (Descriptor.get<3>() <= 0 || Descriptor.get<3>() <=
371 (!iter->first->IsCached() && !NonCachedSample))
375 MC_LOG(
"Sound file ended: %s (id: %d, duration: %d)", iter->first->GetDisplayName().c_str(),
378 Playbacks.erase(iter++);
385 for (
int i = 0; i < BufferSize; ++i)
386 target_buffer[i] = (int16_t)
MCBound((int32_t)-32768, TempBuffer[i], (int32_t)32767);
390 unsigned int MASpeakerController::GetRemainingPlaybackTime()
const 392 if (Playbacks.empty())
395 unsigned int RemainingData = 0;
397 for (
auto& playback : Playbacks)
399 const MA::PlaybackDescriptor& Descriptor = playback.second;
400 int SoundSize = playback.first->GetSize();
401 int CurrentPosition = Descriptor.get<1>();
404 if (CurrentPosition < SoundSize && (
unsigned int)(SoundSize-CurrentPosition) > RemainingData)
405 RemainingData = (
unsigned int)(SoundSize-CurrentPosition);
409 return RemainingData*2 / SpeakerDevice->GetMsecSampleSize();
413 bool MASpeakerController::IsOnlyEffectsPlayed()
const 415 if (Playbacks.empty())
418 for (
auto& playback : Playbacks)
420 if (!playback.first->IsEffect())
429 return MA::DeviceGeneratorsMap();
virtual MA::DeviceList GetMotors() const override
Get the list of the motors.
bool IsFree() const
Check if any sound is being played back.
std::string GetSoundProfileName() const
Get sound profile name.
int Play(const std::string &name)
Play a sound by name.
void SetVolume(const MA::VolumeType new_volume)
Set a new volume level.
void FreePreloadedSound(const std::string &name)
Free a preloaded sound.
void SwitchSoundProfile()
Switch the sound profile.
#define MC_WARNING(...)
Warning macro.
Base class for the controllers.
const T & MCBound(const T &min, const T &value, const T &max)
Check a value bound according to a range.
static bool IsVerbose()
Get the verbosity of the controller domain.
virtual void UpdateRobotState(MARobotState &state) override
Update the robot state.
virtual bool IsCached() const =0
Check if the sound data is cached.
virtual void LoadVolumeControl()
Load the volume control.
virtual MA::DeviceGeneratorsMap GetSkitTransitionGenerators(MA::SkitBaseSPtr skit) override
Get skit transition generators.
void SetSoundProfileName(const std::string &profile_name)
Set sound profile name.
bool IsPlayed(const int playback_id) const
Check if a playback ID is active.
static void RegisterFutureSound(const int id, const std::string &name, const int duration)
Register a sound for future playback.
bool Preload(const std::string &name)
Preload a sound.
virtual void SaveVolumeControl()
Save the volume control.
static int64_t GetElapsedSystemTime(bool relative_time=true)
Get the system time.
virtual void LoadSoundProfile()
Load the sound profile.
boost::scoped_ptr< MAAudio > Audio
Audio input/output.
A wrapper class to cover boost::thread_specific_ptr/folly::ThreadLocal API on certain targets...
#define MC_LOG(...)
Debug macro.
virtual void SaveSoundProfile()
Save the sound profile.