Skip to content

Commit 560ee24

Browse files
committed
Add: Support sound effects in Ogg Opus format.
1 parent 8b00661 commit 560ee24

File tree

10 files changed

+227
-0
lines changed

10 files changed

+227
-0
lines changed

.github/workflows/ci-linux.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ jobs:
6060
libicu-dev \
6161
liblzma-dev \
6262
liblzo2-dev \
63+
libogg-dev \
64+
libopus-dev \
65+
libopusfile-dev \
6366
${{ inputs.libraries }} \
6467
zlib1g-dev \
6568
# EOF

.github/workflows/ci-mingw.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ jobs:
3737
mingw-w64-${{ inputs.arch }}-libpng
3838
mingw-w64-${{ inputs.arch }}-lld
3939
mingw-w64-${{ inputs.arch }}-ninja
40+
mingw-w64-${{ inputs.arch }}-ogg
41+
mingw-w64-${{ inputs.arch }}-opus
42+
mingw-w64-${{ inputs.arch }}-opusfile
4043
4144
- name: Install OpenGFX
4245
shell: bash

.github/workflows/codeql.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ jobs:
5454
libicu-dev \
5555
liblzma-dev \
5656
liblzo2-dev \
57+
libopus-dev \
58+
libopusfile-dev \
5759
libsdl2-dev \
5860
zlib1g-dev \
5961
# EOF

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ if(NOT OPTION_DEDICATED)
155155
find_package(ICU OPTIONAL_COMPONENTS i18n uc)
156156
endif()
157157
endif()
158+
find_package(OpusFile)
158159
endif()
159160
if(APPLE)
160161
enable_language(OBJCXX)
@@ -332,6 +333,7 @@ if(NOT OPTION_DEDICATED)
332333
link_package(Harfbuzz TARGET harfbuzz::harfbuzz)
333334
link_package(ICU_i18n)
334335
link_package(ICU_uc)
336+
link_package(OpusFile TARGET OpusFile::opusfile)
335337

336338
if(SDL2_FOUND AND OPENGL_FOUND AND UNIX)
337339
# SDL2 dynamically loads OpenGL if needed, so do not link to OpenGL when

cmake/FindOgg.cmake

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
include(FindPackageHandleStandardArgs)
2+
3+
find_library(Ogg_LIBRARY
4+
NAMES ogg
5+
)
6+
7+
set(Ogg_COMPILE_OPTIONS "" CACHE STRING "Extra compile options of ogg")
8+
9+
set(Ogg_LINK_LIBRARIES "" CACHE STRING "Extra link libraries of ogg")
10+
11+
set(Ogg_LINK_FLAGS "" CACHE STRING "Extra link flags of ogg")
12+
13+
find_path(Ogg_INCLUDE_PATH
14+
NAMES ogg.h
15+
PATH_SUFFIXES ogg
16+
)
17+
18+
find_package_handle_standard_args(Ogg
19+
REQUIRED_VARS Ogg_LIBRARY Ogg_INCLUDE_PATH
20+
)
21+
22+
if (Ogg_FOUND)
23+
set(Ogg_dirs ${Ogg_INCLUDE_PATH})
24+
if(EXISTS "${Ogg_INCLUDE_PATH}/ogg")
25+
list(APPEND Ogg_dirs "${Ogg_INCLUDE_PATH}/ogg")
26+
endif()
27+
if (NOT TARGET Ogg::ogg)
28+
add_library(Ogg::ogg UNKNOWN IMPORTED)
29+
set_target_properties(Ogg::ogg PROPERTIES
30+
IMPORTED_LOCATION "${Ogg_LIBRARY}"
31+
INTERFACE_INCLUDE_DIRECTORIES "${Ogg_dirs}"
32+
INTERFACE_COMPILE_OPTIONS "${Ogg_COMPILE_OPTIONS}"
33+
INTERFACE_LINK_LIBRARIES "${Ogg_LINK_LIBRARIES}"
34+
INTERFACE_LINK_FLAGS "${Ogg_LINK_FLAGS}"
35+
)
36+
endif()
37+
endif()

