1 /*************************************************************************/
2 /*  sample_player_2d.cpp                                                 */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "sample_player_2d.h"
31 
32 #include "servers/audio_server.h"
33 #include "servers/spatial_sound_server.h"
34 
_set(const StringName & p_name,const Variant & p_value)35 bool SamplePlayer2D::_set(const StringName &p_name, const Variant &p_value) {
36 
37 	String name = p_name;
38 
39 	if (name == "play/play") {
40 		if (library.is_valid()) {
41 
42 			String what = p_value;
43 			if (what == "")
44 				stop_all();
45 			else
46 				play(what);
47 
48 			played_back = what;
49 		}
50 	} else
51 		return false;
52 
53 	return true;
54 }
55 
_get(const StringName & p_name,Variant & r_ret) const56 bool SamplePlayer2D::_get(const StringName &p_name, Variant &r_ret) const {
57 
58 	String name = p_name;
59 
60 	if (name == "play/play") {
61 		r_ret = played_back;
62 	} else
63 		return false;
64 
65 	return true;
66 }
67 
_get_property_list(List<PropertyInfo> * p_list) const68 void SamplePlayer2D::_get_property_list(List<PropertyInfo> *p_list) const {
69 
70 	String en = "";
71 	if (library.is_valid()) {
72 		List<StringName> samples;
73 		Ref<SampleLibrary> ncl = library;
74 		ncl->get_sample_list(&samples);
75 		for (List<StringName>::Element *E = samples.front(); E; E = E->next()) {
76 
77 			en += ",";
78 			en += E->get();
79 		}
80 	}
81 
82 	p_list->push_back(PropertyInfo(Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER));
83 }
84 
_notification(int p_what)85 void SamplePlayer2D::_notification(int p_what) {
86 
87 	switch (p_what) {
88 
89 		case NOTIFICATION_ENTER_TREE: {
90 
91 			SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(), polyphony);
92 
93 		} break;
94 	}
95 }
96 
set_sample_library(const Ref<SampleLibrary> & p_library)97 void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary> &p_library) {
98 
99 	library = p_library;
100 	_change_notify();
101 	update_configuration_warning();
102 }
103 
get_sample_library() const104 Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const {
105 
106 	return library;
107 }
108 
set_polyphony(int p_voice_count)109 void SamplePlayer2D::set_polyphony(int p_voice_count) {
110 
111 	ERR_FAIL_COND(p_voice_count < 0 || p_voice_count > 64);
112 	polyphony = p_voice_count;
113 	if (get_source_rid().is_valid())
114 		SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(), polyphony);
115 }
116 
get_polyphony() const117 int SamplePlayer2D::get_polyphony() const {
118 
119 	return polyphony;
120 }
121 
play(const String & p_sample,int p_voice)122 SamplePlayer2D::VoiceID SamplePlayer2D::play(const String &p_sample, int p_voice) {
123 
124 	if (!get_source_rid().is_valid())
125 		return INVALID_VOICE;
126 	if (library.is_null())
127 		return INVALID_VOICE;
128 	if (!library->has_sample(p_sample))
129 		return INVALID_VOICE;
130 	Ref<Sample> sample = library->get_sample(p_sample);
131 	float vol_change = library->sample_get_volume_db(p_sample);
132 	float pitch_change = library->sample_get_pitch_scale(p_sample);
133 	int priority = library->sample_get_priority(p_sample);
134 
135 	VoiceID vid = SpatialSound2DServer::get_singleton()->source_play_sample(get_source_rid(), sample->get_rid(), sample->get_mix_rate() * pitch_change, p_voice, priority);
136 	if (vol_change)
137 		SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(), vid, vol_change);
138 
139 	if (random_pitch_scale) {
140 		float ps = Math::random(-random_pitch_scale, random_pitch_scale);
141 		if (ps > 0)
142 			ps = 1.0 + ps;
143 		else
144 			ps = 1.0 / (1.0 - ps);
145 		SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(), vid, ps * pitch_change);
146 	}
147 
148 	return vid;
149 }
150 //voices
voice_set_pitch_scale(VoiceID p_voice,float p_pitch_scale)151 void SamplePlayer2D::voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale) {
152 
153 	if (!get_source_rid().is_valid())
154 		return;
155 
156 	SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(), p_voice, p_pitch_scale);
157 }
158 
voice_set_volume_scale_db(VoiceID p_voice,float p_volume_db)159 void SamplePlayer2D::voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db) {
160 
161 	if (!get_source_rid().is_valid())
162 		return;
163 	SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(), p_voice, p_volume_db);
164 }
165 
is_voice_active(VoiceID p_voice) const166 bool SamplePlayer2D::is_voice_active(VoiceID p_voice) const {
167 
168 	if (!get_source_rid().is_valid())
169 		return false;
170 	return SpatialSound2DServer::get_singleton()->source_is_voice_active(get_source_rid(), p_voice);
171 }
172 
stop_voice(VoiceID p_voice)173 void SamplePlayer2D::stop_voice(VoiceID p_voice) {
174 
175 	if (!get_source_rid().is_valid())
176 		return;
177 	SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(), p_voice);
178 }
179 
stop_all()180 void SamplePlayer2D::stop_all() {
181 
182 	if (!get_source_rid().is_valid())
183 		return;
184 
185 	for (int i = 0; i < polyphony; i++) {
186 
187 		SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(), i);
188 	}
189 }
190 
set_random_pitch_scale(float p_scale)191 void SamplePlayer2D::set_random_pitch_scale(float p_scale) {
192 	random_pitch_scale = p_scale;
193 }
194 
get_random_pitch_scale() const195 float SamplePlayer2D::get_random_pitch_scale() const {
196 
197 	return random_pitch_scale;
198 }
199 
get_configuration_warning() const200 String SamplePlayer2D::get_configuration_warning() const {
201 
202 	if (library.is_null()) {
203 		return TTR("A SampleLibrary resource must be created or set in the 'samples' property in order for SamplePlayer to play sound.");
204 	}
205 
206 	return String();
207 }
208 
_bind_methods()209 void SamplePlayer2D::_bind_methods() {
210 
211 	ObjectTypeDB::bind_method(_MD("set_sample_library", "library:SampleLibrary"), &SamplePlayer2D::set_sample_library);
212 	ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"), &SamplePlayer2D::get_sample_library);
213 
214 	ObjectTypeDB::bind_method(_MD("set_polyphony", "max_voices"), &SamplePlayer2D::set_polyphony);
215 	ObjectTypeDB::bind_method(_MD("get_polyphony"), &SamplePlayer2D::get_polyphony);
216 
217 	ObjectTypeDB::bind_method(_MD("play", "sample", "voice"), &SamplePlayer2D::play, DEFVAL(NEXT_VOICE));
218 	//voices,DEV
219 	ObjectTypeDB::bind_method(_MD("voice_set_pitch_scale", "voice", "ratio"), &SamplePlayer2D::voice_set_pitch_scale);
220 	ObjectTypeDB::bind_method(_MD("voice_set_volume_scale_db", "voice", "db"), &SamplePlayer2D::voice_set_volume_scale_db);
221 
222 	ObjectTypeDB::bind_method(_MD("is_voice_active", "voice"), &SamplePlayer2D::is_voice_active);
223 	ObjectTypeDB::bind_method(_MD("stop_voice", "voice"), &SamplePlayer2D::stop_voice);
224 	ObjectTypeDB::bind_method(_MD("stop_all"), &SamplePlayer2D::stop_all);
225 
226 	ObjectTypeDB::bind_method(_MD("set_random_pitch_scale", "val"), &SamplePlayer2D::set_random_pitch_scale);
227 	ObjectTypeDB::bind_method(_MD("get_random_pitch_scale"), &SamplePlayer2D::get_random_pitch_scale);
228 
229 	BIND_CONSTANT(INVALID_VOICE);
230 	BIND_CONSTANT(NEXT_VOICE);
231 
232 	ADD_PROPERTY(PropertyInfo(Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,64,1"), _SCS("set_polyphony"), _SCS("get_polyphony"));
233 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE, "SampleLibrary"), _SCS("set_sample_library"), _SCS("get_sample_library"));
234 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "config/pitch_random", PROPERTY_HINT_RESOURCE_TYPE, "SampleLibrary"), _SCS("set_random_pitch_scale"), _SCS("get_random_pitch_scale"));
235 }
236 
SamplePlayer2D()237 SamplePlayer2D::SamplePlayer2D() {
238 
239 	polyphony = 1;
240 	random_pitch_scale = 0;
241 }
242 
~SamplePlayer2D()243 SamplePlayer2D::~SamplePlayer2D() {
244 }
245