Skip to content
Draft
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: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ Sound/XRSound/**/Release-with-OrbiterRelease/
.kdev/
[Bb]uild/

Extern/irrKlang

Doc/**/*.log
Doc/**/*.pdf
Doc/**/*.gz
4 changes: 0 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,6 @@ option(ORBITER_TRACY_PROFILER

include(cmake/tracy.cmake)

if(ORBITER_BUILD_XRSOUND)
set(IRRKLANG_DIR "" CACHE PATH "Path to the irrKlang library")
endif()

if(ORBITER_BUILD_D3D9CLIENT)
find_package(DXSDK REQUIRED)
set(DXSDK_DIR
Expand Down
5 changes: 3 additions & 2 deletions Doc/Orbiter User Manual/CREDITS.tex
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ \subsection{Source contributions and components}
Steve Arch: TransX development \url{http://orbiter.quorg.org}

\subsection{Libraries, code, data, algorithms}
\textbf{IrrKlang}\\
\textbf{SDL3 and SDL3_mixer}\\
Audio and sound library\\
\url{https://www.ambiera.com/irrklang/}\\
\url{https://github.com/libsdl-org/SDL/}\\
\url{https://github.com/libsdl-org/SDL_mixer/}\\
\\
\textbf{Zlib}\\
Compression/decompression library\\
Expand Down
49 changes: 1 addition & 48 deletions Sound/XRSound/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,49 +1,8 @@
## irrKlang
if(NOT IRRKLANG_DIR)
set(IRRKLANG_DIR ${EXTERN_DIR}/irrKlang/${ARCH})

if(NOT EXISTS ${IRRKLANG_DIR})
if(BUILD64)
set(IRRKLANG_URL https://web.archive.org/web/20250213015920/https://www.ambiera.at/downloads/irrKlang-64bit-1.6.0.zip)
else()
set(IRRKLANG_URL https://web.archive.org/web/20250225180248/http://www.ambiera.at/downloads/irrKlang-32bit-1.6.0.zip)
endif()

include(FetchContent)
FetchContent_Declare(irrKlang
URL ${IRRKLANG_URL}
SOURCE_DIR ${IRRKLANG_DIR}
DOWNLOAD_EXTRACT_TIMESTAMP ON
)

message("Downloading irrKlang from ${IRRKLANG_URL} ...")
FetchContent_MakeAvailable(irrKlang)

else()
message("Found existing irrKlang at ${IRRKLANG_DIR}")
endif()

elseif(NOT EXISTS ${IRRKLANG_DIR})
message(FATAL_ERROR "IRRKLANG_DIR does not exist")
endif()

if(BUILD64)
set(IRRKLANG_BIN_DIR ${IRRKLANG_DIR}/bin/winx64-visualStudio)
set(IRRKLANG_LIB_DIR ${IRRKLANG_DIR}/lib/Winx64-visualStudio)
else()
# because of a bug in the 32bit version of irrKlang (it has hidden "__MACOSX" dir),
# CMake does not strip the top-level directory
string(APPEND IRRKLANG_DIR /irrKlang-1.6.0)

set(IRRKLANG_BIN_DIR ${IRRKLANG_DIR}/bin/win32-visualStudio)
set(IRRKLANG_LIB_DIR ${IRRKLANG_DIR}/lib/Win32-visualStudio)
endif()
set(IRRKLANG_LIB ${IRRKLANG_LIB_DIR}/irrKlang.lib)

## XRSound
set(ASSET_DIR ${CMAKE_CURRENT_SOURCE_DIR}/assets)
set(SOLUTION_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(IRRKLANG_DLL_DIR ${IRRKLANG_DIR})

# Deploy assets
file(GLOB config_files ${ASSET_DIR}/XRSound/*.cfg)

Expand All @@ -55,9 +14,6 @@ add_custom_target(XRSound_assets ALL
COMMAND ${CMAKE_COMMAND} -E copy ${ASSET_DIR}/XRSound/ReadMe.txt ${ORBITER_BINARY_ROOT_DIR}/XRSound/
COMMAND ${CMAKE_COMMAND} -E copy "${ASSET_DIR}/Doc/XRSound User Manual.pdf" ${ORBITER_BINARY_ROOT_DIR}/Doc/
COMMAND ${CMAKE_COMMAND} -E copy ${SOLUTION_DIR}/XRSound.h ${ORBITER_BINARY_SDK_DIR}/XRSound/
COMMAND ${CMAKE_COMMAND} -E copy ${IRRKLANG_BIN_DIR}/ikpMP3.dll ${ORBITER_BINARY_ROOT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${IRRKLANG_BIN_DIR}/ikpFlac.dll ${ORBITER_BINARY_ROOT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${IRRKLANG_BIN_DIR}/irrKlang.dll ${ORBITER_BINARY_ROOT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy_directory ${ASSET_DIR}/XRSound/Default ${ORBITER_BINARY_ROOT_DIR}/XRSound/Default
)

Expand All @@ -73,8 +29,5 @@ install(DIRECTORY ${ORBITER_BINARY_ROOT_DIR}/XRSound/Default
install(FILES "${ORBITER_BINARY_ROOT_DIR}/Doc/XRSound User Manual.pdf"
DESTINATION ${ORBITER_INSTALL_DOC_DIR}/
)
install(FILES ${ORBITER_BINARY_ROOT_DIR}/ikpMP3.dll ${ORBITER_BINARY_ROOT_DIR}/ikpFlac.dll ${ORBITER_BINARY_ROOT_DIR}/irrKlang.dll
DESTINATION ${ORBITER_INSTALL_ROOT_DIR}/
)

add_subdirectory(src)
33 changes: 0 additions & 33 deletions Sound/XRSound/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

=============================================================================

DEPENDENCIES:

1) XRSound uses the irrKlang Sound Engine.
See https://www.ambiera.com/irrklang/license.html for details
about the ikkLang license. Its license as of 31-July-2021 is quoted below:

The irrKlang License
irrKlang's source codes, documentation and binaries contained within the
distributed archive are copyright © Nikolaus Gebhardt / Ambiera 2001-2020.

The contents of the irrKlang distribution archive may not be redistributed,
reproduced, modified, transmitted, broadcast, published or adapted in any way,
shape or form, without the prior written consent of the owner, Nikolaus
Gebhardt.

The irrKlang.dll, irrKlang.so and libirrklang.dylib files may be
redistributed without the author's prior permission in non-commercial
products, and must remain unmodified except for compressing the file.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
16 changes: 4 additions & 12 deletions Sound/XRSound/assets/XRSound/XRSound.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,15 @@
#--------------------------------------------------------------------------
# Space-separated list of sound file extensions supported by XRSound.
#
# XRSound uses irrKlang Pro, which supports these sound file formats by default:
# XRSound uses SDL3_mixer, which supports these sound file formats by default:
#
# RIFF WAVE (*.wav)
# Ogg Vorbis (*.ogg)
# MPEG-1 Audio Layer 3 (*.mp3) [via ikpMP3.dll plugin, included]
# Free Lossless Audio Codec (*.flac) [via ikpFlac.dll plugin, included]
# Amiga Modules (*.mod)
# Impulse Tracker (*.it)
# Scream Tracker 3 (*.s3d)
# Fast Tracker 2 (*.xm)
# MPEG-1 Audio Layer 3 (*.mp3)
#
# Additional formats may be supported via plugins; visit
# https://www.ambiera.com/irrklang/ for more information.
#
# Default = .wav .ogg .mp3 .flac .mod .it .s3d .xm
# Default = .wav .ogg .mp3
#--------------------------------------------------------------------------
SupportedSoundFileTypes = .wav .ogg .mp3 .flac .mod .it .s3d .xm
SupportedSoundFileTypes = .wav .ogg .mp3

#--------------------------------------------------------------------------
# Sets the master volume for all sounds.
Expand Down
3 changes: 1 addition & 2 deletions Sound/XRSound/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_library(XRSound_dll SHARED
Resource.rc
Utils/ConfigFileParser.cpp
Utils/FileList.cpp
ISound.cpp
)

set_target_properties(XRSound_dll PROPERTIES
Expand All @@ -22,13 +23,11 @@ set_target_properties(XRSound_dll PROPERTIES
target_include_directories(XRSound_dll PUBLIC
${ORBITER_SOURCE_SDK_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Utils
${IRRKLANG_DIR}/include
)

target_link_libraries(XRSound_dll
${ORBITER_LIB}
${ORBITER_SDK_LIB}
${IRRKLANG_LIB}
)

add_dependencies(XRSound_dll
Expand Down
2 changes: 1 addition & 1 deletion Sound/XRSound/src/DefaultSoundGroupPreSteps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ void MusicDefaultSoundGroupPreStep::clbkPreStep(const double simt, const double
if (!HasFocus())
return;

// To prevent intermittent music stuttering on Orbiter startup when Orbiter hangs for a full second, which starves the irrKLang engine,
// To prevent intermittent music stuttering on Orbiter startup,
// don't play any music until two seconds after simulation start.
if (simt < 2.0)
{
Expand Down
153 changes: 153 additions & 0 deletions Sound/XRSound/src/ISound.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// ==============================================================
// miniaudio implementation of the ISound API
//
// Copyright (c) 2025 Gondos
// Licensed under the MIT License
// ==============================================================
#include "stb_vorbis.c"
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#include "ISound.h"

#include "OrbiterAPI.h"

ISoundEngine::ISoundEngine()
{
if (ma_engine_init(nullptr, &m_engine) != MA_SUCCESS) {
//oapiAddNotification(OAPINOTIF_ERROR, "Error initialising miniaudio engine");
return;
}
m_initialized = true;
}

ISoundEngine::~ISoundEngine()
{
if(!m_initialized) return;

for(auto &snd: releasedSounds) {
delete snd;
}
ma_engine_uninit(&m_engine);
}

ISound *ISoundEngine::play2D(const char *soundFileName, bool playLooped, bool startPaused, bool track)
{
if(!m_initialized) return nullptr;

CheckReleased();
ISound *snd = nullptr;
try {
snd = new ISound(&m_engine, soundFileName, playLooped, startPaused);
}
catch(...) {
//oapiAddNotification(OAPINOTIF_ERROR, "Error loading sound file", soundFileName);
return nullptr;
}

if (startPaused || track)
return snd;

Release(snd);
return nullptr;
}

void ISoundEngine::Release(ISound *snd)
{
if(!m_initialized) return;
if(!snd) return;

CheckReleased();
if(snd->isFinished())
delete snd;
else
releasedSounds.push_back(snd);
}

void ISoundEngine::CheckReleased()
{
for(auto it = releasedSounds.begin(); it != releasedSounds.end();) {
if((*it)->isFinished()) {
delete *it;
it = releasedSounds.erase(it);
} else {
++it;
}
}
}


ISound::ISound(ma_engine* engine,
const char* filename,
bool looped,
bool paused)
{
if (ma_result r = ma_sound_init_from_file(
engine,
filename,
MA_SOUND_FLAG_STREAM,
nullptr,
nullptr,
&m_sound); r != MA_SUCCESS)
{
throw "Failed to load sound";
}

ma_sound_set_looping(&m_sound, looped);
ma_sound_set_pan(&m_sound, 0.0f);

m_started = !paused;
m_paused = paused;

if (!paused)
ma_sound_start(&m_sound);
}

ISound::~ISound()
{
ma_sound_uninit(&m_sound);
}

void ISound::setIsLooped(bool looped)
{
ma_sound_set_looping(&m_sound, looped);
}

void ISound::setIsPaused(bool paused)
{
if (paused) {
ma_sound_stop_with_fade_in_milliseconds(&m_sound, FADEOUT);
} else {
if (!m_started)
m_started = true;

ma_sound_start(&m_sound);
}
m_paused = paused;
}

void ISound::setPan(float pan)
{
// -1.0 = left, 0 = center, +1.0 = right
ma_sound_set_pan(&m_sound, pan);
m_pan = pan;
}

bool ISound::setPlayPosition(unsigned int pos)
{
ma_uint64 sampleRate = ma_engine_get_sample_rate(
ma_sound_get_engine(&m_sound));

ma_uint64 frame = (sampleRate * pos) / 1000;
return ma_sound_seek_to_pcm_frame(&m_sound, frame) == MA_SUCCESS;
}

unsigned int ISound::getPlayPosition()
{
ma_uint64 frame;
ma_sound_get_cursor_in_pcm_frames(&m_sound, &frame);

ma_uint64 sampleRate = ma_engine_get_sample_rate(
ma_sound_get_engine(&m_sound));

return static_cast<unsigned int>((frame * 1000) / sampleRate);
}
Loading
Loading