Add an operator bool to DeviceManager
[alure.git] / examples / alure-reverb.cpp
blob35c0e2a99a39eb035639457573c40833c42edfd5
1 /*
2 * An example showing how to load and apply a reverb effect to a source.
3 */
5 #include <algorithm>
6 #include <iostream>
7 #include <iomanip>
8 #include <cstring>
9 #include <cctype>
10 #include <thread>
11 #include <chrono>
13 #include "alure2.h"
15 #include "efx-presets.h"
17 namespace {
19 // Not UTF-8 aware!
20 int ci_compare(alure::StringView lhs, alure::StringView rhs)
22 using traits = alure::StringView::traits_type;
24 auto left = lhs.begin();
25 auto right = rhs.begin();
26 for(;left != lhs.end() && right != rhs.end();++left,++right)
28 int diff = std::tolower(traits::to_int_type(*left)) -
29 std::tolower(traits::to_int_type(*right));
30 if(diff != 0) return (diff < 0) ? -1 : 1;
32 if(right != rhs.end()) return -1;
33 if(left != lhs.end()) return 1;
34 return 0;
37 #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
38 const struct ReverbEntry {
39 const char name[32];
40 EFXEAXREVERBPROPERTIES props;
41 } reverblist[] = {
42 DECL(GENERIC),
43 DECL(PADDEDCELL),
44 DECL(ROOM),
45 DECL(BATHROOM),
46 DECL(LIVINGROOM),
47 DECL(STONEROOM),
48 DECL(AUDITORIUM),
49 DECL(CONCERTHALL),
50 DECL(CAVE),
51 DECL(ARENA),
52 DECL(HANGAR),
53 DECL(CARPETEDHALLWAY),
54 DECL(HALLWAY),
55 DECL(STONECORRIDOR),
56 DECL(ALLEY),
57 DECL(FOREST),
58 DECL(CITY),
59 DECL(MOUNTAINS),
60 DECL(QUARRY),
61 DECL(PLAIN),
62 DECL(PARKINGLOT),
63 DECL(SEWERPIPE),
64 DECL(UNDERWATER),
65 DECL(DRUGGED),
66 DECL(DIZZY),
67 DECL(PSYCHOTIC),
69 DECL(CASTLE_SMALLROOM),
70 DECL(CASTLE_SHORTPASSAGE),
71 DECL(CASTLE_MEDIUMROOM),
72 DECL(CASTLE_LARGEROOM),
73 DECL(CASTLE_LONGPASSAGE),
74 DECL(CASTLE_HALL),
75 DECL(CASTLE_CUPBOARD),
76 DECL(CASTLE_COURTYARD),
77 DECL(CASTLE_ALCOVE),
79 DECL(FACTORY_SMALLROOM),
80 DECL(FACTORY_SHORTPASSAGE),
81 DECL(FACTORY_MEDIUMROOM),
82 DECL(FACTORY_LARGEROOM),
83 DECL(FACTORY_LONGPASSAGE),
84 DECL(FACTORY_HALL),
85 DECL(FACTORY_CUPBOARD),
86 DECL(FACTORY_COURTYARD),
87 DECL(FACTORY_ALCOVE),
89 DECL(ICEPALACE_SMALLROOM),
90 DECL(ICEPALACE_SHORTPASSAGE),
91 DECL(ICEPALACE_MEDIUMROOM),
92 DECL(ICEPALACE_LARGEROOM),
93 DECL(ICEPALACE_LONGPASSAGE),
94 DECL(ICEPALACE_HALL),
95 DECL(ICEPALACE_CUPBOARD),
96 DECL(ICEPALACE_COURTYARD),
97 DECL(ICEPALACE_ALCOVE),
99 DECL(SPACESTATION_SMALLROOM),
100 DECL(SPACESTATION_SHORTPASSAGE),
101 DECL(SPACESTATION_MEDIUMROOM),
102 DECL(SPACESTATION_LARGEROOM),
103 DECL(SPACESTATION_LONGPASSAGE),
104 DECL(SPACESTATION_HALL),
105 DECL(SPACESTATION_CUPBOARD),
106 DECL(SPACESTATION_ALCOVE),
108 DECL(WOODEN_SMALLROOM),
109 DECL(WOODEN_SHORTPASSAGE),
110 DECL(WOODEN_MEDIUMROOM),
111 DECL(WOODEN_LARGEROOM),
112 DECL(WOODEN_LONGPASSAGE),
113 DECL(WOODEN_HALL),
114 DECL(WOODEN_CUPBOARD),
115 DECL(WOODEN_COURTYARD),
116 DECL(WOODEN_ALCOVE),
118 DECL(SPORT_EMPTYSTADIUM),
119 DECL(SPORT_SQUASHCOURT),
120 DECL(SPORT_SMALLSWIMMINGPOOL),
121 DECL(SPORT_LARGESWIMMINGPOOL),
122 DECL(SPORT_GYMNASIUM),
123 DECL(SPORT_FULLSTADIUM),
124 DECL(SPORT_STADIUMTANNOY),
126 DECL(PREFAB_WORKSHOP),
127 DECL(PREFAB_SCHOOLROOM),
128 DECL(PREFAB_PRACTISEROOM),
129 DECL(PREFAB_OUTHOUSE),
130 DECL(PREFAB_CARAVAN),
132 DECL(DOME_TOMB),
133 DECL(PIPE_SMALL),
134 DECL(DOME_SAINTPAULS),
135 DECL(PIPE_LONGTHIN),
136 DECL(PIPE_LARGE),
137 DECL(PIPE_RESONANT),
139 DECL(OUTDOORS_BACKYARD),
140 DECL(OUTDOORS_ROLLINGPLAINS),
141 DECL(OUTDOORS_DEEPCANYON),
142 DECL(OUTDOORS_CREEK),
143 DECL(OUTDOORS_VALLEY),
145 DECL(MOOD_HEAVEN),
146 DECL(MOOD_HELL),
147 DECL(MOOD_MEMORY),
149 DECL(DRIVING_COMMENTATOR),
150 DECL(DRIVING_PITGARAGE),
151 DECL(DRIVING_INCAR_RACER),
152 DECL(DRIVING_INCAR_SPORTS),
153 DECL(DRIVING_INCAR_LUXURY),
154 DECL(DRIVING_FULLGRANDSTAND),
155 DECL(DRIVING_EMPTYGRANDSTAND),
156 DECL(DRIVING_TUNNEL),
158 DECL(CITY_STREETS),
159 DECL(CITY_SUBWAY),
160 DECL(CITY_MUSEUM),
161 DECL(CITY_LIBRARY),
162 DECL(CITY_UNDERPASS),
163 DECL(CITY_ABANDONED),
165 DECL(DUSTYROOM),
166 DECL(CHAPEL),
167 DECL(SMALLWATERROOM),
169 #undef DECL
172 // Helper class+method to print the time with human-readable formatting.
173 struct PrettyTime {
174 alure::Seconds mTime;
176 inline std::ostream &operator<<(std::ostream &os, const PrettyTime &rhs)
178 using hours = std::chrono::hours;
179 using minutes = std::chrono::minutes;
180 using seconds = std::chrono::seconds;
181 using centiseconds = std::chrono::duration<int64_t, std::ratio<1, 100>>;
182 using std::chrono::duration_cast;
184 centiseconds t = duration_cast<centiseconds>(rhs.mTime);
185 if(t.count() < 0)
187 os << '-';
188 t *= -1;
191 // Only handle up to hour formatting
192 if(t >= hours(1))
193 os << duration_cast<hours>(t).count() << 'h' << std::setfill('0') << std::setw(2)
194 << duration_cast<minutes>(t).count() << 'm';
195 else
196 os << duration_cast<minutes>(t).count() << 'm' << std::setfill('0');
197 os << std::setw(2) << (duration_cast<seconds>(t).count() % 60) << '.' << std::setw(2)
198 << (t.count() % 100) << 's' << std::setw(0) << std::setfill(' ');
199 return os;
202 } // namespace
204 int main(int argc, char *argv[])
206 alure::ArrayView<const char*> args(argv, argc);
208 if(args.size() < 2)
210 std::cerr<< "Usage: "<<args.front()<<" [-device \"device name\"] [-preset \"reverb preset\"] files..." <<std::endl;
211 return 1;
213 args = args.slice(1);
215 alure::DeviceManager devMgr = alure::DeviceManager::getInstance();
217 alure::Device dev;
218 if(args.size() > 2 && args[0] == alure::StringView("-device"))
220 dev = devMgr.openPlayback(args[1], std::nothrow);
221 if(!dev) std::cerr<< "Failed to open \""<<args[1]<<"\" - trying default" <<std::endl;
222 args = args.slice(2);
224 if(!dev) dev = devMgr.openPlayback();
225 std::cout<< "Opened \""<<dev.getName()<<"\"" <<std::endl;
227 alure::Context ctx = dev.createContext();
228 alure::Context::MakeCurrent(ctx);
230 alure::Effect effect = ctx.createEffect();
231 effect.setReverbProperties(EFX_REVERB_PRESET_GENERIC);
233 if(args.size() > 1 && alure::StringView("-preset") == args[0])
235 alure::StringView reverb_name = args[1];
236 args = args.slice(2);
238 auto iter = std::find_if(std::begin(reverblist), std::end(reverblist),
239 [reverb_name](const ReverbEntry &entry) -> bool
240 { return ci_compare(reverb_name, entry.name) == 0; }
242 if(iter != std::end(reverblist))
244 std::cout<< "Loading preset "<<iter->name <<std::endl;
245 effect.setReverbProperties(iter->props);
247 else
248 std::cout<< "Failed to find preset "<<reverb_name <<std::endl;
250 else
251 std::cout<< "Using generic reverb preset" <<std::endl;
253 alure::AuxiliaryEffectSlot auxslot = ctx.createAuxiliaryEffectSlot();
254 auxslot.applyEffect(effect);
256 for(;!args.empty();args = args.slice(1))
258 alure::SharedPtr<alure::Decoder> decoder = ctx.createDecoder(args.front());
259 alure::Source source = ctx.createSource();
261 source.setAuxiliarySend(auxslot, 0);
263 source.play(decoder, 12000, 4);
264 std::cout<< "Playing "<<args.front()<<" ("
265 << alure::GetSampleTypeName(decoder->getSampleType())<<", "
266 << alure::GetChannelConfigName(decoder->getChannelConfig())<<", "
267 << decoder->getFrequency()<<"hz)" <<std::endl;
269 double invfreq = 1.0 / decoder->getFrequency();
270 while(source.isPlaying())
272 std::cout<< "\r "<<PrettyTime{source.getSecOffset()}<<" / "<<
273 PrettyTime{alure::Seconds(decoder->getLength()*invfreq)};
274 std::cout.flush();
275 std::this_thread::sleep_for(std::chrono::milliseconds(25));
276 ctx.update();
278 std::cout<<std::endl;
280 source.destroy();
281 decoder.reset();
284 auxslot.destroy();
285 effect.destroy();
287 alure::Context::MakeCurrent(nullptr);
288 ctx.destroy();
289 dev.close();
291 return 0;