cmake/FindOpus.cmake

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
include(FindPackageHandleStandardArgs)
2+
3+
find_library(Opus_LIBRARY
4+
NAMES opus
5+
)
6+
7+
set(Opus_COMPILE_OPTIONS "" CACHE STRING "Extra compile options of opus")
8+
9+
set(Opus_LINK_LIBRARIES "" CACHE STRING "Extra link libraries of opus")
10+
11+
set(Opus_LINK_FLAGS "" CACHE STRING "Extra link flags of opus")
12+
13+
find_path(Opus_INCLUDE_PATH
14+
NAMES opus.h
15+
PATH_SUFFIXES opus
16+
)
17+
18+
find_package_handle_standard_args(Opus
19+
REQUIRED_VARS Opus_LIBRARY Opus_INCLUDE_PATH
20+
)
21+
22+
if (Opus_FOUND)
23+
set(Opus_dirs ${Opus_INCLUDE_PATH})
24+
if(EXISTS "${Opus_INCLUDE_PATH}/opus")
25+
list(APPEND Opus_dirs "${Opus_INCLUDE_PATH}/opus")
26+
endif()
27+
if (NOT TARGET Opus::opus)
28+
add_library(Opus::opus UNKNOWN IMPORTED)
29+
set_target_properties(Opus::opus PROPERTIES
30+
IMPORTED_LOCATION "${Opus_LIBRARY}"
31+
INTERFACE_INCLUDE_DIRECTORIES "${Opus_dirs}"
32+
INTERFACE_COMPILE_OPTIONS "${Opus_COMPILE_OPTIONS}"
33+
INTERFACE_LINK_LIBRARIES "${Opus_LINK_LIBRARIES}"
34+
INTERFACE_LINK_FLAGS "${Opus_LINK_FLAGS}"
35+
)
36+
endif()
37+
endif()

cmake/FindOpusFile.cmake

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
include(FindPackageHandleStandardArgs)
2+
3+
find_library(OpusFile_LIBRARY
4+
NAMES opusfile
5+
)
6+
7+
set(OpusFile_COMPILE_OPTIONS "" CACHE STRING "Extra compile options of opusfile")
8+
9+
set(OpusFile_LINK_LIBRARIES "" CACHE STRING "Extra link libraries of opusfile")
10+
11+
set(OpusFile_LINK_FLAGS "" CACHE STRING "Extra link flags of opusfile")
12+
13+
find_path(OpusFile_INCLUDE_PATH
14+
NAMES opusfile.h
15+
PATH_SUFFIXES opus
16+
)
17+
18+
find_package_handle_standard_args(OpusFile
19+
REQUIRED_VARS OpusFile_LIBRARY OpusFile_INCLUDE_PATH
20+
)
21+
22+
find_package(Ogg)
23+
find_package(Opus)
24+
25+
if (OpusFile_FOUND)
26+
set(OpusFile_dirs ${OpusFile_INCLUDE_PATH})
27+
if(EXISTS "${OpusFile_INCLUDE_PATH}/opus")
28+
list(APPEND OpusFile_dirs "${OpusFile_INCLUDE_PATH}/opus")
29+
endif()
30+
if (NOT TARGET OpusFile::opusfile)
31+
add_library(OpusFile::opusfile UNKNOWN IMPORTED)
32+
set_target_properties(OpusFile::opusfile PROPERTIES
33+
IMPORTED_LOCATION "${OpusFile_LIBRARY}"
34+
INTERFACE_INCLUDE_DIRECTORIES "${OpusFile_dirs}"
35+
INTERFACE_COMPILE_OPTIONS "${OpusFile_COMPILE_OPTIONS}"
36+
INTERFACE_LINK_LIBRARIES "Ogg::ogg;Opus::opus;${OpusFile_LINK_LIBRARIES}"
37+
INTERFACE_LINK_FLAGS "${OpusFile_LINK_FLAGS}"
38+
)
39+
endif()
40+
endif()

src/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ add_files(
3939
CONDITION ICU_i18n_FOUND AND HARFBUZZ_FOUND
4040
)
4141

