4#include <Tempest/Sound>
12using namespace Tempest;
17 using Tempest::SoundProducer::SoundProducer;
21 std::lock_guard<std::recursive_mutex> guard(pendingSync);
29 std::lock_guard<std::recursive_mutex> guard(pendingSync);
45 std::lock_guard<std::recursive_mutex> guard(pendingSync);
46 reloadTheme = !pendingMusic || pendingMusic->file !=
theme.file;
54 bool reloadTheme =
false;
56 std::lock_guard<std::recursive_mutex> guard(pendingSync);
57 if(hasPending && pendingMusic && enable.load()) {
59 reloadTheme = this->reloadTheme;
60 theme = this->pendingMusic.value();
61 tags = this->pendingTags;
64 this->reloadTheme =
false;
73 zenkit::MusicTransitionEffect embellishment = zenkit::MusicTransitionEffect::NONE;
76 embellishment = zenkit::MusicTransitionEffect::BREAK;
80 embellishment = zenkit::MusicTransitionEffect::FILL;
84 embellishment = zenkit::MusicTransitionEffect::NONE;
91 std::atomic_bool enable{
true};
93 std::recursive_mutex pendingSync;
94 bool hasPending =
false;
95 bool reloadTheme =
false;
97 std::optional<zenkit::IMusicTheme> pendingMusic;
104 using GameMusic::MusicProvider::MusicProvider;
108 std::memset(out, 0, n *
sizeof(int32_t) * 2);
116 zenkit::IMusicTheme
theme;
121 if(
theme.file.empty()) {
140 catch (std::runtime_error &) {
141 Log::e(
"unable to load sound: \"",
theme.file,
"\"");
144 catch (std::bad_alloc &) {
145 Log::e(
"out of memory for sound: \"",
theme.file,
"\"");
157 case zenkit::MusicTransitionEffect::UNKNOWN:
158 case zenkit::MusicTransitionEffect::NONE:
160 case zenkit::MusicTransitionEffect::GROOVE:
162 case zenkit::MusicTransitionEffect::FILL:
164 case zenkit::MusicTransitionEffect::BREAK:
166 case zenkit::MusicTransitionEffect::INTRO:
168 case zenkit::MusicTransitionEffect::END:
169 case zenkit::MusicTransitionEffect::END_AND_INTO:
179static std::pair<DmTiming, DmEmbellishmentType>
computeEmbellishmentAndTiming(
const zenkit::MusicTransitionEffect effect,
const zenkit::MusicTransitionType type) {
180 DmEmbellishmentType embellishment = DmEmbellishment_NONE;
182 case zenkit::MusicTransitionEffect::UNKNOWN:
183 case zenkit::MusicTransitionEffect::NONE:
184 embellishment = DmEmbellishment_NONE;
186 case zenkit::MusicTransitionEffect::GROOVE:
187 embellishment = DmEmbellishment_GROOVE;
189 case zenkit::MusicTransitionEffect::FILL:
190 embellishment = DmEmbellishment_FILL;
192 case zenkit::MusicTransitionEffect::BREAK:
193 embellishment = DmEmbellishment_BREAK;
195 case zenkit::MusicTransitionEffect::INTRO:
196 embellishment = DmEmbellishment_INTRO;
198 case zenkit::MusicTransitionEffect::END:
199 embellishment = DmEmbellishment_END;
201 case zenkit::MusicTransitionEffect::END_AND_INTO:
202 embellishment = DmEmbellishment_END_AND_INTRO;
206 DmTiming timing = DmTiming_MEASURE;
208 case zenkit::MusicTransitionType::UNKNOWN:
209 case zenkit::MusicTransitionType::MEASURE:
210 timing = DmTiming_MEASURE;
212 case zenkit::MusicTransitionType::IMMEDIATE:
213 timing = DmTiming_INSTANT;
215 case zenkit::MusicTransitionType::BEAT:
216 timing = DmTiming_BEAT;
220 return std::make_pair(timing, embellishment);
231 DmResult rv = DmPerformance_create(&performance, rate);
232 if(rv != DmResult_SUCCESS) {
233 Log::e(
"Unable to create DmPerformance object. Out of memory?");
238 DmPerformance_release(performance);
243 std::memset(out, 0, n *
sizeof(int32_t) * 2);
247 DmPerformance_renderPcm(performance, out, n * 2, DmRenderOptions(DmRender_SHORT | DmRender_STEREO));
251 zenkit::IMusicTheme
theme;
256 if(
theme.file.empty()) {
265 DmResult rv = DmPerformance_playTransition(performance, sgt, embellishment, timing);
266 if(rv != DmResult_SUCCESS) {
267 Log::e(
"Failed to play theme: ",
theme.file);
271 DmPerformance_setVolume(performance,
theme.vol);
272 DmSegment_release(sgt);
278 DmPerformance_playTransition(performance,
nullptr, DmEmbellishment_NONE, DmTiming_INSTANT);
285 DmEmbellishmentType embellishment = DmEmbellishment_NONE;
287 case zenkit::MusicTransitionEffect::UNKNOWN:
288 case zenkit::MusicTransitionEffect::NONE:
289 embellishment = DmEmbellishment_NONE;
291 case zenkit::MusicTransitionEffect::GROOVE:
292 embellishment = DmEmbellishment_GROOVE;
294 case zenkit::MusicTransitionEffect::FILL:
295 embellishment = DmEmbellishment_FILL;
297 case zenkit::MusicTransitionEffect::BREAK:
298 embellishment = DmEmbellishment_BREAK;
300 case zenkit::MusicTransitionEffect::INTRO:
301 embellishment = DmEmbellishment_INTRO;
303 case zenkit::MusicTransitionEffect::END:
304 embellishment = DmEmbellishment_END;
306 case zenkit::MusicTransitionEffect::END_AND_INTO:
307 embellishment = DmEmbellishment_END_AND_INTRO;
313 embellishment = DmEmbellishmentType::DmEmbellishment_BREAK;
317 embellishment = DmEmbellishmentType::DmEmbellishment_FILL;
321 embellishment = DmEmbellishmentType::DmEmbellishment_NONE;
324 return embellishment;
328 DmPerformance *performance =
nullptr;
346 sound = SoundEffect();
356 return Tags(daytime | mode);
368 const char *clsTheme =
"";
371 clsTheme =
"SYS_Loading";
379 currentMusic.theme =
theme;
380 currentMusic.tags =
tags;
381 impl->
playTheme(currentMusic.theme, currentMusic.tags);
388void GameMusic::setupSettings() {
393 if(providerIndex != provider) {
394 Log::i(
"Switching music provider to ", providerIndex ==
PROVIDER_OPENGOTHIC ?
"'OpenGothic'" :
"'GothicKit'");
395 sound = SoundEffect();
397 std::unique_ptr<MusicProvider> p;
399 p = std::make_unique<OpenGothicMusicProvider>(
SAMPLE_RATE, 2);
401 p = std::make_unique<GothicKitMusicProvider>(
SAMPLE_RATE, 2);
404 provider = providerIndex;
406 impl->
playTheme(currentMusic.theme, currentMusic.tags);
408 sound = device.load(std::move(p));
413 sound.setVolume(musicVolume);
void setMusic(const Music &m, DMUS_EMBELLISHT_TYPES embellishment=DMUS_EMBELLISHT_NORMAL)
void setMusicVolume(float v)
void mix(int16_t *out, size_t samples)
void addPattern(const PatternList &list)
static Tags mkTags(Tags daytime, Tags mode)
static GameMusic & inst()
zenkit::IMusicTheme theme
Tempest::Signal< void()> onSettingsChanged
static int settingsGetI(std::string_view sec, std::string_view name)
static const MusicDefinitions & musicDef()
static float settingsGetF(std::string_view sec, std::string_view name)
static Dx8::PatternList loadDxMusic(std::string_view name)
static DmSegment * loadMusicSegment(char const *name)
static constexpr int PROVIDER_UNINITIALIZED
static constexpr uint16_t SAMPLE_RATE
static std::pair< DmTiming, DmEmbellishmentType > computeEmbellishmentAndTiming(const zenkit::MusicTransitionEffect effect, const zenkit::MusicTransitionType type)
static constexpr int PROVIDER_OPENGOTHIC
void stopTheme() override
~GothicKitMusicProvider() override
DmEmbellishmentType computeEmbellishment(Tags nextTags, Tags currTags, zenkit::MusicTransitionEffect transtype) const
void renderSound(int16_t *out, size_t n) override
GothicKitMusicProvider(uint16_t rate, uint16_t channels)
void playTheme(const zenkit::IMusicTheme &theme, GameMusic::Tags tags)
static zenkit::MusicTransitionEffect computeTransitionEffect(Tags nextTags, Tags currTags, zenkit::MusicTransitionEffect transtype)
bool updateTheme(zenkit::IMusicTheme &theme, Tags &tags)
static Dx8::DMUS_EMBELLISHT_TYPES computeEmbellishment(zenkit::MusicTransitionEffect ef)
void renderSound(int16_t *out, size_t n) override
void stopTheme() override