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