Urho3D/Source/Samples/14_SoundEffects/SoundEffects.cpp
2021-07-17 16:43:46 +00:00

229 lines
8.1 KiB
C++

//
// Copyright (c) 2008-2021 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#include <Urho3D/Audio/Audio.h>
#include <Urho3D/Audio/AudioEvents.h>
#include <Urho3D/Audio/Sound.h>
#include <Urho3D/Audio/SoundSource.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/UI/Button.h>
#include <Urho3D/UI/Font.h>
#include <Urho3D/UI/Slider.h>
#include <Urho3D/UI/Text.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/UI/UIEvents.h>
#include "SoundEffects.h"
#include <Urho3D/DebugNew.h>
// Custom variable identifier for storing sound effect name within the UI element
static const StringHash VAR_SOUNDRESOURCE("SoundResource");
static const unsigned NUM_SOUNDS = 3;
static const char* soundNames[] = {
"Fist",
"Explosion",
"Power-up"
};
static const char* soundResourceNames[] = {
"Sounds/PlayerFistHit.wav",
"Sounds/BigExplosion.wav",
"Sounds/Powerup.wav"
};
URHO3D_DEFINE_APPLICATION_MAIN(SoundEffects)
SoundEffects::SoundEffects(Context* context) :
Sample(context),
musicSource_(nullptr)
{
}
void SoundEffects::Setup()
{
// Modify engine startup parameters
Sample::Setup();
engineParameters_[EP_SOUND] = true;
}
void SoundEffects::Start()
{
// Execute base class startup
Sample::Start();
// Create a scene which will not be actually rendered, but is used to hold SoundSource components while they play sounds
scene_ = new Scene(context_);
// Create music sound source
musicSource_ = scene_->CreateComponent<SoundSource>();
// Set the sound type to music so that master volume control works correctly
musicSource_->SetSoundType(SOUND_MUSIC);
// Enable OS cursor
GetSubsystem<Input>()->SetMouseVisible(true);
// Create the user interface
CreateUI();
// Set the mouse mode to use in the sample
Sample::InitMouseMode(MM_FREE);
}
void SoundEffects::CreateUI()
{
UIElement* root = GetSubsystem<UI>()->GetRoot();
auto* cache = GetSubsystem<ResourceCache>();
auto* uiStyle = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
// Set style to the UI root so that elements will inherit it
root->SetDefaultStyle(uiStyle);
// Create buttons for playing back sounds
for (unsigned i = 0; i < NUM_SOUNDS; ++i)
{
Button* button = CreateButton(i * 140 + 20, 20, 120, 40, soundNames[i]);
// Store the sound effect resource name as a custom variable into the button
button->SetVar(VAR_SOUNDRESOURCE, soundResourceNames[i]);
SubscribeToEvent(button, E_PRESSED, URHO3D_HANDLER(SoundEffects, HandlePlaySound));
}
// Create buttons for playing/stopping music
Button* button = CreateButton(20, 80, 120, 40, "Play Music");
SubscribeToEvent(button, E_RELEASED, URHO3D_HANDLER(SoundEffects, HandlePlayMusic));
button = CreateButton(160, 80, 120, 40, "Stop Music");
SubscribeToEvent(button, E_RELEASED, URHO3D_HANDLER(SoundEffects, HandleStopMusic));
auto* audio = GetSubsystem<Audio>();
// Create sliders for controlling sound and music master volume
Slider* slider = CreateSlider(20, 140, 200, 20, "Sound Volume");
slider->SetValue(audio->GetMasterGain(SOUND_EFFECT));
SubscribeToEvent(slider, E_SLIDERCHANGED, URHO3D_HANDLER(SoundEffects, HandleSoundVolume));
slider = CreateSlider(20, 200, 200, 20, "Music Volume");
slider->SetValue(audio->GetMasterGain(SOUND_MUSIC));
SubscribeToEvent(slider, E_SLIDERCHANGED, URHO3D_HANDLER(SoundEffects, HandleMusicVolume));
}
Button* SoundEffects::CreateButton(int x, int y, int xSize, int ySize, const String& text)
{
UIElement* root = GetSubsystem<UI>()->GetRoot();
auto* cache = GetSubsystem<ResourceCache>();
auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
// Create the button and center the text onto it
auto* button = root->CreateChild<Button>();
button->SetStyleAuto();
button->SetPosition(x, y);
button->SetSize(xSize, ySize);
auto* buttonText = button->CreateChild<Text>();
buttonText->SetAlignment(HA_CENTER, VA_CENTER);
buttonText->SetFont(font, 12);
buttonText->SetText(text);
return button;
}
Slider* SoundEffects::CreateSlider(int x, int y, int xSize, int ySize, const String& text)
{
UIElement* root = GetSubsystem<UI>()->GetRoot();
auto* cache = GetSubsystem<ResourceCache>();
auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
// Create text and slider below it
auto* sliderText = root->CreateChild<Text>();
sliderText->SetPosition(x, y);
sliderText->SetFont(font, 12);
sliderText->SetText(text);
auto* slider = root->CreateChild<Slider>();
slider->SetStyleAuto();
slider->SetPosition(x, y + 20);
slider->SetSize(xSize, ySize);
// Use 0-1 range for controlling sound/music master volume
slider->SetRange(1.0f);
return slider;
}
void SoundEffects::HandlePlaySound(StringHash eventType, VariantMap& eventData)
{
auto* button = static_cast<Button*>(GetEventSender());
const String& soundResourceName = button->GetVar(VAR_SOUNDRESOURCE).GetString();
// Get the sound resource
auto* cache = GetSubsystem<ResourceCache>();
auto* sound = cache->GetResource<Sound>(soundResourceName);
if (sound)
{
// Create a SoundSource component for playing the sound. The SoundSource component plays
// non-positional audio, so its 3D position in the scene does not matter. For positional sounds the
// SoundSource3D component would be used instead
auto* soundSource = scene_->CreateComponent<SoundSource>();
// Component will automatically remove itself when the sound finished playing
soundSource->SetAutoRemoveMode(REMOVE_COMPONENT);
soundSource->Play(sound);
// In case we also play music, set the sound volume below maximum so that we don't clip the output
soundSource->SetGain(0.75f);
}
}
void SoundEffects::HandlePlayMusic(StringHash eventType, VariantMap& eventData)
{
auto* cache = GetSubsystem<ResourceCache>();
auto* music = cache->GetResource<Sound>("Music/Ninja Gods.ogg");
// Set the song to loop
music->SetLooped(true);
musicSource_->Play(music);
}
void SoundEffects::HandleStopMusic(StringHash eventType, VariantMap& eventData)
{
// Remove the music player node from the scene
musicSource_->Stop();
}
void SoundEffects::HandleSoundVolume(StringHash eventType, VariantMap& eventData)
{
using namespace SliderChanged;
float newVolume = eventData[P_VALUE].GetFloat();
GetSubsystem<Audio>()->SetMasterGain(SOUND_EFFECT, newVolume);
}
void SoundEffects::HandleMusicVolume(StringHash eventType, VariantMap& eventData)
{
using namespace SliderChanged;
float newVolume = eventData[P_VALUE].GetFloat();
GetSubsystem<Audio>()->SetMasterGain(SOUND_MUSIC, newVolume);
}