42+
add_files(
43+
soundloader_opus.cpp
44+
CONDITION OpusFile_FOUND
45+
)
46+
4247
add_files(
4348
aircraft.h
4449
aircraft_cmd.cpp

src/soundloader_opus.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* This file is part of OpenTTD.
3+
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4+
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5+
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6+
*/
7+
8+
/** @file sound_opus.cpp Loading of opus sounds. */
9+
10+
#include "stdafx.h"
11+
#include "random_access_file_type.h"
12+
#include "sound_type.h"
13+
#include "soundloader_type.h"
14+
15+
#include <opusfile.h>
16+
17+
#include "safeguards.h"
18+
19+
/** Opus sound loader. */
20+
class SoundLoader_Opus : public SoundLoader {
21+
public:
22+
SoundLoader_Opus() : SoundLoader("opus", "Opus sound loader", 10) {}
23+
24+
static constexpr uint16_t OPUS_SAMPLE_RATE = 48000; ///< OpusFile always decodes at 48kHz.
25+
static constexpr uint8_t OPUS_SAMPLE_BITS = 16; ///< OpusFile op_read() uses 16 bits per sample.
26+
27+
/* For good results, you will need at least 57 bytes (for a pure Opus-only stream). */
28+
static constexpr size_t MIN_OPUS_FILE_SIZE = 57U;
29+
30+
/* It is recommended that this be large enough for at least 120 ms of data at 48 kHz per channel (5760 values per channel).
31+
* Smaller buffers will simply return less data, possibly consuming more memory to buffer the data internally. */
32+
static constexpr size_t DECODE_BUFFER_SAMPLES = 5760 * 2;
33+
static constexpr size_t DECODE_BUFFER_BYTES = DECODE_BUFFER_SAMPLES * sizeof(opus_int16);
34+
35+
bool Load(SoundEntry &sound, bool new_format, std::vector<uint8_t> &data) override
36+
{
37+
if (!new_format) return false;
38+
39+
/* At least 57 bytes are needed for an Opus-only file. */
40+
if (sound.file_size < MIN_OPUS_FILE_SIZE) return false;
41+
42+
/* Test if data is an Ogg Opus stream, as identified by the initial file header. */
43+
auto filepos = sound.file->GetPos();
44+
std::vector<uint8_t> tmp(MIN_OPUS_FILE_SIZE);
45+
sound.file->ReadBlock(tmp.data(), tmp.size());
46+
if (op_test(nullptr, tmp.data(), tmp.size()) != 0) return false;
47+
48+
/* Read the whole file into memory. */
49+
tmp.resize(sound.file_size);
50+
sound.file->SeekTo(filepos, SEEK_SET);
51+
sound.file->ReadBlock(tmp.data(), tmp.size());
52+
53+
int error = 0;
54+
auto of = std::unique_ptr<OggOpusFile, OggOpusFileDeleter>(op_open_memory(tmp.data(), tmp.size(), &error));
55+
if (error != 0) return false;
56+
57+
size_t datapos = 0;
58+
for (;;) {
59+
data.resize(datapos + DECODE_BUFFER_BYTES);
60+
61+
int link_index;
62+
int read = op_read(of.get(), reinterpret_cast<opus_int16 *>(&data[datapos]), DECODE_BUFFER_BYTES, &link_index);
63+
if (read == 0) break;
64+
65+
if (read < 0 || op_channel_count(of.get(), link_index) != 1) {
66+
/* Error reading, or incorrect channel count. */
67+
data.clear();
68+
return false;
69+
}
70+
71+
datapos += read * sizeof(opus_int16);
72+
}
73+
74+
/* OpusFile always decodes at 48kHz. */
75+
sound.channels = 1;
76+
sound.bits_per_sample = OPUS_SAMPLE_BITS;
77+
sound.rate = OPUS_SAMPLE_RATE;
78+
79+
/* We resized by DECODE_BUFFER_BYTES just before finally reading zero bytes, undo this. */
80+
data.resize(data.size() - DECODE_BUFFER_BYTES);
81+
82+
return true;
83+
}
84+
85+
private:
86+
/** Helper class to RAII release an OggOpusFile. */
87+
struct OggOpusFileDeleter {
88+
void operator()(OggOpusFile *of)
89+
{
90+
if (of != nullptr) op_free(of);
91+
}
92+
};
93+
};
94+
95+
static SoundLoader_Opus s_sound_loader_opus;

vcpkg.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
{
4343
"name": "lzo"
4444
},
45+
{
46+
"name": "opusfile"
47+
},
4548
{
4649
"name": "sdl2",
4750
"platform": "linux"

0 commit comments

Comments
 (0)