31 music_break_min(DefaultMusicBreak), music_break_max(DefaultMusicBreak),
41 #if AUDIO_TK == AUDIO_TK_OPENAL
44 alcMakeContextCurrent(alcContext);
50 #if AUDIO_TK == AUDIO_TK_SDL_MIXER
51 SDL_version compile_version;
52 const SDL_version * link_version;
53 MIX_VERSION(&compile_version);
54 link_version=Mix_Linked_Version();
55 LogF(
"SDL_mixer runtime version is %d.%d.%d (compiled with %d.%d.%d)",
56 link_version->major, link_version->minor, link_version->patch,
57 compile_version.major, compile_version.minor, compile_version.patch);
58 if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
60 LogF(
"SDL_InitSubSystem(SDL_INIT_AUDIO): %s", SDL_GetError());
64 if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024))
66 LogF(
"SDL_mixer: %s", SDL_GetError());
71 #elif AUDIO_TK == AUDIO_TK_OPENAL
72 alcDevice = alcOpenDevice(
nullptr);
75 LogF(
"Sound system: OpenAL create context error");
78 alcContext = alcCreateContext(alcDevice,
nullptr);
81 LogF(
"Sound system: OpenAL create context error");
85 if (!alutInitWithoutContext(
nullptr,
nullptr))
87 LogF(
"Sound system: ALUT init error");
99 #if AUDIO_TK == AUDIO_TK_SDL_MIXER
101 SDL_QuitSubSystem(SDL_INIT_AUDIO);
102 #elif AUDIO_TK == AUDIO_TK_OPENAL
106 alcDestroyContext(alcContext);
107 alcCloseDevice(alcDevice);
108 alcContext =
nullptr;
138 bool fLocalMusic =
false;
152 C4Group *pMusicFolder =
nullptr;
180 if (!szFile || !*szFile)
return;
182 #if AUDIO_TK == AUDIO_TK_OPENAL
185 if (
SEqualNoCase(szExt,
"ogg")) NewSong =
new C4MusicFileOgg;
186 #elif AUDIO_TK == AUDIO_TK_SDL_MIXER
191 if (!NewSong)
return;
193 NewSong->
Init(szFile);
196 while (pCurr && pCurr->
pNext) pCurr = pCurr->
pNext;
197 if (pCurr) pCurr->
pNext = NewSong;
else Songs = NewSong;
198 NewSong->
pNext =
nullptr;
201 playlist_valid =
false;
211 SCopy(pFileName, File);
212 *(pFileName - 1) = 0;
222 if (!pDirGroup->
Open(szPath))
225 if (!pDirGroup->
Open(Path))
228 LogF(
"Music File not found: %s", szPath);
245 if (!pDirGroup->
Open(Path))
247 LogF(
"Music File not found: %s", szPath);
271 char *pPos = MoreMusicFile.
getMData();
272 while (pPos && *pPos)
275 char szLine[1024 + 1];
277 pPos = strchr(pPos,
'\n');
if (pPos) pPos++;
279 char *pLine = szLine;
280 while (*pLine ==
' ' || *pLine ==
'\t' || *pLine ==
'\r') pLine++;
282 char *p = pLine + strlen(pLine) - 1;
283 while (*p ==
' ' || *p ==
'\t' || *p ==
'\r') { *p = 0; --p; }
288 if (
SEqual(pLine,
"#clear"))
308 playlist_valid =
false;
313 #if AUDIO_TK == AUDIO_TK_SDL_MIXER
323 game_music_level = 100;
324 music_break_min = music_break_max = DefaultMusicBreak;
325 music_break_chance = DefaultMusicBreakChance;
326 music_max_position_memory = DefaultMusicMaxPositionMemory;
350 force_song_execution =
true;
362 #if AUDIO_TK != AUDIO_TK_SDL_MIXER
365 (
void) force_song_execution;
377 Play(next_file,
false, 0.0);
390 bool C4MusicSystem::Play(
const char *szSongname,
bool fLoop,
int fadetime_ms,
double max_resume_time,
bool allow_break)
403 LogF(R
"(MusicSystem: Play("%s", %s, %d, %.3lf, %s))", szSongname ? szSongname : "(null)", fLoop ?
"true" :
"false", fadetime_ms, max_resume_time, allow_break ?
"true" :
"false");
409 if (szSongname && szSongname[0])
412 for (NewFile =
Songs; NewFile; NewFile = NewFile->
pNext)
426 if (max_resume_time > 0)
430 if (!check_file->NoPlay)
432 if (check_file->HasResumePos() && check_file->GetRemainingTime() > max_resume_time)
433 if (!music_max_position_memory || (t_now - check_file->GetLastInterruptionTime() <= music_max_position_memory*1000))
434 if (!NewFile || NewFile->
LastPlayed < check_file->LastPlayed)
435 NewFile = check_file;
448 int32_t new_file_playability = 0, new_file_num_rolls = 0;
451 if (!check_file->NoPlay)
458 int32_t check_file_playability = (check_file->LastPlayed < 0) ? 3 : (
SCounter - check_file->LastPlayed <=
ASongCount / 2) ? 1 : 2;
459 if (::
Config.
Sound.
Verbose)
LogF(
" Song LastPlayed %d [%d] (%s)",
int(check_file->LastPlayed),
int(check_file_playability), check_file->GetDebugInfo().getData());
460 if (check_file_playability > new_file_playability)
463 new_file_num_rolls = 1;
464 NewFile = check_file;
465 new_file_playability = check_file_playability;
467 else if (check_file_playability == new_file_playability)
525 if (!NewFile)
return false;
537 if (!
Play(NewFile, fLoop, max_resume_time))
return false;
549 LogF(R
"(MusicSystem: PlaySong("%s", %s, %.3lf))", NewFile->GetDebugInfo().getData(), fLoop ? "true" :
"false", max_resume_time);
552 if (!NewFile->
Play(fLoop, max_resume_time))
return false;
585 if (int32_t(
UnsyncedRandom(100)) >= music_break_chance)
return false;
586 if (music_break_max > 0)
588 int32_t music_break = music_break_min;
589 if (music_break_max > music_break_min) music_break +=
UnsyncedRandom(music_break_max - music_break_min);
596 LogF(
"MusicSystem: Pause (%d msecs)", (
int)music_break);
600 check_file->ClearResumePos();
638 Volume = config_volume * game_music_level / 100;
648 #if AUDIO_TK == AUDIO_TK_SDL_MIXER
678 if (playlist_valid && playlist == szPlayList)
return 0;
682 LogF(R
"(MusicSystem: SetPlayList("%s", %s, %d, %.3lf))", szPlayList ? szPlayList : "(null)", fForceSwitch ?
"true" :
"false", fadetime_ms, max_resume_time);
686 for (pFile =
Songs; pFile; pFile = pFile->
pNext)
691 if (szPlayList && *szPlayList)
707 for (pFile =
Songs; pFile; pFile = pFile->
pNext)
735 playlist.
Copy(szPlayList);
736 playlist_valid =
true;
767 comp->
Value(
mkNamingAdapt(music_break_chance,
"MusicBreakChance", DefaultMusicBreakChance));
768 comp->
Value(
mkNamingAdapt(music_max_position_memory,
"MusicMaxPositionMemory", DefaultMusicMaxPositionMemory));
780 game_music_level = Clamp<int32_t>(volume_percent, 0, 500);
782 return game_music_level;
785 const int32_t C4MusicSystem::DefaultMusicBreak = 120000;
786 const int32_t C4MusicSystem::DefaultMusicBreakChance = 50;
787 const int32_t C4MusicSystem::DefaultMusicMaxPositionMemory = 420;
C4GraphicsSystem GraphicsSystem
const char * LoadResStr(const char *id)
bool LogF(const char *strMessage,...)
MusicType GetMusicFileTypeByExtension(const char *ext)
uint32_t UnsyncedRandom()
const char * SSearch(const char *szString, const char *szIndex)
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
bool SGetModule(const char *szList, int iIndex, char *sTarget, int iSize)
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
void SCopyUntil(const char *szSource, char *sTarget, char cUntil, int iMaxL, int iIndex)
bool SEqual(const char *szStr1, const char *szStr2)
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
char * GetExtension(char *szFilename)
bool WildcardMatch(const char *szWildcard, const char *szString)
void DefaultExtension(char *szFilename, const char *szExtension)
char * GetFilename(char *szPath)
const char * AtSystemDataPath(const char *filename)
const char * AtUserDataPath(const char *filename)
void FlashMessageOnOff(const char *description, bool switch_on)
bool FindNextEntry(const char *wildcard, StdStrBuf *filename=nullptr, size_t *size=nullptr, bool start_at_filename=false)
StdStrBuf GetFullName() const
void ResetSearch(bool reload_contents=false)
bool FindEntry(const char *wildcard, StdStrBuf *filename=nullptr, size_t *size=nullptr)
bool Open(const char *group_name, bool do_create=false)
C4Group * FindGroup(int32_t Contents, C4Group *pAfter=nullptr, bool fSamePrio=false)
char FileName[_MAX_FNAME_LEN]
virtual void SetVolume(int)=0
virtual double GetRemainingTime()
virtual StdStrBuf GetDebugInfo() const
virtual bool Init(const char *strFile)
virtual void CheckIfPlaying()=0
virtual bool Play(bool loop=false, double max_resume_time=0.0)=0
virtual bool HasCategory(const char *szcat) const
virtual bool HasResumePos() const
virtual void Stop(int fadeout_ms=0)=0
bool HasBeenAnnounced() const
C4TimeMilliseconds FadeTimeStart
C4TimeMilliseconds wait_time_end
bool GrpContainsMusic(C4Group &rGrp)
void CompileFunc(class StdCompiler *comp)
void FadeOut(int fadeout_ms)
bool Play(const char *szSongname=nullptr, bool fLoop=false, int fadetime_ms=0, double max_resume_time=0.0, bool allow_break=false)
C4MusicFile * FadeMusicFile
bool Init(const char *PlayList=nullptr)
C4TimeMilliseconds FadeTimeEnd
void Execute(bool force_buffer_checks=false)
C4MusicFile * PlayMusicFile
int SetPlayList(const char *szPlayList, bool fForceSwitch=false, int fadetime_ms=0, double max_resume_time=0.0)
void LoadDir(const char *szPath)
int32_t SetGameMusicLevel(int32_t val)
bool InitForScenario(C4Group &hGroup)
C4MusicFile * upcoming_music_file
void Load(const char *szFile)
static C4TimeMilliseconds Now()
void Value(const T &rStruct)
virtual bool isDeserializer()
const char * getData() const
void AppendChar(char cChar)
bool LoadFromFile(const char *szFile)
void Append(const char *pnData, size_t iChars)