1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include <Urho3D/Audio/Audio.h>
24 #include <Urho3D/Audio/AudioEvents.h>
25 #include <Urho3D/Audio/Sound.h>
26 #include <Urho3D/Audio/SoundSource.h>
27 #include <Urho3D/Engine/Engine.h>
28 #include <Urho3D/Input/Input.h>
29 #include <Urho3D/IO/Log.h>
30 #include <Urho3D/Resource/ResourceCache.h>
31 #include <Urho3D/Scene/Scene.h>
32 #include <Urho3D/UI/Button.h>
33 #include <Urho3D/UI/Font.h>
34 #include <Urho3D/UI/Slider.h>
35 #include <Urho3D/UI/Text.h>
36 #include <Urho3D/UI/UI.h>
37 #include <Urho3D/UI/UIEvents.h>
38 
39 #include "SoundEffects.h"
40 
41 #include <Urho3D/DebugNew.h>
42 
43 // Custom variable identifier for storing sound effect name within the UI element
44 static const StringHash VAR_SOUNDRESOURCE("SoundResource");
45 static const unsigned NUM_SOUNDS = 3;
46 
47 static String soundNames[] = {
48     "Fist",
49     "Explosion",
50     "Power-up"
51 };
52 
53 static String soundResourceNames[] = {
54     "Sounds/PlayerFistHit.wav",
55     "Sounds/BigExplosion.wav",
56     "Sounds/Powerup.wav"
57 };
58 
URHO3D_DEFINE_APPLICATION_MAIN(SoundEffects)59 URHO3D_DEFINE_APPLICATION_MAIN(SoundEffects)
60 
61 SoundEffects::SoundEffects(Context* context) :
62     Sample(context),
63     musicSource_(0)
64 {
65 }
66 
Setup()67 void SoundEffects::Setup()
68 {
69     // Modify engine startup parameters
70     Sample::Setup();
71     engineParameters_[EP_SOUND] = true;
72 }
73 
Start()74 void SoundEffects::Start()
75 {
76     // Execute base class startup
77     Sample::Start();
78 
79     // Create a scene which will not be actually rendered, but is used to hold SoundSource components while they play sounds
80     scene_ = new Scene(context_);
81 
82     // Create music sound source
83     musicSource_ = scene_->CreateComponent<SoundSource>();
84     // Set the sound type to music so that master volume control works correctly
85     musicSource_->SetSoundType(SOUND_MUSIC);
86 
87     // Enable OS cursor
88     GetSubsystem<Input>()->SetMouseVisible(true);
89 
90     // Create the user interface
91     CreateUI();
92 
93     // Set the mouse mode to use in the sample
94     Sample::InitMouseMode(MM_FREE);
95 }
96 
CreateUI()97 void SoundEffects::CreateUI()
98 {
99     UIElement* root = GetSubsystem<UI>()->GetRoot();
100     ResourceCache* cache = GetSubsystem<ResourceCache>();
101     XMLFile* uiStyle = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
102     // Set style to the UI root so that elements will inherit it
103     root->SetDefaultStyle(uiStyle);
104 
105     // Create buttons for playing back sounds
106     for (unsigned i = 0; i < NUM_SOUNDS; ++i)
107     {
108         Button* button = CreateButton(i * 140 + 20, 20, 120, 40, soundNames[i]);
109         // Store the sound effect resource name as a custom variable into the button
110         button->SetVar(VAR_SOUNDRESOURCE, soundResourceNames[i]);
111         SubscribeToEvent(button, E_PRESSED, URHO3D_HANDLER(SoundEffects, HandlePlaySound));
112     }
113 
114     // Create buttons for playing/stopping music
115     Button* button = CreateButton(20, 80, 120, 40, "Play Music");
116     SubscribeToEvent(button, E_RELEASED, URHO3D_HANDLER(SoundEffects, HandlePlayMusic));
117 
118     button = CreateButton(160, 80, 120, 40, "Stop Music");
119     SubscribeToEvent(button, E_RELEASED, URHO3D_HANDLER(SoundEffects, HandleStopMusic));
120 
121     Audio* audio = GetSubsystem<Audio>();
122 
123     // Create sliders for controlling sound and music master volume
124     Slider* slider = CreateSlider(20, 140, 200, 20, "Sound Volume");
125     slider->SetValue(audio->GetMasterGain(SOUND_EFFECT));
126     SubscribeToEvent(slider, E_SLIDERCHANGED, URHO3D_HANDLER(SoundEffects, HandleSoundVolume));
127 
128     slider = CreateSlider(20, 200, 200, 20, "Music Volume");
129     slider->SetValue(audio->GetMasterGain(SOUND_MUSIC));
130     SubscribeToEvent(slider, E_SLIDERCHANGED, URHO3D_HANDLER(SoundEffects, HandleMusicVolume));
131 }
132 
CreateButton(int x,int y,int xSize,int ySize,const String & text)133 Button* SoundEffects::CreateButton(int x, int y, int xSize, int ySize, const String& text)
134 {
135     UIElement* root = GetSubsystem<UI>()->GetRoot();
136     ResourceCache* cache = GetSubsystem<ResourceCache>();
137     Font* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
138 
139     // Create the button and center the text onto it
140     Button* button = root->CreateChild<Button>();
141     button->SetStyleAuto();
142     button->SetPosition(x, y);
143     button->SetSize(xSize, ySize);
144 
145     Text* buttonText = button->CreateChild<Text>();
146     buttonText->SetAlignment(HA_CENTER, VA_CENTER);
147     buttonText->SetFont(font, 12);
148     buttonText->SetText(text);
149 
150     return button;
151 }
152 
CreateSlider(int x,int y,int xSize,int ySize,const String & text)153 Slider* SoundEffects::CreateSlider(int x, int y, int xSize, int ySize, const String& text)
154 {
155     UIElement* root = GetSubsystem<UI>()->GetRoot();
156     ResourceCache* cache = GetSubsystem<ResourceCache>();
157     Font* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
158 
159     // Create text and slider below it
160     Text* sliderText = root->CreateChild<Text>();
161     sliderText->SetPosition(x, y);
162     sliderText->SetFont(font, 12);
163     sliderText->SetText(text);
164 
165     Slider* slider = root->CreateChild<Slider>();
166     slider->SetStyleAuto();
167     slider->SetPosition(x, y + 20);
168     slider->SetSize(xSize, ySize);
169     // Use 0-1 range for controlling sound/music master volume
170     slider->SetRange(1.0f);
171 
172     return slider;
173 }
174 
HandlePlaySound(StringHash eventType,VariantMap & eventData)175 void SoundEffects::HandlePlaySound(StringHash eventType, VariantMap& eventData)
176 {
177     Button* button = static_cast<Button*>(GetEventSender());
178     const String& soundResourceName = button->GetVar(VAR_SOUNDRESOURCE).GetString();
179 
180     // Get the sound resource
181     ResourceCache* cache = GetSubsystem<ResourceCache>();
182     Sound* sound = cache->GetResource<Sound>(soundResourceName);
183 
184     if (sound)
185     {
186         // Create a SoundSource component for playing the sound. The SoundSource component plays
187         // non-positional audio, so its 3D position in the scene does not matter. For positional sounds the
188         // SoundSource3D component would be used instead
189         SoundSource* soundSource = scene_->CreateComponent<SoundSource>();
190         // Component will automatically remove itself when the sound finished playing
191         soundSource->SetAutoRemoveMode(REMOVE_COMPONENT);
192         soundSource->Play(sound);
193         // In case we also play music, set the sound volume below maximum so that we don't clip the output
194         soundSource->SetGain(0.75f);
195     }
196 }
197 
HandlePlayMusic(StringHash eventType,VariantMap & eventData)198 void SoundEffects::HandlePlayMusic(StringHash eventType, VariantMap& eventData)
199 {
200     ResourceCache* cache = GetSubsystem<ResourceCache>();
201     Sound* music = cache->GetResource<Sound>("Music/Ninja Gods.ogg");
202     // Set the song to loop
203     music->SetLooped(true);
204 
205     musicSource_->Play(music);
206 }
207 
HandleStopMusic(StringHash eventType,VariantMap & eventData)208 void SoundEffects::HandleStopMusic(StringHash eventType, VariantMap& eventData)
209 {
210     // Remove the music player node from the scene
211     musicSource_->Stop();
212 }
213 
HandleSoundVolume(StringHash eventType,VariantMap & eventData)214 void SoundEffects::HandleSoundVolume(StringHash eventType, VariantMap& eventData)
215 {
216     using namespace SliderChanged;
217 
218     float newVolume = eventData[P_VALUE].GetFloat();
219     GetSubsystem<Audio>()->SetMasterGain(SOUND_EFFECT, newVolume);
220 }
221 
HandleMusicVolume(StringHash eventType,VariantMap & eventData)222 void SoundEffects::HandleMusicVolume(StringHash eventType, VariantMap& eventData)
223 {
224     using namespace SliderChanged;
225 
226     float newVolume = eventData[P_VALUE].GetFloat();
227     GetSubsystem<Audio>()->SetMasterGain(SOUND_MUSIC, newVolume);
228 }
229