Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ft sound manager #18

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
**/*.png filter=lfs diff=lfs merge=lfs -text
**/*.ttf filter=lfs diff=lfs merge=lfs -text
**/*.wav filter=lfs diff=lfs merge=lfs -text
**/*.mp3 filter=lfs diff=lfs merge=lfs -text
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Set the output directory for the build executables and libraries
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)

# Set the executable name
set(EXECUTABLE wolfenstein)
Expand Down Expand Up @@ -62,6 +68,7 @@ add_subdirectory(src/NavigationManager)
add_subdirectory(src/ShootingManager)
add_subdirectory(src/Strike)
add_subdirectory(src/State)
add_subdirectory(src/SoundManager)
add_subdirectory(src/TextureManager)
add_subdirectory(src/TimeManager)
add_subdirectory(src/Utility)
Expand Down
Binary file added assets/sounds/npc_attack.wav
Binary file not shown.
Binary file added assets/sounds/npc_death.wav
Binary file not shown.
Binary file added assets/sounds/npc_pain.wav
Binary file not shown.
Binary file added assets/sounds/player_pain.wav
Binary file not shown.
Binary file added assets/sounds/shotgun.wav
Binary file not shown.
Binary file added assets/sounds/theme.mp3
Binary file not shown.
14 changes: 14 additions & 0 deletions src/SoundManager/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_library(
sound_manager
STATIC
src/sound_manager.cpp
)
target_include_directories(sound_manager PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(
sound_manager
PUBLIC
SDL2
SDL2_mixer
)
53 changes: 53 additions & 0 deletions src/SoundManager/include/SoundManager/sound_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @file sound_manager.h
* @author Bilal Kahraman ([email protected])
* @brief
* @version 0.1
* @date 2024-12-12
*
* @copyright Copyright (c) 2024
*
*/

#ifndef SOUND_MANAGER_INCLUDE_SOUND_MANAGER_H
#define SOUND_MANAGER_INCLUDE_SOUND_MANAGER_H

#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <cstddef>
#include <string>
#include <unordered_map>
#include <vector>

namespace wolfenstein {

class SoundManager
{

public:
static SoundManager& GetInstance();

SoundManager(const SoundManager&) = delete;
SoundManager& operator=(const SoundManager&) = delete;
~SoundManager();

void InitManager();
void PlayEffect(std::string requester_id, std::string sound_effect);

private:
SoundManager() = default;
void LoadSound(const std::string sound_name, const std::string& sound_path);
void PlaySound(Mix_Chunk* sound, int channel = -1, int loops = 0);
Mix_Chunk* GetSound(std::string sound_name);

static SoundManager* instance_;
bool initialized_{false};
int channel_counter;
std::unordered_map<std::string, Mix_Chunk*> chunks_;
std::unordered_map<std::string, int> id_to_channel_;
Mix_Music* main_theme;
};

} // namespace wolfenstein

#endif // SOUND_MANAGER_INCLUDE_SOUND_MANAGER_H
105 changes: 105 additions & 0 deletions src/SoundManager/src/sound_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "SoundManager/sound_manager.h"
#include <SDL2/SDL_image.h>
#include <iostream>
#include <string>

namespace wolfenstein {

SoundManager* SoundManager::instance_ = nullptr;

SoundManager& SoundManager::GetInstance() {
if (instance_ == nullptr) {
instance_ = new SoundManager();
}
return *instance_;
}

SoundManager::~SoundManager() {
for (auto chunk : chunks_) {
Mix_FreeChunk(chunk.second);
}
Mix_FreeMusic(main_theme);
Mix_CloseAudio();
delete instance_;
}

void SoundManager::InitManager() {
if (initialized_) {
return;
}
if (SDL_Init(SDL_INIT_AUDIO) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
exit(EXIT_FAILURE);
}

if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
std::cerr << "Failed to initialize SDL_mixer: " << Mix_GetError()
<< std::endl;
exit(EXIT_FAILURE);
}

// Allocate channels (default is 8; increase if necessary)
Mix_AllocateChannels(16);

std::string sound_path = std::string(RESOURCE_DIR) + "sounds/";
LoadSound("npc_attack", sound_path + "npc_attack.wav");
LoadSound("npc_pain", sound_path + "npc_pain.wav");
LoadSound("npc_death", sound_path + "npc_death.wav");
LoadSound("player_pain", sound_path + "player_pain.wav");
LoadSound("shotgun", sound_path + "shotgun.wav");

Mix_VolumeChunk(GetSound("npc_attack"), 32);
Mix_VolumeChunk(GetSound("npc_pain"), 32);
Mix_VolumeChunk(GetSound("npc_death"), 64);
Mix_VolumeChunk(GetSound("player_pain"), 64);
Mix_VolumeChunk(GetSound("shotgun"), 64);

std::string main_music = sound_path + "theme.mp3";
main_theme = Mix_LoadMUS(main_music.c_str());
Mix_VolumeMusic(64);

// Play the MP3 file
if (Mix_PlayMusic(main_theme, -1) == -1) {
std::cerr << "Failed to play MP3 file: " << Mix_GetError() << std::endl;
exit(EXIT_FAILURE);
}
channel_counter = 0;
initialized_ = true;
}

// keep track of the ids
void SoundManager::PlayEffect(std::string requester_id,
std::string sound_effect) {
auto channel = id_to_channel_.find(requester_id);
if (channel == id_to_channel_.end()) {
id_to_channel_.insert({requester_id, channel_counter++});
PlaySound(GetSound(sound_effect), id_to_channel_[requester_id]);
}
else {
Mix_HaltChannel(channel->second);
PlaySound(GetSound(sound_effect), id_to_channel_[requester_id]);
}
}

void SoundManager::LoadSound(const std::string sound_name,
const std::string& sound_path) {
Mix_Chunk* sound = Mix_LoadWAV(sound_path.c_str());
if (!sound) {
std::cerr << "Failed to load WAV file: " << Mix_GetError() << std::endl;
return exit(EXIT_FAILURE);
}
chunks_.insert({sound_name, sound});
}

Mix_Chunk* SoundManager::GetSound(std::string sound_name) {
return chunks_[sound_name];
}

void SoundManager::PlaySound(Mix_Chunk* sound, int channel, int loops) {
// Play the sound on the specified channel with the specified number of loops
if (Mix_PlayChannel(channel, sound, loops) == -1) {
std::cerr << "Failed to play sound: " << Mix_GetError() << std::endl;
}
}

} // namespace wolfenstein
Loading