Overview
rsgain.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Mon Jun 10 11:24:03 UTC 2024 - Luigi Baldoni <aloisio@gmx.com>
4
+
5
+- Update to version 3.5.1
6
+ * Fix header gain calculation for multichannel Opus files
7
+ * Static builds: Upgrade to FFmpeg 7
8
+ version 3.5:
9
+ * Add -p option to preserve file modification times
10
+ * In Custom Mode, immediately fail if any file in the list
11
+ does not exist or is of unsupported type
12
+ * Fix segfault that occurs when attempting to tag corrupted
13
+ MP4 files
14
+ * Provide static builds for macOS and Linux
15
+ * Unix: Include optional manpage with installation
16
+ * Windows: Support long paths
17
+ * Static builds: Upgrade to TagLib 2
18
+ version 3.4:
19
+ * Added support for Tom's lossless Audio Kompressor (TAK)
20
+ format
21
+ * Added -O option 'a' which sorts the output by filename
22
+ alphanumerically
23
+ * Added Custom Mode -o option 's' which forces Opus files to
24
+ normalize to -23 LUFS regardless of the target loudness
25
+ setting
26
+ * Support files with .mp4 file extension
27
+ + Introduce Easy Mode preset option "SkipMP4" which allows
28
+ users to opt out of the new behavior
29
+ * When scanning completely silent tracks, the program now
30
+ writes "0.00 dB" and "0.000000" as gain and peak tags,
31
+ respectively. Previously, the program would completely skip
32
+ over these files without writing any tags to them
33
+ + Silent tracks are not included in album gain calculations
34
+ to keep results consistent with previous versions
35
+ * -I 'keep' mode now default in both Custom Mode and Easy Mode
36
+ * Fix TagMode 'n' option (regression from v3.2)
37
+- Clean up specfile
38
+
39
+-------------------------------------------------------------------
40
Mon Jul 3 05:37:40 UTC 2023 - Philipp Seiler <p.seiler@linuxmail.org>
41
42
- removed compiler flags that didn't work for now. Will be properly fixed
43
rsgain.spec
Changed
72
1
2
#
3
-# spec file for package
4
+# spec file for package rsgain
5
#
6
+# Copyright (c) 2024 Packman Team <packman@links2linux.de>
7
# Copyright (c) 2023 SUSE LINUX Products GmbH, Nuernberg, Germany.
8
#
9
# All modifications and additions to the file contributed by third parties
10
11
#
12
13
Name: rsgain
14
-Version: 3.3
15
-Release: 1
16
-License: custom
17
+Version: 3.5.1
18
+Release: 0
19
+License: BSD-2-Clause AND BSD-3-Clause
20
Summary: ReplayGain 2.0 loudness normalizer
21
-Url: https://www.archlinux.org/packages/community/x86_64/xbmc/
22
+URL: https://www.archlinux.org/packages/community/x86_64/xbmc/
23
Group: System/Base
24
-Source0: %{name}-%{version}-source.tar.xz
25
+Source0: https://github.com/complexlogic/rsgain/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
26
BuildRequires: cmake
27
-BuildRequires: gcc12-c++
28
+BuildRequires: pkgconfig(fmt)
29
+BuildRequires: pkgconfig(inih)
30
BuildRequires: pkgconfig(libavcodec)
31
BuildRequires: pkgconfig(libavformat)
32
-BuildRequires: libtag-devel
33
-BuildRequires: libebur128-devel
34
-BuildRequires: libinih-devel
35
-BuildRequires: fmt-devel
36
-BuildRoot: %{_tmppath}/%{name}-%{version}-build
37
+BuildRequires: pkgconfig(libebur128)
38
+BuildRequires: pkgconfig(taglib)
39
+%if 0%{?suse_version} > 1500
40
+BuildRequires: gcc-c++
41
+%else
42
+BuildRequires: gcc13-c++
43
+%endif
44
45
%description
46
A modern ReplayGain 2.0 loudness normalizer utility
47
48
%prep
49
-%setup -q
50
+%autosetup -p1
51
52
%build
53
-%cmake \
54
- -DCMAKE_CXX_COMPILER='/usr/bin/g++-12' \
55
- -DCMAKE_BUILD_TYPE=Release
56
+export CXX=g++
57
+test -x "$(type -p g++-13)" && export CXX=g++-13
58
+%cmake
59
%cmake_build
60
61
%install
62
%cmake_install
63
64
+%check
65
+
66
%files
67
+%license LICENSE LICENSE-CRCpp
68
+%doc CHANGELOG README.md
69
%dir %{_datadir}/%{name}
70
%dir %{_datadir}/%{name}/presets
71
%{_bindir}/rsgain
72
rsgain-3.3-source.tar.xz/.github/workflows/build.yml -> rsgain-3.5.1.tar.gz/.github/workflows/build.yml
Changed
220
1
2
3
workflow_dispatch:
4
5
-defaults:
6
- run:
7
- shell: bash
8
-
9
permissions:
10
actions: none
11
checks: none
12
13
repository-projects: none
14
security-events: none
15
statuses: read
16
+defaults:
17
+ run:
18
+ shell: bash
19
+env:
20
+ VCPKG_COMMITTISH: 01f602195983451bc83e72f4214af2cbc495aa94
21
22
jobs:
23
build_windows:
24
25
runs-on: windows-2022
26
strategy:
27
fail-fast: false
28
-
29
env:
30
CMAKE_BUILD_TYPE: Release
31
CMAKE_GENERATOR: Visual Studio 17 2022
32
33
uses: actions/checkout@v3
34
with:
35
submodules: true
36
+ fetch-depth: 0
37
38
- name: Setup vcpkg
39
uses: friendlyanon/setup-vcpkg@v1
40
- with: { committish: 4f9d25a7f299db656c376af402637819ee2caba0 }
41
+ with:
42
+ committish: ${{env.VCPKG_COMMITTISH}}
43
44
- name: Setup Overlays
45
uses: actions/checkout@v3
46
47
48
- name: Configure
49
run: cmake -S . -B build
50
- -G "${{env.CMAKE_GENERATOR}}"
51
+ -G "${{env.CMAKE_GENERATOR}}"
52
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
53
+ -DVCPKG_MANIFEST_FEATURES="ffmpeg;libebur128;inih;"
54
-DVCPKG_OVERLAY_PORTS=build/overlays/ports
55
-DVCPKG_OVERLAY_TRIPLETS=config/vcpkg_triplets
56
-DVCPKG_TARGET_TRIPLET=${{env.VCPKG_TRIPLET}}
57
58
matrix:
59
config:
60
- name: Debian
61
- docker_image: debian:bullseye
62
+ docker_image: debian:bookworm
63
package_type: DEB
64
package_ext: .deb
65
+ vcpkg_features: fmt;
66
67
- name: Fedora
68
- docker_image: fedora:38
69
+ docker_image: fedora:39
70
package_type: RPM
71
package_ext: .rpm
72
+ vcpkg_features: fmt;
73
+
74
+ - name: Static
75
+ docker_image: debian:bullseye
76
+ package_type: TXZ
77
+ package_ext: .tar.xz
78
+ vcpkg_features: fmt;ffmpeg;libebur128;inih;
79
80
container:
81
image: ${{matrix.config.docker_image}}
82
83
env:
84
CMAKE_BUILD_TYPE: Release
85
- VCPKG_COMMITISH: 4f9d25a7f299db656c376af402637819ee2caba0
86
VCPKG_TRIPLET: x64-linux
87
88
steps:
89
- name: Checkout Git repository
90
uses: actions/checkout@v3
91
+ with:
92
+ fetch-depth: 0
93
94
- name: "Install dependencies"
95
run: |
96
if "${{matrix.config.name}}" == "Debian" ; then
97
- apt update && apt install -y curl zip unzip tar build-essential git cmake pkg-config libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libebur128-dev libinih-dev
98
+ apt update && apt install -y curl zip unzip gzip tar build-essential git cmake pkg-config libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libebur128-dev libinih-dev binutils
99
fi
100
if "${{matrix.config.name}}" == "Fedora" ; then
101
- dnf install -y curl zip unzip tar git make pkg-config gcc-c++ fedora-packager rpmdevtools cmake libavcodec-free-devel libavformat-free-devel libswresample-free-devel libavutil-free-devel libebur128-devel taglib-devel inih-devel
102
+ dnf install -y curl zip unzip gzip tar git make pkg-config gcc-c++ fedora-packager rpmdevtools cmake libavcodec-free-devel libavformat-free-devel libswresample-free-devel libavutil-free-devel libebur128-devel inih-devel
103
+ fi
104
+ if "${{matrix.config.name}}" == "Static" ; then
105
+ apt update && apt install -y curl zip unzip tar build-essential git cmake pkg-config python3 nasm binutils
106
fi
107
108
- name: Setup vcpkg
109
uses: friendlyanon/setup-vcpkg@v1
110
with:
111
- committish: ${{env.VCPKG_COMMITISH}}
112
+ committish: ${{env.VCPKG_COMMITTISH}}
113
cache-key: vcpkg-${{matrix.config.name}}-${{env.VCPKG_COMMITISH}}
114
cache-restore-keys: vcpkg-${{matrix.config.name}}-${{env.VCPKG_COMMITISH}}
115
116
+ - name: Setup Overlays
117
+ uses: actions/checkout@v3
118
+ with:
119
+ repository: complexlogic/vcpkg
120
+ ref: refs/heads/rsgain
121
+ path: build/overlays
122
+
123
- name: Configure
124
run: cmake -S . -B build
125
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
126
-DVCPKG_TARGET_TRIPLET=${{env.VCPKG_TRIPLET}}
127
+ -DVCPKG_MANIFEST_FEATURES="${{matrix.config.vcpkg_features}}"
128
+ -DVCPKG_OVERLAY_PORTS=build/overlays/ports
129
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}}
130
-DCMAKE_INSTALL_PREFIX=/usr
131
-DPACKAGE=${{matrix.config.package_type}}
132
+ -DSTRIP_BINARY=ON
133
+ -DINSTALL_MANPAGE=${{matrix.config.name == 'Debian' && 'ON' || 'OFF'}}
134
135
- name: Build
136
run: |
137
138
packages: write
139
strategy:
140
fail-fast: false
141
+ matrix:
142
+ config:
143
+ - name: Intel
144
+ OSX_ARCH: x86_64
145
+ VCPKG_TRIPLET: x64-osx
146
+
147
+ - name: Apple Silicon
148
+ OSX_ARCH: arm64
149
+ VCPKG_TRIPLET: arm64-osx
150
151
env:
152
CMAKE_BUILD_TYPE: Release
153
154
steps:
155
- name: Checkout Git repository
156
uses: actions/checkout@v3
157
+ with:
158
+ fetch-depth: 0
159
160
- - name: "Install dependencies"
161
- run: |
162
- /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
163
- brew install libebur128 taglib ffmpeg fmt inih cmake pkg-config || true
164
+ - name: Install Dependencies
165
+ run: brew install nasm automake autoconf-archive ninja
166
+
167
+ - name: Setup vcpkg
168
+ uses: friendlyanon/setup-vcpkg@v1
169
+ with:
170
+ committish: ${{env.VCPKG_COMMITTISH}}
171
+ cache-key: vcpkg-${{matrix.config.name}}-${{env.VCPKG_COMMITISH}}
172
+ cache-restore-keys: vcpkg-${{matrix.config.name}}-${{env.VCPKG_COMMITISH}}
173
+
174
+ - name: Setup Overlays
175
+ uses: actions/checkout@v3
176
+ with:
177
+ repository: complexlogic/vcpkg
178
+ ref: refs/heads/rsgain
179
+ path: build/overlays
180
181
- name: Configure
182
run: cmake -S . -B build
183
- -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}}
184
- -DCMAKE_INSTALL_PREFIX=/usr
185
+ -DCMAKE_BUILD_TYPE=Release
186
+ -DCMAKE_OSX_ARCHITECTURES=${{matrix.config.OSX_ARCH}}
187
+ -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
188
+ -DVCPKG_OVERLAY_PORTS=build/overlays/ports
189
+ -DVCPKG_TARGET_TRIPLET=${{matrix.config.VCPKG_TRIPLET}}
190
+ -DVCPKG_MANIFEST_FEATURES="fmt;ffmpeg;libebur128;inih;"
191
+ -DSTRIP_BINARY=ON
192
+ -DPACKAGE=ZIP
193
+ -DCPACK_SYSTEM_NAME="macOS-${{matrix.config.OSX_ARCH}}"
194
195
- name: Build
196
run: |
197
cmake \
198
--build build \
199
- --config ${{env.CMAKE_BUILD_TYPE}}
200
- build/rsgain -v
201
+ --target package
202
+
203
+ - name: Test
204
+ if: ${{matrix.config.OSX_ARCH == 'x86_64'}}
205
+ run: build/rsgain -v
206
+
207
+ - name: Upload Package
208
+ uses: actions/upload-artifact@v3
209
+ with:
210
+ name: macOS ${{matrix.config.name}} build
211
+ path: build/*.zip
212
+
213
+ - name: Release
214
+ uses: softprops/action-gh-release@v1
215
+ if: startsWith(github.ref, 'refs/tags/')
216
+ with:
217
+ files: build/*.zip
218
+ token: ${{secrets.ACTIONS_SECRET}}
219
\ No newline at end of file
220
rsgain-3.3-source.tar.xz/CHANGELOG -> rsgain-3.5.1.tar.gz/CHANGELOG
Changed
30
1
2
+v3.5.1 (2024-06-08)
3
+- Fix header gain calculation for multichannel Opus files
4
+- Static builds: Upgrade to FFmpeg 7
5
+
6
+v3.5 (2024-02-25)
7
+- Add -p option to preserve file modification times
8
+- In Custom Mode, immediately fail if any file in the list does not exist or is of unsupported type
9
+- Fix segfault that occurs when attempting to tag corrupted MP4 files
10
+- Provide static builds for macOS and Linux
11
+- Unix: Include optional manpage with installation
12
+- Windows: Support long paths
13
+- Static builds: Upgrade to TagLib 2
14
+
15
+v3.4 (2023-09-11)
16
+- Added support for Tom's lossless Audio Kompressor (TAK) format
17
+- Added -O option 'a' which sorts the output by filename alphanumerically
18
+- Added Custom Mode -o option 's' which forces Opus files to normalize to -23 LUFS regardless of the target loudness setting
19
+- Support files with .mp4 file extension
20
+ - Introduce Easy Mode preset option "SkipMP4" which allows users to opt out of the new behavior
21
+- When scanning completely silent tracks, the program now writes "0.00 dB" and "0.000000" as gain and peak tags, respectively. Previously, the program would completely skip over these files without writing any tags to them
22
+ - Silent tracks are not included in album gain calculations to keep results consistent with previous versions
23
+- -I 'keep' mode now default in both Custom Mode and Easy Mode
24
+- Fix TagMode 'n' option (regression from v3.2)
25
+
26
+
27
v3.3 (2023-04-23)
28
- New -I mode 'keep' detects the file's existing ID3v2 version, and preserves it
29
- Less disruptive to files, less prone to data loss as TagLib sometimes discards frames when converting between ID3v2 versions.
30
rsgain-3.3-source.tar.xz/CMakeLists.txt -> rsgain-3.5.1.tar.gz/CMakeLists.txt
Changed
190
1
2
# This file is released under the 2 clause BSD license, see COPYING
3
4
cmake_minimum_required(VERSION 3.13)
5
+option(VCPKG "Build dependencies with vcpkg" OFF)
6
+if (VCPKG)
7
+ include("${CMAKE_SOURCE_DIR}/config/vcpkg.cmake")
8
+endif ()
9
+
10
project(rsgain
11
- VERSION 3.3
12
+ VERSION 3.5.1
13
DESCRIPTION "ReplayGain 2.0 loudness normalizer"
14
HOMEPAGE_URL "https://github.com/complexlogic/rsgain"
15
LANGUAGES CXX
16
17
set(MAXPROGBARWIDTH "0" CACHE STRING "Maximum width of progress bar")
18
option(UCHECKMARKS "Enable use of Unicode checkmarks" ON)
19
option(EXTRA_WARNINGS "Enable extra compiler warnings" OFF)
20
+option(INSTALL_MANPAGE "Install man page (requires gzip)" OFF)
21
if (EXTRA_WARNINGS)
22
if (MSVC)
23
add_compile_options(/W4 /WX)
24
25
set(EXECUTABLE_TITLE "rsgain")
26
include_directories(${PROJECT_BINARY_DIR})
27
add_compile_definitions("$<$<CONFIG:DEBUG>:DEBUG>")
28
+if (WIN32)
29
+ set (USE_STD_FORMAT true)
30
+ if (MSVC_VERSION AND MSVC_VERSION VERSION_LESS 1937)
31
+ message(FATAL_ERROR "Visual Studio 17.7 and later supported only")
32
+ endif ()
33
+endif ()
34
+if (USE_STD_FORMAT)
35
+ if (UNIX)
36
+ include(CheckIncludeFiles)
37
+ CHECK_INCLUDE_FILES("format;print" SUPPORT_STD_FORMAT LANGUAGE CXX)
38
+ if (NOT SUPPORT_STD_FORMAT)
39
+ message(FATAL_ERROR "You do not have the required system headers for std::format and/or std::print")
40
+ endif ()
41
+ endif ()
42
+ add_compile_definitions(USE_STD_FORMAT)
43
+ set(CMAKE_CXX_STANDARD 23)
44
+endif ()
45
46
# GCC 9 and earlier are not supported due to C++20 features
47
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10)
48
49
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${EXECUTABLE_TITLE})
50
endif ()
51
52
+# Embed Git information
53
+find_package(Git QUIET)
54
+if (Git_FOUND)
55
+ execute_process(COMMAND "${GIT_EXECUTABLE}" describe --long --tags
56
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
57
+ OUTPUT_VARIABLE GIT_OUTPUT
58
+ RESULT_VARIABLE GIT_RESULT
59
+ OUTPUT_STRIP_TRAILING_WHITESPACE
60
+ )
61
+ if (GIT_RESULT EQUAL 0)
62
+ string(REPLACE "-" ";" GIT_LIST "${GIT_OUTPUT}")
63
+ list(GET GIT_LIST 1 COMMITS_SINCE_TAG)
64
+ if (NOT COMMITS_SINCE_TAG STREQUAL "0")
65
+ list(GET GIT_LIST 2 COMMIT_HASH)
66
+ string(REPLACE "g" "" COMMIT_HASH "${COMMIT_HASH}")
67
+ add_compile_definitions(COMMITS_SINCE_TAG=\"${COMMITS_SINCE_TAG}\")
68
+ add_compile_definitions(COMMIT_HASH=\"${COMMIT_HASH}\")
69
+ endif ()
70
+ endif ()
71
+endif ()
72
+
73
# Find dependencies - Windows
74
if (WIN32)
75
find_path(FFMPEG_INCLUDE_DIR "libavformat/avformat.h" REQUIRED)
76
77
find_library(TAGLIB tag REQUIRED)
78
find_path(LIBEBUR128_INCLUDE_DIR "ebur128.h" REQUIRED)
79
find_library(LIBEBUR128 ebur128 REQUIRED)
80
- find_path(FMT_INCLUDE_DIR "fmt/core.h" REQUIRED)
81
- find_library(FMT fmt REQUIRED)
82
find_path(GETOPT_INCLUDE_DIR "getopt.h" REQUIRED)
83
find_library(GETOPT getopt REQUIRED)
84
find_path(INIH_INCLUDE_DIR "ini.h" REQUIRED)
85
86
87
# Find dependencies - Linux/Mac
88
elseif (UNIX)
89
- if (APPLE)
90
- link_directories(/usr/local/lib) # Fix linking on 10.14+. See https://stackoverflow.com/questions/54068035
91
- endif (APPLE)
92
-
93
find_package(PkgConfig MODULE REQUIRED)
94
set(THREADS_PREFER_PTHREAD_FLAG ON)
95
find_package(Threads REQUIRED)
96
97
pkg_check_modules(TAGLIB REQUIRED IMPORTED_TARGET taglib>=1.11.1)
98
pkg_check_modules(LIBEBUR128 REQUIRED IMPORTED_TARGET libebur128>=1.2.4)
99
pkg_check_modules(INIH REQUIRED IMPORTED_TARGET inih)
100
- pkg_check_modules(FMT REQUIRED IMPORTED_TARGET fmt)
101
+ if (STRIP_BINARY)
102
+ find_program(STRIP strip REQUIRED)
103
+ endif ()
104
+ if (INSTALL_MANPAGE)
105
+ find_program(GZIP gzip REQUIRED)
106
+ endif ()
107
+ if (NOT USE_STD_FORMAT)
108
+ pkg_check_modules(FMT REQUIRED IMPORTED_TARGET fmt)
109
+ endif ()
110
endif()
111
112
# Generate Windows application manifest and resource file
113
114
# Installation - Windows
115
if (WIN32)
116
install(DIRECTORY ${PROJECT_BINARY_DIR}/$<CONFIG>/ DESTINATION .)
117
- foreach(item CHANGELOG LICENSE)
118
+ foreach(item CHANGELOG LICENSE LICENSE-CRCpp)
119
configure_file("${PROJECT_SOURCE_DIR}/${item}" "${PROJECT_BINARY_DIR}/${item}.txt")
120
install(FILES "${PROJECT_BINARY_DIR}/${item}.txt" DESTINATION .)
121
endforeach ()
122
123
# Installation - Linux/Mac
124
elseif (UNIX)
125
install(TARGETS ${EXECUTABLE_TITLE} DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
126
+ if (INSTALL_MANPAGE)
127
+ install(FILES "${PROJECT_BINARY_DIR}/${EXECUTABLE_TITLE}.1.gz" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1")
128
+ endif ()
129
install(DIRECTORY "${PROJECT_SOURCE_DIR}/config/presets" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${EXECUTABLE_TITLE}")
130
+ if (PACKAGE STREQUAL "TXZ" OR PACKAGE STREQUAL "ZIP")
131
+ set(BINARY_PREFIX ".")
132
+ set(PRESETS_PREFIX ".")
133
+ else ()
134
+ set(BINARY_PREFIX "${CMAKE_INSTALL_PREFIX}/bin")
135
+ set(PRESETS_PREFIX "${CMAKE_INSTALL_PREFIX}/share/${EXECUTABLE_TITLE}")
136
+ endif ()
137
+ install(TARGETS ${EXECUTABLE_TITLE} DESTINATION "${BINARY_PREFIX}")
138
+ install(DIRECTORY "${PROJECT_SOURCE_DIR}/config/presets" DESTINATION "${PRESETS_PREFIX}")
139
set(PRESETS_DIR ${CMAKE_INSTALL_PREFIX}/share/${EXECUTABLE_TITLE}/presets)
140
141
# Build Debian packages
142
if (PACKAGE STREQUAL "DEB")
143
set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
144
- set(CPACK_DEBIAN_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION})
145
- set(CPACK_DEBIAN_PACKAGE_DEPENDS "libavcodec58 (>= 4.2.4), libavutil56 (>= 4.2.4), libswresample3 (>= 4.2.4), libavformat58 (>= 4.2.4), libebur128-1 (>=1.2.4), libinih1, libc6 (>=2.29), libstdc++6 (>=10.2), zlib1g")
146
+ if (COMMITS_SINCE_TAG AND COMMIT_HASH)
147
+ set(CPACK_DEBIAN_PACKAGE_VERSION "${PROJECT_VERSION}-r${COMMITS_SINCE_TAG}-${COMMIT_HASH}")
148
+ endif ()
149
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "libavcodec59 (>= 5.1), libavutil57 (>= 5.1), libswresample4 (>= 5.1), libavformat59 (>= 5.1), libebur128-1 (>=1.2.4), libinih1, libc6 (>=2.29), libstdc++6 (>=10.2), zlib1g")
150
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "complexlogic")
151
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
152
set(CPACK_DEBIAN_ARCHIVE_TYPE "gnutar")
153
154
# Build Fedora packages
155
elseif (PACKAGE STREQUAL "RPM")
156
set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
157
+ if (COMMITS_SINCE_TAG AND COMMIT_HASH)
158
+ set(CPACK_RPM_PACKAGE_VERSION "${PROJECT_VERSION}-r${COMMITS_SINCE_TAG}-${COMMIT_HASH}")
159
+ endif ()
160
set(CPACK_RPM_PACKAGE_LICENSE "BSD")
161
set(CPACK_RPM_PACKAGE_GROUP "Applications/Multimedia")
162
set(CPACK_RPM_PACKAGE_AUTOREQPROV 0)
163
- set(CPACK_RPM_PACKAGE_REQUIRES "libavcodec-free >= 6, libavformat-free >= 56, libswresample-free >= 6, libavutil-free >= 6, libebur128, zlib, inih")
164
+ set(CPACK_RPM_PACKAGE_REQUIRES "libavcodec-free >= 6, libavformat-free >= 6, libswresample-free >= 6, libavutil-free >= 6, libebur128, zlib, inih")
165
+ elseif (PACKAGE STREQUAL "TXZ")
166
+ set(CPACK_ARCHIVE_FILE_EXTENSION ".tar.xz")
167
endif ()
168
if (PACKAGE)
169
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_DESCRIPTION})
170
171
include(CPack)
172
endif ()
173
174
- # Provide 'uninstall' target
175
- if(NOT TARGET uninstall)
176
- configure_file(
177
- "${PROJECT_SOURCE_DIR}/config/cmake_uninstall.cmake.in"
178
- "${PROJECT_BINARY_DIR}/cmake_uninstall.cmake"
179
- IMMEDIATE @ONLY)
180
- add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${PROJECT_BINARY_DIR}/cmake_uninstall.cmake)
181
- endif()
182
+ configure_file(
183
+ "${PROJECT_SOURCE_DIR}/config/cmake_uninstall.cmake.in"
184
+ "${PROJECT_BINARY_DIR}/cmake_uninstall.cmake"
185
+ IMMEDIATE @ONLY)
186
+ add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${PROJECT_BINARY_DIR}/cmake_uninstall.cmake)
187
endif()
188
189
configure_file("${PROJECT_SOURCE_DIR}/config/config.h.in" "${PROJECT_BINARY_DIR}/config.h")
190
rsgain-3.3-source.tar.xz/Dockerfile -> rsgain-3.5.1.tar.gz/Dockerfile
Changed
10
1
2
-FROM debian
3
+FROM debian:bookworm
4
5
-ARG VERSION=3.3 \
6
+ARG VERSION=3.5.1 \
7
ARCH=amd64
8
9
RUN apt-get update && \
10
rsgain-3.5.1.tar.gz/LICENSE-CRCpp
Added
30
1
2
+CRC++
3
+Copyright (c) 2022, Daniel Bahr
4
+All rights reserved.
5
+
6
+Redistribution and use in source and binary forms, with or without
7
+modification, are permitted provided that the following conditions are met:
8
+
9
+* Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+* Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+* Neither the name of CRC++ nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
rsgain-3.3-source.tar.xz/README.md -> rsgain-3.5.1.tar.gz/README.md
Changed
271
1
2
3
1. About(#about)
4
2. Installation(#installation)
5
+ - Windows(#windows)
6
+ - macOS(#macos)
7
+ - Linux(#linux)
8
+ - FreeBSD(#freebsd)
9
+ - Android(#android)
10
+ - Docker(#docker)
11
3. Supported File Formats(#supported-file-formats)
12
4. Usage(#usage)
13
- Easy Mode(#easy-mode)
14
15
16
## About
17
18
-**rsgain** (**r**eally **s**imple **gain**) is a ReplayGain 2.0 command line utility for Windows, macOS, Linux, and BSD. rsgain applies loudness metadata tags to your files, while leaving the audio stream untouched. A ReplayGain-compatible player will dynamically adjust the volume of your tagged files during playback.
19
+**rsgain** (**r**eally **s**imple **gain**) is a ReplayGain 2.0 command line utility for Windows, macOS, Linux, BSD, and Android. rsgain applies loudness metadata tags to your files, while leaving the audio stream untouched. A ReplayGain-compatible player will dynamically adjust the volume of your tagged files during playback.
20
21
rsgain is designed with a "batteries included" philosophy, allowing a user to scan their entire music library without requiring external scripts or other tools. It aims to strike the perfect balance between power and simplicity by providing multiple user interfaces. See Usage(#usage) for more information.
22
23
24
25
## Installation
26
27
-Binary packages are available for some platforms on the Release Page(https://github.com/complexlogic/rsgain/releases). You can also build the program yourself, see BUILDING(docs/BUILDING.md).
28
+Binary packages are available on the Release Page(https://github.com/complexlogic/rsgain/releases) for Windows, macOS, and some Linux distributions. You can also build the program yourself, see BUILDING(docs/BUILDING.md).
29
30
### Windows
31
32
Download the ZIP file from the link below and extract its contents to a folder of your choice:
33
-- rsgain v3.3 portable ZIP (x64)(https://github.com/complexlogic/rsgain/releases/download/v3.3/rsgain-3.3-win64.zip)
34
+- rsgain v3.5.1 portable ZIP (x64)(https://github.com/complexlogic/rsgain/releases/download/v3.5.1/rsgain-3.5.1-win64.zip)
35
36
rsgain should be run on Windows 10 or later for full compatibility, but it can run on Windows versions as early as Vista with some caveats. See Windows Notes(#windows-notes) for more information.
37
38
39
40
#### Scoop
41
42
-rsgain can also be installed from several community Scoop buckets(https://scoop.sh/#/apps?q=rsgain&s=0&d=1&o=false). This installation method enables you to receive automatic upgrades to future versions, unlike the manual installation method described above.
43
+rsgain is available in the Scoop(https://scoop.sh/) extras bucket. Installing via Scoop enables you to receive automatic upgrades to future versions, unlike the manual installation method described above.
44
45
-### macOS
46
-
47
-There is a Homebrew formula available for macOS users. Make sure you have the latest available Xcode installed, as well as Homebrew. Then, execute the following command:
48
+First, make sure you have enabled the extras bucket. Then, install using the command below:
49
50
-```bash
51
-brew install complexlogic/tap/rsgain
52
+```powershell
53
+scoop install extras/rsgain
54
```
55
56
-### FreeBSD
57
+### macOS
58
59
-Available via ports tree or using packages (2023Q1 and later) as listed below:
60
+Separate builds are available for Apple Silicon and Intel based Macs. Both require macOS 12 (Monterey) or later. Download and extract the correct version according to your hardware:
61
+- rsgain v3.5.1 portable ZIP (Apple Silicon)(https://github.com/complexlogic/rsgain/releases/download/v3.5.1/rsgain-3.5.1-macOS-arm64.zip)
62
+- rsgain v3.5.1 portable ZIP (Intel)(https://github.com/complexlogic/rsgain/releases/download/v3.5.1/rsgain-3.5.1-macOS-x86_64.zip)
63
64
-```bash
65
-cd /usr/ports/audio/rsgain && make install clean
66
+These builds are not codesigned, and the macOS Gatekeeper will most likely block execution. To work around this, you can remove the quarantine bit using the command below:
67
68
-pkg install rsgain
69
+```bash
70
+xattr -d com.apple.quarantine /path/to/rsgain
71
```
72
73
+Substitute `/path/to/rsgain` with the actual path on your system.
74
+
75
### Linux
76
77
#### Debian/Ubuntu
78
79
-An amd64 .deb package is provided on the release page(https://github.com/complexlogic/rsgain/releases/latest). It is installable on Debian Bullseye and later, Ubuntu 21.04 and later. It can be installed with the following commands:
80
+rsgain is available as an official Debian package starting in Debian 13 (Trixie) and Ubuntu 24.04 (noble). Install via `apt`:
81
+
82
+```bash
83
+sudo apt install rsgain
84
+```
85
+
86
+There is also a .deb package for Debian Bookworm available on the release page(https://github.com/complexlogic/rsgain/releases/latest). Use the following commands to install:
87
88
```bash
89
-wget https://github.com/complexlogic/rsgain/releases/download/v3.3/rsgain_3.3_amd64.deb
90
-sudo apt install ./rsgain_3.3_amd64.deb
91
+wget https://github.com/complexlogic/rsgain/releases/download/v3.5.1/rsgain_3.5.1-1_amd64.deb
92
+sudo apt install ./rsgain_3.5.1-1_amd64.deb
93
```
94
+The above package won't work on recent Ubuntu releases due to an FFmpeg ABI break.
95
96
#### Arch/Manjaro
97
98
-There is an AUR package rsgain-git(https://aur.archlinux.org/packages/rsgain-git) based on the current `master` (which is relatively stable). You can install it with an AUR helper such as yay:
99
+rsgain is available in the AUR via the packages rsgain(https://aur.archlinux.org/packages/rsgain) and rgsain-git(https://aur.archlinux.org/packages/rsgain-git). You can install with an AUR helper such as `yay`:
100
101
```bash
102
-yay -S rsgain-git
103
+yay -S rsgain
104
```
105
106
-There is also a PKGBUILD script based on the latest release source tarball located in the `config` directory of the repo.
107
-
108
#### Fedora
109
110
-A package is available on the release page(https://github.com/complexlogic/rsgain/releases/latest) that is compatible with Fedora 38.
111
+rsgain is packaged in Fedora's repositories. You can use `dnf` to install:
112
+
113
+```bash
114
+sudo dnf install rsgain
115
+```
116
+
117
+#### Nix/NixOS
118
+
119
+`rsgain` is in nixpkgs(https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/rs/rsgain/package.nix). Some options:
120
+
121
+- Run it without installing:
122
+ ```sh
123
+ nix run nixpkgs#rsgain
124
+ ```
125
+- Install it in your Nix environment:
126
+ ```sh
127
+ nix-env -f '<nixpkgs>' -iA rsgain
128
+ ```
129
+- Add it to your NixOS configuration:
130
+ ```nix
131
+ environment.systemPackages = with pkgs; rsgain ;
132
+ ```
133
+
134
+#### Static Build
135
+
136
+An x86_64 static build is available that should run on recent releases of most GNU-based Linux distros (any distro shipping GCC 10 or later). Download the archive below and extract it to a directory of your choice:
137
+- rsgain v3.5.1 portable TAR (x86_64)(https://github.com/complexlogic/rsgain/releases/download/v3.5.1/rsgain-3.5.1-Linux.tar.xz)
138
+
139
+### FreeBSD
140
+
141
+Available via ports tree or using packages (2023Q1 and later) as listed below:
142
143
```bash
144
-sudo dnf install https://github.com/complexlogic/rsgain/releases/download/v3.3/rsgain-3.3-1.x86_64.rpm
145
+cd /usr/ports/audio/rsgain && make install clean
146
+
147
+pkg install rsgain
148
```
149
150
-#### Others
151
+### Android
152
153
-Users of other distros will need to build from source. See BUILDING(docs/BUILDING.md).
154
+rsgain can be installed on Android devices via the Termux(https://termux.dev/en/) terminal emulator package manager:
155
+
156
+```bash
157
+pkg install rsgain
158
+```
159
160
### Docker
161
162
163
164
## Supported file formats
165
166
-rsgain supports all popular file formats. See the below table for compatibility. It should be noted that rsgain sorts files internally based on file extension, so it is required that your audio files match one of the extensions in the second column of the table in order to be recognized as valid.
167
+rsgain supports all popular file formats. See the below table for compatibility. rsgain sorts files internally based on file extension, so it is required that your audio files match one of the extensions in the second column of the table in order to be recognized as valid.
168
169
| Format | Supported File Extension(s) |
170
| ------------------------------------ | --------------------------- |
171
172
| Musepack (MPC)² | .mpc |
173
| Ogg (Vorbis, Speex, FLAC) | .ogg, .oga, .spx |
174
| Opus | .opus |
175
+| Tom's lossless Audio Kompressor | .tak |
176
| Waveform Audio File Format (WAV) | .wav |
177
| Wavpack | .wv |
178
| Windows Media Audio (WMA) | .wma |
179
180
-1. *Support for HE-AAC and xHE-AAC are available via the Fraunhofer AAC library. On Windows, the statically-linked FFmpeg already includes support, so no further action is required. On Unix platforms, you will need to check if your build of FFmpeg was compiled with the '--enable-libfdk-aac' option, and compile it yourself if necessary*
181
+1. *Support for HE-AAC and xHE-AAC are available via the Fraunhofer FDK AAC library. For the static builds, the included FFmpeg was compiled with support, so no further action is required. For the dynamic builds, you will need to check if your build of FFmpeg was compiled with the '--enable-libfdk-aac' option, and compile it yourself if necessary*
182
2. *Stream Version 8 (SV8) supported only. If you have files in the older SV7 format, you can convert them losslessly to SV8*
183
184
## Usage
185
186
187
Microsoft Excel doesn't recognize the tab delimiter in CSV files by default. To enable Excel compatibility, rsgain has an option `-Os` which will add a `sep` header to the CSV file. This is a non-standard Microsoft extension which will enable the outputted CSV files to open in Excel.
188
189
+##### Sorting
190
+
191
+If you want the output sorted alphanumerically by filename, use the 'a' option, e.g. `-Oa`.
192
+
193
+The options can be chained. For example, if you want both Excel compatibility and alphanumeric sorting, you can pass `-Oas`.
194
+
195
#### Scan Presets
196
197
Easy Mode scans files with the following settings by default:
198
199
- Sample peak calculations for peak tags
200
- Clipping protection enabled for positive gain values only (0 dB max peak)
201
- Standard uppercase tags for all formats
202
-- ID3v2.3 tags for ID3 formats
203
+- Preserve the existing ID3v2 tag version for ID3 formats (e.g. MP3)
204
- Standard ReplayGain tags for Opus files
205
206
These settings are recommended for maximum compatibility with modern players. However, if you need one or more of the settings changed, you can use a preset file.
207
208
| -------------- | ---------- | ------------------ |
209
| TagMode | Character | -s |
210
| TargetLoudness | Integer | -l |
211
-| AlbumGain | Boolean | -a |
212
+| Album | Boolean | -a |
213
| ClipMode | Character | -c |
214
| TruePeak | Boolean | -t |
215
| Lowercase | Boolean | -L |
216
| ID3v2Version | Integer | -I |
217
| MaxPeakLevel | Decimal | -m |
218
| OpusMode | Character | -o |
219
+| PreserveMtimes | Booelan | -p |
220
221
See Custom Mode(#custom-mode) for more information.
222
223
224
225
The ReplayGain specification does not explicitly specify whether the peak should be calculated using the sample peak or true peak method, leaving the decision to the implementation. Comparing popular ReplayGain scanners, r128gain always uses sample peak, while loudgain always uses true peak. Conversely, rsgain allows the user to choose between the sample peak and true peak methods. The default is sample peak.
226
227
-It should be noted that using true peak instead of sample peak comes at a significant performance cost. Scans using true peak will typically be 2-4x longer than otherwise equivalent sample peak scans; the oversampling interpolation process used to calculate the true peak is very computationally intensive.
228
+Using true peak instead of sample peak comes at a significant performance cost. Scans using true peak will typically be 2-4x longer than otherwise equivalent sample peak scans; the oversampling interpolation process used to calculate the true peak is very computationally intensive.
229
230
### Clipping Protection
231
232
233
234
Additionally, there is also an "output gain" field in the header, which contains another volume adjustment that needs to be taken into account.
235
236
-To handle the complexity, rsgain has a Opus Mode setting with a 4 choice character option that determines how Opus files should be tagged:
237
+To handle the complexity, rsgain has a Opus Mode setting with a 5 choice character option that determines how Opus files should be tagged:
238
239
- `d`: Write standard ReplayGain tags, set header output gain to 0
240
- `r`: Write R128_*_GAIN tags, set header output gain to 0
241
+- `s`: Same as 'r' above, plus the target loudness is forced to -23 LUFS for Opus files only
242
- `t`: Write track gain to header output gain
243
- `a`: Write album gain to header output gain
244
245
-Note the the `r` mode does not set the target loudness to -23 LUFS as specified in RFC 7845. You will need to use the separate target loudness setting to do so.
246
-
247
Since rsgain is a *ReplayGain* scanner, the `d` mode is the default, even though the ReplayGain standard conflicts with RFC 7845. In my opinion, the authors of RFC 7845 totally overstepped their authority by specifying a format-specific loudness normalization method. Particularly egregious is the specification of a target loudness level. There is no one-size-fits-all solution for target loudness. The best value depends on the dynamic range of your music, which tends to vary by genre. Moreover, most people do not have a music library comprised entirely of a single audio format, so format-specific loudness normalization methods are inappropriate. Having Opus files play back 5 dB quieter than all other file types defeats the purpose of applying ReplayGain.
248
249
-If you do wish to write tags that are fully compliant to RFC 7845 instead of ReplayGain, use a scan preset(#scan-presets) as follows:
250
+Some players will automatically add a +5 dB pregain to Opus files to attempt to compensate for the difference in target loudness between the RFC 7845 normalization method and ReplayGain. foobar2000 and a few others are among those that do this. You'll need to research how your chosen player(s) handle Opus files, and adjust your settings in rsgain accordingly.
251
+
252
+If you wish to write tags that are fully compliant to RFC 7845 instead of ReplayGain 2.0, you can use the `-o` 's' option. For example, as an Easy Mode preset
253
254
```ini
255
Opus
256
-OpusMode=r
257
-TargetLoudness=-23
258
+OpusMode=s
259
```
260
261
### Tag casing
262
263
264
rsgain uses UTF-8 for Unicode, while Windows has historically used a subset of UTF-16. However, Microsoft added full UTF-8 support in Windows 10 version 1903(https://docs.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page). Therefore, it is strongly recommended to run rsgain on Windows 10 or later to ensure compatibility with all filenames. You can still run rsgain on Windows Vista through 8.1 if you don't need Unicode support, i.e. you don't have any filenames with non-ANSI characters.
265
266
-Another caveat with Windows is the performance of the scan progress bar. Console output on Windows is notoriously slow compared to Unix platforms. Unfortunately, the progress bar can be a bottleneck, particularly with the default sample peak calculations. I have optimized the progress bar as much as possible, it can't be optimized any further without increasing the update interval, which is undesirable. I have decided to leave it as-is, under the rationale that the performance in the single-threaded mode is less important than in multithreaded(#multithreaded-scanning), which is unaffected by this issue since the progress bar is disabled. If you do need to tag a large number of files using the single-threaded Easy Mode or Custom Mode, pass the `-q` option to disable the progress bar, which will eliminate the bottleneck.
267
+Another caveat with Windows is the performance of the scan progress bar. Console output on Windows is notoriously slow compared to Unix platforms. Unfortunately, the progress bar can be a bottleneck, particularly with the default sample peak calculations. I have decided to leave it as-is, under the rationale that the performance in the single-threaded mode is less important than in multithreaded(#multithreaded-scanning), which is unaffected by this issue since the progress bar is disabled. If you do need to tag a large number of files using the single-threaded Easy Mode or Custom Mode, pass the `-q` option to disable the progress bar, which will eliminate the bottleneck.
268
269
## License
270
271
rsgain-3.3-source.tar.xz/config/PKGBUILD -> rsgain-3.5.1.tar.gz/config/PKGBUILD
Changed
8
1
2
pkgname=rsgain
3
-pkgver=3.3
4
+pkgver=3.5.1
5
pkgrel=1
6
epoch=
7
pkgdesc="ReplayGain 2.0 loudness normalizer"
8
rsgain-3.3-source.tar.xz/config/presets/default.ini -> rsgain-3.5.1.tar.gz/config/presets/default.ini
Changed
123
1
2
MaxPeakLevel=0.0
3
TruePeak=false
4
Lowercase=false
5
-ID3v2Version=3
6
+ID3v2Version=keep
7
OpusMode=d
8
+PreserveMtimes=false
9
10
MP3
11
#TagMode=i
12
13
#MaxPeakLevel=0.0
14
#TruePeak=false
15
#Lowercase=false
16
-#ID3v2Version=3
17
+#ID3v2Version=keep
18
+#PreserveMtimes=false
19
20
FLAC
21
#TagMode=i
22
23
#ClipMode=p
24
#MaxPeakLevel=0.0
25
#TruePeak=false
26
+#PreserveMtimes=false
27
28
Ogg
29
#TagMode=i
30
31
#ClipMode=p
32
#MaxPeakLevel=0.0
33
#TruePeak=false
34
+#PreserveMtimes=false
35
36
Opus
37
#TagMode=i
38
39
#MaxPeakLevel=0.0
40
#TruePeak=false
41
#OpusMode=d
42
+#PreserveMtimes=false
43
44
M4A
45
#TagMode=i
46
47
#MaxPeakLevel=0.0
48
#TruePeak=false
49
#Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
53
WMA
54
#TagMode=i
55
56
#MaxPeakLevel=0.0
57
#TruePeak=false
58
#Lowercase=false
59
+#PreserveMtimes=false
60
61
MP2
62
#TagMode=i
63
64
#MaxPeakLevel=0.0
65
#TruePeak=false
66
#Lowercase=false
67
-#ID3v2Version=3
68
+#ID3v2Version=keep
69
+#PreserveMtimes=false
70
71
WAV
72
#TagMode=i
73
74
#MaxPeakLevel=0.0
75
#TruePeak=false
76
#Lowercase=false
77
-#ID3v2Version=3
78
+#ID3v2Version=keep
79
+#PreserveMtimes=false
80
81
AIFF
82
#TagMode=i
83
84
#MaxPeakLevel=0.0
85
#TruePeak=false
86
#Lowercase=false
87
-#ID3v2Version=3
88
+#ID3v2Version=keep
89
+#PreserveMtimes=false
90
91
Wavpack
92
#TagMode=i
93
94
#ClipMode=p
95
#MaxPeakLevel=0.0
96
#TruePeak=false
97
+#PreserveMtimes=false
98
99
APE
100
#TagMode=i
101
102
#ClipMode=p
103
#MaxPeakLevel=0.0
104
#TruePeak=false
105
+#PreserveMtimes=false
106
+
107
+TAK
108
+#TagMode=i
109
+#Album=true
110
+#TargetLoudness=-18
111
+#ClipMode=p
112
+#MaxPeakLevel=0.0
113
+#TruePeak=false
114
+#PreserveMtimes=false
115
116
Musepack
117
#TagMode=i
118
119
#ClipMode=p
120
#MaxPeakLevel=0.0
121
#TruePeak=false
122
+#PreserveMtimes=false
123
rsgain-3.3-source.tar.xz/config/presets/ebur128.ini -> rsgain-3.5.1.tar.gz/config/presets/ebur128.ini
Changed
123
1
2
MaxPeakLevel=-1.0
3
TruePeak=true
4
Lowercase=false
5
-ID3v2Version=3
6
+ID3v2Version=keep
7
OpusMode=d
8
+PreserveMtimes=false
9
10
MP3
11
#TagMode=i
12
13
#MaxPeakLevel=-1.0
14
#TruePeak=true
15
#Lowercase=false
16
-#ID3v2Version=3
17
+#ID3v2Version=keep
18
+#PreserveMtimes=false
19
20
FLAC
21
#TagMode=i
22
23
#ClipMode=p
24
#MaxPeakLevel=-1.0
25
#TruePeak=true
26
+#PreserveMtimes=false
27
28
Ogg
29
#TagMode=i
30
31
#ClipMode=p
32
#MaxPeakLevel=-1.0
33
#TruePeak=true
34
+#PreserveMtimes=false
35
36
Opus
37
#TagMode=i
38
39
#MaxPeakLevel=-1.0
40
#TruePeak=true
41
#OpusMode=d
42
+#PreserveMtimes=false
43
44
M4A
45
#TagMode=i
46
47
#MaxPeakLevel=-1.0
48
#TruePeak=true
49
#Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
53
WMA
54
#TagMode=i
55
56
#MaxPeakLevel=-1.0
57
#TruePeak=true
58
#Lowercase=false
59
+#PreserveMtimes=false
60
61
MP2
62
#TagMode=i
63
64
#MaxPeakLevel=-1.0
65
#TruePeak=true
66
#Lowercase=false
67
-#ID3v2Version=3
68
+#ID3v2Version=keep
69
+#PreserveMtimes=false
70
71
WAV
72
#TagMode=i
73
74
#MaxPeakLevel=-1.0
75
#TruePeak=true
76
#Lowercase=false
77
-#ID3v2Version=3
78
+#ID3v2Version=keep
79
+#PreserveMtimes=false
80
81
AIFF
82
#TagMode=i
83
84
#MaxPeakLevel=-1.0
85
#TruePeak=true
86
#Lowercase=false
87
-#ID3v2Version=3
88
+#ID3v2Version=keep
89
+#PreserveMtimes=false
90
91
Wavpack
92
#TagMode=i
93
94
#ClipMode=p
95
#MaxPeakLevel=-1.0
96
#TruePeak=true
97
+#PreserveMtimes=false
98
99
APE
100
#TagMode=i
101
102
#ClipMode=p
103
#MaxPeakLevel=-1.0
104
#TruePeak=true
105
+#PreserveMtimes=false
106
+
107
+TAK
108
+#TagMode=i
109
+#Album=true
110
+#TargetLoudness=-23
111
+#ClipMode=p
112
+#MaxPeakLevel=-1.0
113
+#TruePeak=true
114
+#PreserveMtimes=false
115
116
Musepack
117
#TagMode=i
118
119
#ClipMode=p
120
#MaxPeakLevel=0.0
121
#TruePeak=false
122
+#PreserveMtimes=false
123
rsgain-3.3-source.tar.xz/config/presets/loudgain.ini -> rsgain-3.5.1.tar.gz/config/presets/loudgain.ini
Changed
112
1
2
Lowercase=true
3
ID3v2Version=3
4
OpusMode=r
5
+PreserveMtimes=false
6
7
MP3
8
#TagMode=i
9
10
#TruePeak=true
11
#Lowercase=true
12
#ID3v2Version=3
13
+#PreserveMtimes=false
14
15
FLAC
16
#TagMode=i
17
18
#ClipMode=a
19
#MaxPeakLevel=-1.0
20
#TruePeak=true
21
+#PreserveMtimes=false
22
23
Ogg
24
#TagMode=i
25
26
#ClipMode=a
27
#MaxPeakLevel=-1.0
28
#TruePeak=true
29
+#PreserveMtimes=false
30
31
Opus
32
#TagMode=i
33
34
#MaxPeakLevel=-1.0
35
#TruePeak=true
36
#OpusMode=r
37
+#PreserveMtimes=false
38
39
M4A
40
#TagMode=i
41
42
#MaxPeakLevel=-1.0
43
#TruePeak=true
44
#Lowercase=true
45
+#SkipMP4=false
46
+#PreserveMtimes=false
47
48
WMA
49
#TagMode=i
50
51
#MaxPeakLevel=-1.0
52
#TruePeak=true
53
#Lowercase=true
54
+#PreserveMtimes=false
55
56
MP2
57
#TagMode=i
58
59
#TruePeak=true
60
#Lowercase=true
61
#ID3v2Version=3
62
+#PreserveMtimes=false
63
64
WAV
65
#TagMode=i
66
67
#TruePeak=true
68
#Lowercase=true
69
#ID3v2Version=3
70
+#PreserveMtimes=false
71
72
AIFF
73
#TagMode=i
74
75
#TruePeak=true
76
#Lowercase=true
77
#ID3v2Version=3
78
+#PreserveMtimes=false
79
80
Wavpack
81
#TagMode=i
82
83
#ClipMode=a
84
#MaxPeakLevel=-1.0
85
#TruePeak=true
86
+#PreserveMtimes=false
87
88
APE
89
#TagMode=i
90
91
#ClipMode=a
92
#MaxPeakLevel=-1.0
93
#TruePeak=true
94
+#PreserveMtimes=false
95
+
96
+TAK
97
+#TagMode=i
98
+#Album=true
99
+#TargetLoudness=-18
100
+#ClipMode=a
101
+#MaxPeakLevel=-1.0
102
+#TruePeak=true
103
+#PreserveMtimes=false
104
105
Musepack
106
#TagMode=i
107
108
#ClipMode=p
109
#MaxPeakLevel=0.0
110
#TruePeak=false
111
+#PreserveMtimes=false
112
rsgain-3.3-source.tar.xz/config/presets/no_album.ini -> rsgain-3.5.1.tar.gz/config/presets/no_album.ini
Changed
123
1
2
MaxPeakLevel=0.0
3
TruePeak=false
4
Lowercase=false
5
-ID3v2Version=3
6
+ID3v2Version=keep
7
OpusMode=d
8
+PreserveMtimes=false
9
10
MP3
11
#TagMode=i
12
13
#MaxPeakLevel=0.0
14
#TruePeak=false
15
#Lowercase=false
16
-#ID3v2Version=3
17
+#ID3v2Version=keep
18
+#PreserveMtimes=false
19
20
FLAC
21
#TagMode=i
22
23
#ClipMode=p
24
#MaxPeakLevel=0.0
25
#TruePeak=false
26
+#PreserveMtimes=false
27
28
Ogg
29
#TagMode=i
30
31
#ClipMode=p
32
#MaxPeakLevel=0.0
33
#TruePeak=false
34
+#PreserveMtimes=false
35
36
Opus
37
#TagMode=i
38
39
#MaxPeakLevel=0.0
40
#TruePeak=false
41
#OpusMode=d
42
+#PreserveMtimes=false
43
44
M4A
45
#TagMode=i
46
47
#MaxPeakLevel=0.0
48
#TruePeak=false
49
#Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
53
WMA
54
#TagMode=i
55
56
#MaxPeakLevel=0.0
57
#TruePeak=false
58
#Lowercase=false
59
+#PreserveMtimes=false
60
61
MP2
62
#TagMode=i
63
64
#MaxPeakLevel=0.0
65
#TruePeak=false
66
#Lowercase=false
67
-#ID3v2Version=3
68
+#ID3v2Version=keep
69
+#PreserveMtimes=false
70
71
WAV
72
#TagMode=i
73
74
#MaxPeakLevel=0.0
75
#TruePeak=false
76
#Lowercase=false
77
-#ID3v2Version=3
78
+#ID3v2Version=keep
79
+#PreserveMtimes=false
80
81
AIFF
82
#TagMode=i
83
84
#MaxPeakLevel=0.0
85
#TruePeak=false
86
#Lowercase=false
87
-#ID3v2Version=3
88
+#ID3v2Version=keep
89
+#PreserveMtimes=false
90
91
Wavpack
92
#TagMode=i
93
94
#ClipMode=p
95
#MaxPeakLevel=0.0
96
#TruePeak=false
97
+#PreserveMtimes=false
98
99
APE
100
#TagMode=i
101
102
#ClipMode=p
103
#MaxPeakLevel=0.0
104
#TruePeak=false
105
+#PreserveMtimes=false
106
+
107
+TAK
108
+#TagMode=i
109
+#Album=true
110
+#TargetLoudness=-18
111
+#ClipMode=p
112
+#MaxPeakLevel=0.0
113
+#TruePeak=false
114
+#PreserveMtimes=false
115
116
Musepack
117
#TagMode=i
118
119
#ClipMode=p
120
#MaxPeakLevel=0.0
121
#TruePeak=false
122
+#PreserveMtimes=false
123
rsgain-3.3-source.tar.xz/config/rsgain.manifest.in -> rsgain-3.5.1.tar.gz/config/rsgain.manifest.in
Changed
9
1
2
<application>
3
<windowsSettings>
4
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
5
+ <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
6
</windowsSettings>
7
</application>
8
</assembly>
9
rsgain-3.5.1.tar.gz/config/vcpkg.cmake
Added
33
1
2
+message("Setting up vcpkg...")
3
+include(FetchContent)
4
+FetchContent_Declare(
5
+ vcpkg
6
+ GIT_REPOSITORY https://github.com/microsoft/vcpkg.git
7
+ GIT_SHALLOW TRUE
8
+ SOURCE_DIR ${PROJECT_BINARY_DIR}
9
+)
10
+FetchContent_Declare(
11
+ vcpkg_overlay
12
+ GIT_REPOSITORY https://github.com/complexlogic/vcpkg.git
13
+ GIT_TAG origin/rsgain
14
+ GIT_SHALLOW TRUE
15
+ SOURCE_DIR ${PROJECT_BINARY_DIR}
16
+)
17
+FetchContent_MakeAvailable(vcpkg vcpkg_overlay)
18
+set(VCPKG_OVERLAY_PORTS "${CMAKE_BINARY_DIR}/_deps/vcpkg_overlay-src/ports")
19
+
20
+if (WIN32)
21
+ if (NOT VCPKG_MANIFEST_FEATURES)
22
+ set(VCPKG_MANIFEST_FEATURES ffmpeg libebur128 inih)
23
+ endif ()
24
+ if (NOT VCPKG_OVERLAY_TRIPLETS)
25
+ list(APPEND VCPKG_OVERLAY_TRIPLETS "${CMAKE_SOURCE_DIR}/config/vcpkg_triplets")
26
+ endif ()
27
+ if (NOT VCPKG_TARGET_TRIPLET)
28
+ set (VCPKG_TARGET_TRIPLET "custom-triplet")
29
+ endif ()
30
+endif ()
31
+
32
+set(CMAKE_TOOLCHAIN_FILE "${CMAKE_BINARY_DIR}/_deps/vcpkg-src/scripts/buildsystems/vcpkg.cmake")
33
rsgain-3.3-source.tar.xz/docs/BUILDING.md -> rsgain-3.5.1.tar.gz/docs/BUILDING.md
Changed
54
1
2
3
rsgain builds natively on Unix and Windows, and features a cross-platform CMake build system. The following external dependencies are required:
4
5
-- libebur128
6
-- taglib
7
+- libebur128(https://github.com/jiixyj/libebur128) or ebur128(https://github.com/sdroege/ebur128)
8
+- TagLib
9
- FFmpeg, specifically the libraries:
10
+ libavformat
11
+ libavcodec
12
+ libswresample
13
+ libavutil
14
-- fmt
15
- inih
16
+- Unix only: fmt (see below(#fmt-library))
17
18
-The source code is written in C++20, and as such requires a relatively modern compiler to build:
19
+The Windows version uses C++23, and the Unix versions use either C++20 or C++23 depending on the compiler. As such, it requires a relatively modern compiler to build:
20
21
-- On Windows, use Visual Studio 2022
22
+- On Windows, Visual Studio 2022 17.7 or later is required
23
- On Linux, use GCC 10 or later
24
- On macOS, the latest available Xcode for your machine should work
25
26
+### fmt library
27
+
28
+The features that rsgain uses from the fmt library have been integrated into the C++20 and C++23 standards, specifically the `<format>` and `<print>` headers. Currently, neither GCC nor Clang have full support those features, so the fmt libary is required. When they gain support, the fmt dependency will be dropped in favor of the C++ standard library.
29
+
30
+The features have been incorporated into Microsoft's C++ standard library implementation, so the fmt library is no longer required for the Windows version.
31
+
32
## Unix
33
34
Before starting, make sure you have the development tools Git, CMake and pkg-config installed.
35
36
### FreeBSD (Packages)
37
38
```bash
39
-pkg install libebur128 taglib libfmt inih ffmpeg
40
+pkg install ebur128 taglib libfmt inih ffmpeg
41
```
42
43
### Building
44
45
Build the dependencies and generate the Visual Studio project files:
46
47
```bash
48
-git clone https://github.com/microsoft/vcpkg
49
-cmake .. -DCMAKE_TOOLCHAIN_FILE=".\vcpkg\scripts\buildsystems\vcpkg.cmake" -DVCPKG_OVERLAY_TRIPLETS="..\config\vcpkg_triplets" -DVCPKG_TARGET_TRIPLET="custom-triplet"
50
+cmake .. -DVCPKG=ON
51
```
52
53
Build and test the program:
54
rsgain-3.5.1.tar.gz/docs/rsgain.1
Added
183
1
2
+.TH "rsgain" "1" "October 2023" "" ""
3
+.
4
+.SH "NAME"
5
+\fBrsgain\fR \- ReplayGain 2\.0 loudness normalizer
6
+.
7
+.SH "SYNOPSIS"
8
+rsgain OPTIONS <command> \.\.\.
9
+.
10
+.SH "DESCRIPTION"
11
+\fBrsgain\fR (really simple gain) is a ReplayGain 2\.0 command-line utility\.
12
+.P
13
+It applies loudness metadata tags to audio and video files while leaving the audio stream untouched\.
14
+.P
15
+A ReplayGain-compatible player will dynamically adjust the volume of your tagged files during playback\.
16
+.P
17
+\fBrsgain\fR supports writing tags to the following file types:
18
+.br
19
+ \- AIFF (\.aiff, \.aif, \.snd)
20
+ \- APE (\.ape)
21
+ \- FLAC (\.flac)
22
+ \- MP2 (\.mp2)
23
+ \- MP3 (\.mp3)
24
+ \- MP4 (\.m4a)
25
+ \- Musepack (\.mpc)
26
+ \- Ogg (\.ogg, \.oga, \.spx)
27
+ \- Opus (\.opus)
28
+ \- TAK (\.tak)
29
+ \- WAV (\.wav)
30
+ \- WavPack (\.wv)
31
+ \- WMA (\.wma)\.
32
+.
33
+.SS "OPTIONS AND COMMANDS"
34
+.TP
35
+\fB\-h\fR, \fB\-\-help\fR
36
+Show help\.
37
+.TP
38
+\fB\-v\fR, \fB\-\-version\fR
39
+Show version number\.
40
+.TP
41
+\fBeasy\fR
42
+Easy Mode:
43
+.br
44
+Recursively scan a directory with recommended settings\.
45
+.TP
46
+\fBcustom\fR
47
+Custom Mode:
48
+.br
49
+Scan individual files with custom settings\.
50
+.P
51
+Run \fBrsgain easy \-\-help\fR or \fBrsgain custom \-\-help\fR for more information\.
52
+.
53
+.SH "EASY MODE"
54
+Usage: rsgain easy OPTIONS DIRECTORY
55
+.P
56
+Easy Mode recursively scans a directory using the recommended settings for each file type\.
57
+.P
58
+Easy Mode assumes that you have your music library organized with each album in its own folder\.
59
+.
60
+.SS "OPTIONS"
61
+.TP
62
+\fB\-h\fR, \fB\-\-help\fR
63
+Show help\.
64
+.TP
65
+\fB\-q\fR, \fB\-\-quiet\fR
66
+Don't print scanning status messages\.
67
+.TP
68
+\fB\-S\fR, \fB\-\-skip\-existing\fR
69
+Don't scan files with existing ReplayGain information\.
70
+.TP
71
+\fB\-m n\fR, \fB\-\-multithread=n\fR
72
+Scan files with \fBn\fR parallel threads\.
73
+.TP
74
+\fB\-p s\fR, \fB\-\-preset=s\fR
75
+Load scan preset \fBs\fR\.
76
+.TP
77
+\fB\-O\fR, \fB\-\-output\fR
78
+Output tab\-delimited scan data to CSV file per directory\.
79
+.TP
80
+\fB\-O s\fR, \fB\-\-output=s\fR
81
+Output with sep header (needed for Microsoft Excel compatibility)\.
82
+.TP
83
+\fB\-O a\fR, \fB\-\-output=a\fR
84
+Output with files sorted in alphanumeric order\.
85
+.
86
+.SH "CUSTOM MODE"
87
+Usage: rsgain custom OPTIONS FILES\.\.\.
88
+.P
89
+Custom Mode allows the user to specify the options to scan files with\.
90
+.P
91
+The list of files to scan must be listed explicitly after the options\.
92
+.
93
+.SS "OPTIONS"
94
+.TP
95
+\fB\-h\fR, \fB\-\-help\fR
96
+Show help\.
97
+.TP
98
+\fB\-a\fR, \fB\-\-album\fR
99
+Calculate album gain and peak\.
100
+.TP
101
+\fB\-S\fR, \fB\-\-skip\-existing\fR
102
+Don't scan files with existing ReplayGain information\.
103
+.TP
104
+\fB\-s s\fR, \fB\-\-tagmode=s\fR
105
+Scan files but don't write ReplayGain tags (default)\.
106
+.TP
107
+\fB\-s d\fR, \fB\-\-tagmode=d\fR
108
+Delete ReplayGain tags from files\.
109
+.TP
110
+\fB\-s i\fR, \fB\-\-tagmode=i\fR
111
+Scan and write ReplayGain 2\.0 tags to files\.
112
+.TP
113
+\fB-l n\fR, \fB\-\-loudness=n\fR
114
+Use \fBn\fR LUFS as target loudness (-30 ≤ n ≤ -5)\.
115
+.TP
116
+\fB\-c n\fR, \fB\-\-clip-mode=n\fR
117
+No clipping protection (default)\.
118
+.TP
119
+\fB\-c p\fR, \fB\-\-clip\-mode=p\fR
120
+Clipping protection enabled for positive\-gain values only\.
121
+.TP
122
+\fB\-c a\fR, \fB\-\-clip\-mode=a\fR
123
+Clipping protection always enabled\.
124
+.TP
125
+\fB\-m n\fR, \fB\-\-max\-peak=n\fR
126
+Use max peak level \fBn\fR dB for clipping protection\.
127
+.TP
128
+\fB\-t\fR, \fB\-\-true\-peak\fR
129
+Use true peak for peak calculations\.
130
+.TP
131
+\fB\-L\fR, \fB\-\-lowercase\fR
132
+Write lowercase tags (MP2/MP3/MP4/WMA/WAV/AIFF)\.
133
+.br
134
+This is non\-standard but sometimes needed\.
135
+.TP
136
+\fB\-I keep\fR, \fB\-\-id3v2\-version=keep\fR
137
+Keep file's existing ID3v2 version, 3 if none exists (default)\.
138
+.TP
139
+\fB\-I 3\fR, \fB\-\-id3v2\-version=3\fR
140
+Write ID3v2\.3 tags to MP2/MP3/WAV/AIFF\.
141
+.TP
142
+\fB\-I 4\fR, \fB\-\-id3v2\-version=4\fR
143
+Write ID3v2\.4 tags to MP2/MP3/WAV/AIFF\.
144
+.TP
145
+\fB\-o d\fR, \fB\-\-opus\-mode=d\fR
146
+Write standard ReplayGain tags, clear header output gain (default)\.
147
+.TP
148
+\fB\-o r\fR, \fB\-\-opus\-mode=r\fR
149
+Write R128_*_GAIN tags, clear header output gain\.
150
+.TP
151
+\fB\-o s\fR, \fB\-\-opus\-mode=s\fR
152
+Same as 'r', plus override target loudness to \-23 LUFS\.
153
+.TP
154
+\fB\-o t\fR, \fB\-\-opus\-mode=t\fR
155
+Write track gain to header output gain\.
156
+.TP
157
+\fB\-o a\fR, \fB\-\-opus\-mode=a\fR
158
+Write album gain to header output gain\.
159
+.TP
160
+\fB\-O\fR, \fB\-\-output\fR
161
+Output tab\-delimited scan data to stdout\.
162
+.TP
163
+\fB\-O s\fR, \fB\-\-output=s\fR
164
+Output with sep header (needed for Microsoft Excel compatibility)\.
165
+.TP
166
+\fB\-O a\fR, \fB\-\-output=a\fR
167
+Output with files sorted in alphanumeric order\.
168
+.TP
169
+\fB\-p\fR, \fB\-\-preserve-mtimes\fR
170
+Preserve file mtimes\.
171
+.TP
172
+\fB\-q\fR, \fB\-\-quiet\fR
173
+Don't print scanning status messages\.
174
+.
175
+.SH "BUGS"
176
+\fBrsgain\fR is maintained on GitHub. Please report all bugs to the issue tracker at https://github\.com/complexlogic/rsgain/issues\.
177
+.
178
+.SH "COPYRIGHT"
179
+Copyright (C) 2023 Hugh McMaster
180
+.
181
+.P
182
+\fBrsgain\fR is released under the BSD\-2\-Clause licence\.
183
rsgain-3.3-source.tar.xz/src/CMakeLists.txt -> rsgain-3.5.1.tar.gz/src/CMakeLists.txt
Changed
63
1
2
set(SOURCE_FILES
3
rsgain.cpp
4
+ rsgain.hpp
5
scan.cpp
6
+ scan.hpp
7
output.cpp
8
+ output.hpp
9
tag.cpp
10
+ tag.hpp
11
easymode.cpp
12
+ easymode.hpp
13
)
14
if (WIN32)
15
add_executable(${EXECUTABLE_TITLE} ${SOURCE_FILES} "${PROJECT_BINARY_DIR}/rsgain.manifest" "${PROJECT_BINARY_DIR}/versioninfo.rc")
16
17
${LIBSWRESAMPLE}
18
${TAGLIB}
19
${LIBEBUR128}
20
- ${FMT}
21
${GETOPT}
22
${INIH}
23
FDK-AAC::fdk-aac
24
25
if (VCPKG_TARGET_TRIPLET STREQUAL "custom-triplet")
26
target_link_libraries(${EXECUTABLE_TITLE} ${STATIC_LIBS})
27
endif ()
28
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
29
30
elseif (UNIX)
31
add_executable(${EXECUTABLE_TITLE} ${SOURCE_FILES})
32
33
PkgConfig::TAGLIB
34
PkgConfig::LIBEBUR128
35
PkgConfig::INIH
36
- PkgConfig::FMT
37
Threads::Threads
38
)
39
+ if (NOT USE_STD_FORMAT)
40
+ target_link_libraries(${EXECUTABLE_TITLE} PkgConfig::FMT)
41
+ endif ()
42
+ if (STRIP)
43
+ add_custom_command(TARGET ${EXECUTABLE_TITLE}
44
+ POST_BUILD
45
+ COMMAND "${STRIP}" "${PROJECT_BINARY_DIR}/${EXECUTABLE_TITLE}"
46
+ )
47
+ endif ()
48
+ if (INSTALL_MANPAGE)
49
+ add_custom_command(TARGET ${EXECUTABLE_TITLE}
50
+ POST_BUILD
51
+ COMMAND "${CMAKE_COMMAND}" -E copy "${PROJECT_SOURCE_DIR}/docs/${EXECUTABLE_TITLE}.1" "${PROJECT_BINARY_DIR}"
52
+ COMMAND "${GZIP}" -f "${PROJECT_BINARY_DIR}/${EXECUTABLE_TITLE}.1"
53
+ )
54
+ endif ()
55
endif()
56
set (EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}")
57
-
58
+string(TIMESTAMP BUILD_DATE "%Y-%m-%d")
59
+add_compile_definitions("BUILD_DATE=\"${BUILD_DATE}\"")
60
if (MAXPROGBARWIDTH GREATER_EQUAL 20)
61
target_compile_definitions(${EXECUTABLE_TITLE} PUBLIC "MAXPROGBARWIDTH=${MAXPROGBARWIDTH}")
62
endif ()
63
rsgain-3.3-source.tar.xz/src/easymode.cpp -> rsgain-3.5.1.tar.gz/src/easymode.cpp
Changed
536
1
2
#endif
3
#include <ini.h>
4
#include <getopt.h>
5
-#include <fmt/core.h>
6
-#include <fmt/chrono.h>
7
8
#include <config.h>
9
#include "rsgain.hpp"
10
11
#include "scan.hpp"
12
13
#define MAX_THREAD_SLEEP 30
14
-#define HELP_STATS(title, format, ...) fmt::print(COLOR_YELLOW "{:<18} " COLOR_OFF format "\n", title ":" __VA_OPT__(,) __VA_ARGS__)
15
+#define HELP_STATS(title, format, ...) print(COLOR_YELLOW "{:<18} " COLOR_OFF format "\n", title ":" __VA_OPT__(,) __VA_ARGS__)
16
17
extern "C" {
18
int format_handler(void *user, const char *section, const char *name, const char *value);
19
20
.do_album = true,
21
.tab_output = OutputType::NONE,
22
.sep_header = false,
23
+ .sort_alphanum = false,
24
.lowercase = false,
25
- .id3v2version = 3,
26
- .opus_mode = 'd'
27
+ .id3v2version = ID3V2_KEEP,
28
+ .opus_mode = 'd',
29
+ .skip_mp4 = false
30
},
31
32
// MP2 config
33
34
.do_album = true,
35
.tab_output = OutputType::NONE,
36
.sep_header = false,
37
+ .sort_alphanum = false,
38
.lowercase = false,
39
- .id3v2version = 3,
40
- .opus_mode = 'd'
41
+ .id3v2version = ID3V2_KEEP,
42
+ .opus_mode = 'd',
43
+ .skip_mp4 = false
44
},
45
46
// MP3 config
47
48
.do_album = true,
49
.tab_output = OutputType::NONE,
50
.sep_header = false,
51
+ .sort_alphanum = false,
52
.lowercase = false,
53
- .id3v2version = 3,
54
- .opus_mode = 'd'
55
+ .id3v2version = ID3V2_KEEP,
56
+ .opus_mode = 'd',
57
+ .skip_mp4 = false
58
},
59
60
// FLAC config
61
62
.do_album = true,
63
.tab_output = OutputType::NONE,
64
.sep_header = false,
65
+ .sort_alphanum = false,
66
.lowercase = false,
67
- .id3v2version = 3,
68
- .opus_mode = 'd'
69
+ .id3v2version = ID3V2_KEEP,
70
+ .opus_mode = 'd',
71
+ .skip_mp4 = false
72
},
73
74
// OGG config
75
76
.do_album = true,
77
.tab_output = OutputType::NONE,
78
.sep_header = false,
79
+ .sort_alphanum = false,
80
.lowercase = false,
81
- .id3v2version = 3,
82
- .opus_mode = 'd'
83
+ .id3v2version = ID3V2_KEEP,
84
+ .opus_mode = 'd',
85
+ .skip_mp4 = false
86
},
87
88
// OPUS config
89
90
.do_album = true,
91
.tab_output = OutputType::NONE,
92
.sep_header = false,
93
+ .sort_alphanum = false,
94
.lowercase = false,
95
- .id3v2version = 3,
96
- .opus_mode = 'd'
97
+ .id3v2version = ID3V2_KEEP,
98
+ .opus_mode = 'd',
99
+ .skip_mp4 = false
100
},
101
102
// M4A config
103
104
.do_album = true,
105
.tab_output = OutputType::NONE,
106
.sep_header = false,
107
+ .sort_alphanum = false,
108
.lowercase = false,
109
- .id3v2version = 3,
110
- .opus_mode = 'd'
111
+ .id3v2version = ID3V2_KEEP,
112
+ .opus_mode = 'd',
113
+ .skip_mp4 = false
114
},
115
116
// WMA config
117
118
.do_album = true,
119
.tab_output = OutputType::NONE,
120
.sep_header = false,
121
+ .sort_alphanum = false,
122
.lowercase = false,
123
- .id3v2version = 3,
124
- .opus_mode = 'd'
125
+ .id3v2version = ID3V2_KEEP,
126
+ .opus_mode = 'd',
127
+ .skip_mp4 = false
128
},
129
130
// WAV config
131
132
.do_album = true,
133
.tab_output = OutputType::NONE,
134
.sep_header = false,
135
+ .sort_alphanum = false,
136
.lowercase = false,
137
- .id3v2version = 3,
138
- .opus_mode = 'd'
139
+ .id3v2version = ID3V2_KEEP,
140
+ .opus_mode = 'd',
141
+ .skip_mp4 = false
142
},
143
144
// AIFF config
145
146
.do_album = true,
147
.tab_output = OutputType::NONE,
148
.sep_header = false,
149
+ .sort_alphanum = false,
150
.lowercase = false,
151
- .id3v2version = 3,
152
- .opus_mode = 'd'
153
+ .id3v2version = ID3V2_KEEP,
154
+ .opus_mode = 'd',
155
+ .skip_mp4 = false
156
},
157
158
// Wavpack config
159
160
.do_album = true,
161
.tab_output = OutputType::NONE,
162
.sep_header = false,
163
+ .sort_alphanum = false,
164
.lowercase = false,
165
- .id3v2version = 3,
166
- .opus_mode = 'd'
167
+ .id3v2version = ID3V2_KEEP,
168
+ .opus_mode = 'd',
169
+ .skip_mp4 = false
170
},
171
172
// APE config
173
174
.do_album = true,
175
.tab_output = OutputType::NONE,
176
.sep_header = false,
177
+ .sort_alphanum = false,
178
.lowercase = false,
179
- .id3v2version = 3,
180
- .opus_mode = 'd'
181
+ .id3v2version = ID3V2_KEEP,
182
+ .opus_mode = 'd',
183
+ .skip_mp4 = false
184
},
185
186
+ // TAK config
187
+ {
188
+ .tag_mode = 'i',
189
+ .skip_existing = false,
190
+ .target_loudness = RG_TARGET_LOUDNESS,
191
+ .max_peak_level = 0.0,
192
+ .true_peak = false,
193
+ .clip_mode = 'p',
194
+ .do_album = true,
195
+ .tab_output = OutputType::NONE,
196
+ .sep_header = false,
197
+ .sort_alphanum = false,
198
+ .lowercase = false,
199
+ .id3v2version = ID3V2_KEEP,
200
+ .opus_mode = 'd',
201
+ .skip_mp4 = false
202
+ },
203
+
204
// Musepack config
205
{
206
.tag_mode = 'i',
207
208
.do_album = true,
209
.tab_output = OutputType::NONE,
210
.sep_header = false,
211
+ .sort_alphanum = false,
212
.lowercase = false,
213
- .id3v2version = 3,
214
- .opus_mode = 'd'
215
+ .id3v2version = ID3V2_KEEP,
216
+ .opus_mode = 'd',
217
+ .skip_mp4 = false
218
}
219
};
220
221
222
223
case 'O':
224
if (optarg) {
225
- if (*optarg == 's') {
226
- for (Config &config : configs)
227
- config.sep_header = true;
228
- }
229
- else {
230
- output_fail("Unrecognized output argument '{}'", optarg);
231
- quit(EXIT_FAILURE);
232
+ const auto& sep_header, sort_alphanum = parse_output_mode(optarg);
233
+ for (Config &config : configs) {
234
+ config.sep_header = sep_header;
235
+ config.sort_alphanum = sort_alphanum;
236
}
237
}
238
for (Config &config : configs)
239
240
quit(EXIT_FAILURE);
241
}
242
243
- scan_easy(argvoptind, preset, threads);
244
+ scan_easy(argvoptind, preset ? preset : std::filesystem::path(), threads);
245
}
246
247
static bool convert_bool(const char *value, bool &setting)
248
249
{"AIFF", FileType::AIFF},
250
{"Wavpack", FileType::WAVPACK},
251
{"APE", FileType::APE},
252
+ {"TAK", FileType::TAK},
253
{"Musepack", FileType::MPC}
254
};
255
auto it = map.find(section);
256
257
else
258
quit(EXIT_FAILURE);
259
}
260
+ else if (MATCH(name, "PreserveMtimes")) {
261
+ bool preserve_mtimes;
262
+ if (convert_bool(value, preserve_mtimes)) {
263
+ for (Config &config : configs)
264
+ config.preserve_mtimes = preserve_mtimes;
265
+ }
266
+ else
267
+ quit(EXIT_FAILURE);
268
+ }
269
return 0;
270
}
271
272
273
convert_bool(value, configsstatic_cast<int>(file_type).true_peak);
274
else if (MATCH(name, "OpusMode"))
275
parse_opus_mode(value, configsstatic_cast<int>(file_type).opus_mode);
276
+ else if (file_type == FileType::M4A && MATCH(name, "SkipMP4"))
277
+ convert_bool(value, configsstatic_cast<int>(file_type).skip_mp4);
278
+ else if (MATCH(name, "PreserveMtimes"))
279
+ convert_bool(value, configsstatic_cast<int>(file_type).preserve_mtimes);
280
return 0;
281
}
282
283
-inline bool join_paths(maybe_unused std::filesystem::path &p)
284
+inline bool join_path(maybe_unused const std::filesystem::path &p)
285
{
286
return true;
287
}
288
289
template<typename... Args>
290
-inline bool join_paths(std::filesystem::path &path, const char *first, const Args&... args)
291
+inline bool join_path(std::filesystem::path &path, const std::filesystem::path &first, const Args&... args)
292
{
293
- if (!first)
294
- return false;
295
path /= first;
296
- return join_paths(path, args...);
297
+ return join_path(path, args...);
298
}
299
300
template<typename... Args>
301
-inline std::filesystem::path join_paths(const char *first, const Args&... args)
302
+inline std::filesystem::path join_paths(const std::filesystem::path &first, const Args&... args)
303
{
304
- if (!first)
305
- return std::filesystem::path();
306
std::filesystem::path path(first);
307
- return join_paths(path, args...) ? path : std::filesystem::path();
308
+ return join_path(path, args...) ? path : std::filesystem::path();
309
}
310
311
-static void load_preset(const char *preset)
312
+static void load_preset(const std::filesystem::path &preset)
313
{
314
std::filesystem::path path(preset);
315
316
// Find preset file from name
317
if (!path.has_extension()) {
318
+ std::filesystem::path preset_basename(std::move(path));
319
+ preset_basename += ".ini";
320
+
321
// Check user directory
322
#ifdef _WIN32
323
- char bufferMAX_PATH;
324
+ char buffer1024;
325
if (GetEnvironmentVariableA("USERPROFILE", buffer, sizeof(buffer)))
326
- path = join_paths(buffer, "." EXECUTABLE_TITLE, "presets", preset);
327
+ path = join_paths(buffer, "." EXECUTABLE_TITLE, "presets", preset_basename);
328
#else
329
+ const char* const home = getenv("HOME");
330
+ if (home)
331
#ifdef __APPLE__
332
- path = join_paths(getenv("HOME"), "Library", EXECUTABLE_TITLE, "presets", preset);
333
+ path = join_paths(home, "Library", EXECUTABLE_TITLE, "presets", preset_basename);
334
#else
335
- path = join_paths(getenv("HOME"), ".config", EXECUTABLE_TITLE, "presets", preset);
336
+ path = join_paths(home, ".config", EXECUTABLE_TITLE, "presets", preset_basename);
337
#endif
338
#endif
339
- path += ".ini";
340
341
// Check .exe preset folder on Windows, system directory on Unix
342
if (!std::filesystem::exists(path)) {
343
#ifdef _WIN32
344
if (GetModuleFileNameA(nullptr, buffer, sizeof(buffer))) {
345
- std::filesystem::path exe = buffer;
346
- path = join_paths(exe.parent_path().string().c_str(), "presets", preset);
347
+ std::filesystem::path exe(buffer);
348
+ path = join_paths(exe.parent_path(), "presets", preset_basename);
349
}
350
#else
351
- path = join_paths(PRESETS_DIR, preset);
352
+ path = join_paths(PRESETS_DIR, preset_basename);
353
#endif
354
- path += ".ini";
355
}
356
}
357
358
if (!std::filesystem::exists(path)) {
359
- output_error("Could not locate preset '{}'", preset);
360
+ output_error("Could not locate preset '{}'", preset.string());
361
quit(EXIT_FAILURE);
362
}
363
364
365
quit(EXIT_FAILURE);
366
}
367
368
- output_ok("Applying preset '{}'...", preset);
369
+ output_ok("Applying preset '{}'...", preset.string());
370
ini_parse_file(file, global_handler, nullptr);
371
rewind(file);
372
ini_parse_file(file, format_handler, nullptr);
373
374
return true;
375
}
376
377
-void scan_easy(const char *directory, const char *preset, size_t nb_threads)
378
+void scan_easy(const std::filesystem::path &path, const std::filesystem::path &preset, size_t nb_threads)
379
{
380
- std::filesystem::path path(directory);
381
std::queue<std::unique_ptr<ScanJob>> jobs;
382
ScanData data;
383
384
// Verify directory exists and is valid
385
if (!std::filesystem::exists(path)) {
386
- output_fail("Directory '{}' does not exist", directory);
387
+ output_fail("Directory '{}' does not exist", path.string());
388
quit(EXIT_FAILURE);
389
}
390
else if (!std::filesystem::is_directory(path)) {
391
- output_fail("'{}' is not a valid directory", directory);
392
+ output_fail("'{}' is not a valid directory", path.string());
393
quit(EXIT_FAILURE);
394
}
395
396
// Load scan preset
397
- if (preset)
398
+ if (!preset.empty())
399
load_preset(preset);
400
401
// Record start time
402
403
// Spawn worker threads
404
output_ok("Scanning with {} threads...", nb_threads);
405
for (size_t i = 0; i < nb_threads; i++) {
406
- progress.update(jobs.front()->path);
407
+ progress.update(jobs.front()->path.string());
408
threads.emplace_back(std::make_unique<WorkerThread>(
409
jobs.front(),
410
mutex,
411
412
// Feed jobs to workers
413
std::string current_job;
414
if (!jobs.empty())
415
- current_job = jobs.front()->path;
416
- while (jobs.size()) {
417
+ current_job = jobs.front()->path.string();
418
+ while (!jobs.empty()) {
419
cv.wait_for(lock, std::chrono::milliseconds(200));
420
for (auto &thread : threads) {
421
if (thread->place_job(jobs.front())) {
422
jobs.pop();
423
progress.update(current_job);
424
if (!jobs.empty())
425
- current_job = jobs.front()->path;
426
+ current_job = jobs.front()->path.string();
427
break;
428
}
429
}
430
431
while (1) {
432
for (auto thread = threads.begin(); thread != threads.end();)
433
thread = (*thread)->wait() ? threads.erase(thread) : thread + 1;
434
- if (!threads.size())
435
+ if (threads.empty())
436
break;
437
cv.wait_for(lock, std::chrono::milliseconds(200));
438
}
439
- fmt::print("\332K\n");
440
+ print("\332K\n");
441
}
442
443
// Single threaded scanning
444
445
job->update_data(data);
446
jobs.pop();
447
}
448
- fmt::print("\n");
449
+ print("\n");
450
}
451
452
// Output statistics at the end
453
auto duration = std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::now() - start_time);
454
if (!data.files) {
455
if (data.skipped)
456
- fmt::print("Skipped {:L} file{} with existing ReplayGain information\n",
457
+ print("Skipped {:L} file{} with existing ReplayGain information\n",
458
data.skipped,
459
data.skipped > 1 ? "s" : ""
460
);
461
- fmt::print("No files were scanned\n");
462
+ print("No files were scanned\n");
463
return;
464
}
465
466
- fmt::print(COLOR_GREEN "Scanning Complete" COLOR_OFF "\n");
467
+ print(COLOR_GREEN "Scanning Complete" COLOR_OFF "\n");
468
HELP_STATS("Time Elapsed", "{:%H:%M:%S}", duration);
469
HELP_STATS("Files Scanned", "{:L}", data.files);
470
if (data.skipped)
471
472
HELP_STATS("Clip Adjustments", "{:L} ({:.1f}% of files)", data.clipping_adjustments, 100.f * (float) data.clipping_adjustments / (float) data.files);
473
HELP_STATS("Average Gain", "{:.2f} dB", data.total_gain / (double) data.files);
474
double average_peak = data.total_peak / (double) data.files;
475
- HELP_STATS("Average Peak", "{:.6f}{}", average_peak, average_peak != 0.0 ? fmt::format(" ({:.2f} dB)", 20.0 * log10(average_peak)) : "");
476
+ HELP_STATS("Average Peak", "{:.6f}{}", average_peak, average_peak != 0.0 ? format(" ({:.2f} dB)", 20.0 * log10(average_peak)) : "");
477
HELP_STATS("Negative Gains", "{:L} ({:.1f}% of files)", data.total_negative, 100.f * (float) data.total_negative / (float) data.files);
478
HELP_STATS("Positive Gains", "{:L} ({:.1f}% of files)", data.total_positive, 100.f * (float) data.total_positive / (float) data.files);
479
- fmt::print("\n");
480
+ print("\n");
481
482
// Inform user of errors
483
- if (data.error_directories.size()) {
484
- fmt::print(COLOR_RED "There were errors while scanning the following directories:" COLOR_OFF "\n");
485
- for (std::string &s : data.error_directories)
486
- fmt::print("{}\n", s);
487
- fmt::print("\n");
488
+ if (!data.error_directories.empty()) {
489
+ print(COLOR_RED "There were errors while scanning the following directories:" COLOR_OFF "\n");
490
+ for (const std::string &s : data.error_directories)
491
+ print("{}\n", s);
492
+ print("\n");
493
}
494
}
495
496
static inline void help_easy() {
497
- fmt::print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} easy OPTIONS DIRECTORY\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
498
+ print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} easy OPTIONS DIRECTORY\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
499
500
- fmt::print(" Easy Mode recursively scans a directory using the recommended settings for each\n");
501
- fmt::print(" file type. Easy Mode assumes that you have your music library organized with each album\n");
502
- fmt::print(" in its own folder.\n");
503
+ print(" Easy Mode recursively scans a directory using the recommended settings for each\n");
504
+ print(" file type. Easy Mode assumes that you have your music library organized with each album\n");
505
+ print(" in its own folder.\n");
506
507
- fmt::print("\n");
508
- fmt::print(COLOR_RED "Options:\n" COLOR_OFF);
509
+ print("\n");
510
+ print(COLOR_RED "Options:\n" COLOR_OFF);
511
512
CMD_HELP("--help", "-h", "Show this help");
513
CMD_HELP("--quiet", "-q", "Don't print scanning status messages");
514
- fmt::print("\n");
515
+ print("\n");
516
517
CMD_HELP("--skip-existing", "-S", "Don't scan files with existing ReplayGain information");
518
CMD_HELP("--multithread=n", "-m n", "Scan files with n parallel threads");
519
CMD_HELP("--preset=s", "-p s", "Load scan preset s");
520
+
521
+ print("\n");
522
+
523
CMD_HELP("--output", "-O", "Output tab-delimited scan data to CSV file per directory");
524
- CMD_HELP("--output=s", "-O s", "Output with sep header (needed for Microsoft Excel compatibility).\n");
525
+ CMD_HELP("--output=s", "-O s", "Output with sep header (needed for Microsoft Excel compatibility)");
526
+ CMD_HELP("--output=a", "-O a", "Output with files sorted in alphanumeric order");
527
528
- fmt::print("\n");
529
+ print("\n");
530
531
- fmt::print("Please report any issues to " PROJECT_URL "/issues\n");
532
- fmt::print("\n");
533
+ print("Please report any issues to " PROJECT_URL "/issues\n");
534
+ print("\n");
535
}
536
rsgain-3.3-source.tar.xz/src/easymode.hpp -> rsgain-3.5.1.tar.gz/src/easymode.hpp
Changed
16
1
2
#include <mutex>
3
#include <filesystem>
4
#include <condition_variable>
5
-#include <fmt/core.h>
6
#include "scan.hpp"
7
8
class WorkerThread {
9
10
};
11
12
void easy_mode(int argc, char *argv);
13
-void scan_easy(const char *directory, const char *preset, size_t nb_threads);
14
+void scan_easy(const std::filesystem::path &path, const std::filesystem::path &preset, size_t nb_threads);
15
const Config& get_config(FileType type);
16
rsgain-3.3-source.tar.xz/src/output.cpp -> rsgain-3.5.1.tar.gz/src/output.cpp
Changed
58
1
2
#include <sys/ioctl.h>
3
#endif
4
5
-#include <fmt/core.h>
6
#include "output.hpp"
7
#include "config.h"
8
9
10
{
11
this->start = start;
12
this->len = len;
13
- w_prev = -1;
14
- c_prev = -1;
15
- pos_prev = -1;
16
}
17
18
void ProgressBar::update(int pos)
19
20
21
if (w != w_prev) {
22
delete buffer;
23
- buffer = new char(unsigned long) (w + 3);
24
+ buffer = new char(size_t) (w + 3);
25
}
26
27
- float percent = ((float) pos / (float) len);
28
+ float percent = (float) pos / (float) len;
29
c = (int) (percent * (float) w);
30
if (c > w)
31
c = w;
32
33
// Only output if we've actually made progress since last the call, or the console width changed
34
if (c != c_prev || w != w_prev) {
35
- fmt::print(" {:3.0f}% ", percent * 100.f);
36
+ print(" {:3.0f}% ", percent * 100.f);
37
memset(buffer, '=', (size_t) c);
38
memset(buffer + c, ' ', (size_t) (w - c));
39
bufferw = '';
40
41
42
delete buffer;
43
buffer = nullptr;
44
- fmt::print("\n");
45
+ print("\n");
46
}
47
48
inline int ProgressBar::get_console_width()
49
50
if (w_path + w_message >= w_console)
51
w_path = w_console - w_message;
52
53
- fmt::print("\332K " COLOR_GREEN "{:5.1f}%" COLOR_OFF MT_MESSAGE "{:.{}}\r",
54
+ print("\332K " COLOR_GREEN "{:5.1f}%" COLOR_OFF MT_MESSAGE "{:.{}}\r",
55
100.f * ((float) (cur) / (float) (total)),
56
path,
57
w_path < 0 ? 0 : w_path
58
rsgain-3.3-source.tar.xz/src/output.hpp -> rsgain-3.5.1.tar.gz/src/output.hpp
Changed
53
1
2
3
#include <string>
4
#include <string_view>
5
+
6
+#ifdef USE_STD_FORMAT
7
+#include <format>
8
+#include <print>
9
+#define format std::format
10
+#define print std::print
11
+#else
12
#include <fmt/core.h>
13
+#include <fmt/chrono.h>
14
+#define format fmt::format
15
+#define print fmt::print
16
+#endif
17
18
#define COLOR_GREEN "1;32m"
19
#define COLOR_YELLOW "1;33m"
20
21
#define FAIL_PREFIX "" COLOR_RED FAIL_CHAR COLOR_OFF " "
22
23
extern int quiet;
24
-#define output_ok(format, ...) if (!quiet) fmt::print(OK_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
25
-#define output_warn(format, ...) if (!quiet) fmt::print(WARN_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
26
-#define output_error(format, ...) fmt::print(stderr, ERROR_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
27
-#define output_fail(format, ...) fmt::print(stderr, FAIL_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
28
+#define output_ok(format, ...) if (!quiet) print(OK_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
29
+#define output_warn(format, ...) if (!quiet) print(WARN_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
30
+#define output_error(format, ...) print(stderr, ERROR_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
31
+#define output_fail(format, ...) print(stderr, FAIL_PREFIX format "\n" __VA_OPT__(,) __VA_ARGS__)
32
33
class ProgressBar {
34
private:
35
- int c_prev;
36
- int w_prev;
37
- int pos_prev;
38
+ int c_prev = -1;
39
+ int w_prev = -1;
40
+ int pos_prev = -1;
41
int start;
42
int len = 0;
43
char *buffer = nullptr;
44
45
void update(int pos);
46
void complete();
47
#ifdef _WIN32
48
- static void set_console(HANDLE c) { console = c; }
49
+ static void set_console(HANDLE c) { console = c; }
50
#endif
51
};
52
53
rsgain-3.3-source.tar.xz/src/rsgain.cpp -> rsgain-3.5.1.tar.gz/src/rsgain.cpp
Changed
331
1
2
#include <libavutil/avutil.h>
3
}
4
#include <taglib/taglib.h>
5
+#define HAS_TAGLIB2 TAGLIB_MAJOR_VERSION > 1
6
+#if HAS_TAGLIB2
7
+#include <taglib/tversionnumber.h>
8
+#endif
9
#include <ebur128.h>
10
-#include <fmt/core.h>
11
12
#include "rsgain.hpp"
13
#include "tag.hpp"
14
15
#include "output.hpp"
16
#include "easymode.hpp"
17
18
-#define PRINT_LIB(lib, version) fmt::print(" " COLOR_YELLOW " {:<14}" COLOR_OFF " {}\n", lib, version)
19
+#define PRINT_LIB(lib, version) print(" " COLOR_YELLOW " {:<14}" COLOR_OFF " {}\n", lib, version)
20
#define PRINT_LIB_FFMPEG(name, fn) \
21
ffver = fn(); \
22
- PRINT_LIB(name, fmt::format("{}.{}.{}", AV_VERSION_MAJOR(ffver), AV_VERSION_MINOR(ffver), AV_VERSION_MICRO(ffver)))
23
+ PRINT_LIB(name, format("{}.{}.{}", AV_VERSION_MAJOR(ffver), AV_VERSION_MINOR(ffver), AV_VERSION_MICRO(ffver)))
24
25
#ifdef _WIN32
26
#include <windows.h>
27
28
return true;
29
}
30
31
+std::pair<bool, bool> parse_output_mode(const std::string_view arg)
32
+{
33
+ std::pair<bool, bool> ret(false, false);
34
+ for (char c : arg) {
35
+ if (c == 's')
36
+ ret.first = true;
37
+ else if (c == 'a')
38
+ ret.second = true;
39
+ else {
40
+ output_fail("Unrecognized output argument '{}'", c);
41
+ quit(EXIT_FAILURE);
42
+ }
43
+ }
44
+ return ret;
45
+}
46
+
47
// Parse Custom Mode command line arguments
48
static void custom_mode(int argc, char *argv)
49
{
50
51
unsigned int nb_files = 0;
52
opterr = 0;
53
54
- const char *short_opts = "+ac:m:tl:O::qs:LSI:o:h?";
55
+ const char *short_opts = "+ac:m:tl:O::qps:LSI:o:h?";
56
static struct option long_opts = {
57
- { "album", no_argument, nullptr, 'a' },
58
- { "skip-existing", no_argument, nullptr, 'S' },
59
+ { "album", no_argument, nullptr, 'a' },
60
+ { "skip-existing", no_argument, nullptr, 'S' },
61
62
- { "clip-mode", required_argument, nullptr, 'c' },
63
- { "max-peak", required_argument, nullptr, 'm' },
64
- { "true-peak", no_argument, nullptr, 't' },
65
+ { "clip-mode", required_argument, nullptr, 'c' },
66
+ { "max-peak", required_argument, nullptr, 'm' },
67
+ { "true-peak", no_argument, nullptr, 't' },
68
69
- { "loudness", required_argument, nullptr, 'l' },
70
+ { "loudness", required_argument, nullptr, 'l' },
71
72
- { "output", optional_argument, nullptr, 'O' },
73
- { "quiet", no_argument, nullptr, 'q' },
74
+ { "output", optional_argument, nullptr, 'O' },
75
+ { "quiet", no_argument, nullptr, 'q' },
76
+ { "preserve-mtimes", no_argument, nullptr, 'p' },
77
78
- { "tagmode", required_argument, nullptr, 's' },
79
- { "lowercase", no_argument, nullptr, 'L' },
80
- { "id3v2-version", required_argument, nullptr, 'I' },
81
- { "opus-mode", required_argument, nullptr, 'o' },
82
- { "help", no_argument, nullptr, 'h' },
83
+ { "tagmode", required_argument, nullptr, 's' },
84
+ { "lowercase", no_argument, nullptr, 'L' },
85
+ { "id3v2-version", required_argument, nullptr, 'I' },
86
+ { "opus-mode", required_argument, nullptr, 'o' },
87
+ { "help", no_argument, nullptr, 'h' },
88
{ 0, 0, 0, 0 }
89
};
90
91
92
.do_album = false,
93
.tab_output = OutputType::NONE,
94
.sep_header = false,
95
+ .sort_alphanum = false,
96
.lowercase = false,
97
- .id3v2version = 3,
98
- .opus_mode = 'd'
99
+ .id3v2version = ID3V2_KEEP,
100
+ .opus_mode = 'd',
101
+ .skip_mp4 = false,
102
+ .preserve_mtimes = false
103
};
104
105
while ((rc = getopt_long(argc, argv, short_opts, long_opts, &i)) != -1) {
106
107
case 'O':
108
config.tab_output = OutputType::STDOUT;
109
if (optarg) {
110
- if (*optarg == 's')
111
- config.sep_header = true;
112
- else {
113
- output_fail("Unrecognized output argument '{}'", optarg);
114
- quit(EXIT_FAILURE);
115
- }
116
+ const auto& sep_header, sort_alphanum = parse_output_mode(optarg);
117
+ config.sep_header = sep_header;
118
+ config.sort_alphanum = sort_alphanum;
119
}
120
quiet = 1;
121
break;
122
123
quiet = 1;
124
break;
125
126
+ case 'p':
127
+ config.preserve_mtimes = true;
128
+ break;
129
+
130
case 's': {
131
if (!parse_tag_mode_custom(optarg, config.tag_mode))
132
quit(EXIT_FAILURE);
133
134
135
std::unique_ptr<ScanJob> job(ScanJob::factory(argv + optind, nb_files, config));
136
if (!job) {
137
- output_fail("No valid files were specified");
138
+ output_fail("File list is not valid");
139
quit(EXIT_FAILURE);
140
}
141
job->scan();
142
143
144
const char *short_opts = "+hv?";
145
static struct option long_opts = {
146
- { "help", no_argument, nullptr, 'h' },
147
- { "version", no_argument, nullptr, 'v' },
148
+ { "help", no_argument, nullptr, 'h' },
149
+ { "version", no_argument, nullptr, 'v' },
150
{ 0, 0, 0, 0 }
151
};
152
std::locale::global(std::locale(""));
153
154
}
155
156
static void help_main() {
157
- fmt::print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} OPTIONS <command> ...\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
158
+ print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} OPTIONS <command> ...\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
159
160
- fmt::print("{} {} supports writing tags to the following file types:\n", PROJECT_NAME, PROJECT_VERSION);
161
- fmt::print(" FLAC (.flac), Ogg (.ogg, .oga, .spx), Opus (.opus), MP2 (.mp2),\n");
162
- fmt::print(" MP3 (.mp3), MP4 (.m4a), WMA (.wma), WavPack (.wv), APE (.ape),\n");
163
- fmt::print(" WAV (.wav), and AIFF (.aiff, .aif, .snd).\n");
164
+ print("{} {} supports writing tags to the following file types:\n", PROJECT_NAME, PROJECT_VERSION);
165
+ print(" FLAC (.flac), Ogg (.ogg, .oga, .spx), Opus (.opus), MP2 (.mp2),\n");
166
+ print(" MP3 (.mp3), MP4 (.m4a), WMA (.wma), WavPack (.wv), APE (.ape),\n");
167
+ print(" WAV (.wav), AIFF (.aiff, .aif, .snd), and TAK (.tak).\n");
168
169
- fmt::print("\n");
170
- fmt::print(COLOR_RED "Options:\n" COLOR_OFF);
171
+ print("\n");
172
+ print(COLOR_RED "Options:\n" COLOR_OFF);
173
174
CMD_HELP("--help", "-h", "Show this help");
175
CMD_HELP("--version", "-v", "Show version number");
176
177
- fmt::print("\n");
178
- fmt::print(COLOR_RED "Commands:\n" COLOR_OFF);
179
+ print("\n");
180
+ print(COLOR_RED "Commands:\n" COLOR_OFF);
181
182
CMD_CMD("easy", "Easy Mode: Recursively scan a directory with recommended settings");
183
CMD_CMD("custom", "Custom Mode: Scan individual files with custom settings");
184
- fmt::print("\n");
185
- fmt::print("Run '{} easy --help' or '{} custom --help' for more information.", EXECUTABLE_TITLE, EXECUTABLE_TITLE);
186
+ print("\n");
187
+ print("Run '{} easy --help' or '{} custom --help' for more information.", EXECUTABLE_TITLE, EXECUTABLE_TITLE);
188
189
- fmt::print("\n\n");
190
- fmt::print("Please report any issues to " PROJECT_URL "/issues\n\n");
191
+ print("\n\n");
192
+ print("Please report any issues to " PROJECT_URL "/issues\n\n");
193
}
194
195
static inline void help_custom() {
196
- fmt::print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} custom OPTIONS FILES...\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
197
+ print(COLOR_RED "Usage: " COLOR_OFF "{}{}{} custom OPTIONS FILES...\n", COLOR_GREEN, EXECUTABLE_TITLE, COLOR_OFF);
198
199
- fmt::print(" Custom Mode allows the user to specify the options to scan the files with. The\n");
200
- fmt::print(" list of files to scan must be listed explicitly after the options.\n");
201
- fmt::print("\n");
202
+ print(" Custom Mode allows the user to specify the options to scan the files with. The\n");
203
+ print(" list of files to scan must be listed explicitly after the options.\n");
204
+ print("\n");
205
206
- fmt::print(COLOR_RED "Options:\n" COLOR_OFF);
207
+ print(COLOR_RED "Options:\n" COLOR_OFF);
208
CMD_HELP("--help", "-h", "Show this help");
209
- fmt::print("\n");
210
+ print("\n");
211
212
CMD_HELP("--album", "-a", "Calculate album gain and peak");
213
CMD_HELP("--skip-existing", "-S", "Don't scan files with existing ReplayGain information");
214
- fmt::print("\n");
215
+ print("\n");
216
217
CMD_HELP("--tagmode=s", "-s s", "Scan files but don't write ReplayGain tags (default)");
218
CMD_HELP("--tagmode=d", "-s d", "Delete ReplayGain tags from files");
219
CMD_HELP("--tagmode=i", "-s i", "Scan and write ReplayGain 2.0 tags to files");
220
- fmt::print("\n");
221
+ print("\n");
222
223
CMD_HELP("--loudness=n", "-l n", "Use n LUFS as target loudness (" STR(MIN_TARGET_LOUDNESS) " ≤ n ≤ " STR(MAX_TARGET_LOUDNESS) ")");
224
- fmt::print("\n");
225
+ print("\n");
226
227
CMD_HELP("--clip-mode=n", "-c n", "No clipping protection (default)");
228
CMD_HELP("--clip-mode=p", "-c p", "Clipping protection enabled for positive gain values only");
229
230
CMD_HELP("--max-peak=n", "-m n", "Use max peak level n dB for clipping protection");
231
CMD_HELP("--true-peak", "-t", "Use true peak for peak calculations");
232
233
- fmt::print("\n");
234
+ print("\n");
235
236
CMD_HELP("--lowercase", "-L", "Write lowercase tags (MP2/MP3/MP4/WMA/WAV/AIFF)");
237
CMD_CONT("This is non-standard but sometimes needed");
238
- CMD_HELP("--id3v2-version=3", "-I 3", "Write ID3v2.3 tags to MP2/MP3/WAV/AIFF (default)");
239
+ CMD_HELP("--id3v2-version=keep", "-I keep", "Keep file's existing ID3v2 version, 3 if none exists (default)");
240
+ CMD_HELP("--id3v2-version=3", "-I 3", "Write ID3v2.3 tags to MP2/MP3/WAV/AIFF");
241
CMD_HELP("--id3v2-version=4", "-I 4", "Write ID3v2.4 tags to MP2/MP3/WAV/AIFF");
242
- CMD_HELP("--id3v2-version=keep", "-I keep", "Keep file's existing ID3v2 version, 3 if none exists");
243
-
244
245
- fmt::print("\n");
246
+ print("\n");
247
248
CMD_HELP("--opus-mode=d", "-o d", "Write standard ReplayGain tags, clear header output gain (default)");
249
CMD_HELP("--opus-mode=r", "-o r", "Write R128_*_GAIN tags, clear header output gain");
250
+ CMD_HELP("--opus-mode=s", "-o s", "Same as 'r', plus override target loudness to -23 LUFS");
251
CMD_HELP("--opus-mode=t", "-o t", "Write track gain to header output gain");
252
CMD_HELP("--opus-mode=a", "-o a", "Write album gain to header output gain");
253
254
- fmt::print("\n");
255
+ print("\n");
256
257
CMD_HELP("--output", "-O", "Output tab-delimited scan data to stdout");
258
- CMD_HELP("--output=s", "-O s", "Output with sep header (needed for Microsoft Excel compatibility).\n");
259
+ CMD_HELP("--output=s", "-O s", "Output with sep header (needed for Microsoft Excel compatibility)");
260
+ CMD_HELP("--output=a", "-O a", "Output with files sorted in alphanumeric order");
261
262
+ CMD_HELP("--preserve-mtimes", "-p", "Preserve file mtimes");
263
CMD_HELP("--quiet", "-q", "Don't print scanning status messages");
264
265
- fmt::print("\n");
266
+ print("\n");
267
268
- fmt::print("Please report any issues to " PROJECT_URL "/issues\n");
269
- fmt::print("\n");
270
+ print("Please report any issues to " PROJECT_URL "/issues\n");
271
+ print("\n");
272
}
273
274
static void version() {
275
276
int ebur128_v_major = 0;
277
int ebur128_v_minor = 0;
278
int ebur128_v_patch = 0;
279
- fmt::print(COLOR_GREEN PROJECT_NAME COLOR_OFF " " PROJECT_VERSION " - using:\n");
280
+ print(COLOR_GREEN PROJECT_NAME COLOR_OFF " " PROJECT_VERSION
281
+#if defined COMMITS_SINCE_TAG && defined COMMIT_HASH
282
+ "-r" COMMITS_SINCE_TAG "-" COMMIT_HASH
283
+#endif
284
+ " - using:\n"
285
+ );
286
287
// Library versions
288
ebur128_get_version(&ebur128_v_major, &ebur128_v_minor, &ebur128_v_patch);
289
- PRINT_LIB("libebur128", fmt::format("{}.{}.{}", ebur128_v_major, ebur128_v_minor, ebur128_v_patch));
290
+ PRINT_LIB("libebur128", format("{}.{}.{}", ebur128_v_major, ebur128_v_minor, ebur128_v_patch));
291
PRINT_LIB_FFMPEG("libavformat", avformat_version);
292
PRINT_LIB_FFMPEG("libavcodec", avcodec_version);
293
PRINT_LIB_FFMPEG("libavutil", avutil_version);
294
PRINT_LIB_FFMPEG("libswresample", swresample_version);
295
- fmt::print("\n");
296
- fmt::print("Built with:\n");
297
- PRINT_LIB("TagLib", fmt::format("{}.{}{}", TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION, TAGLIB_PATCH_VERSION ? fmt::format(".{}", TAGLIB_PATCH_VERSION) : ""));
298
- fmt::print("\n");
299
+#if HAS_TAGLIB2
300
+ TagLib::VersionNumber tver = TagLib::runtimeVersion();
301
+ PRINT_LIB("TagLib", format("{}.{}{}", tver.majorVersion(), tver.minorVersion(), tver.patchVersion() ? format(".{}", tver.patchVersion()) : ""));
302
+#else
303
+ print("\n");
304
+ print("Built with:\n");
305
+ PRINT_LIB("TagLib", format("{}.{}{}", TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION, TAGLIB_PATCH_VERSION ? format(".{}", TAGLIB_PATCH_VERSION) : ""));
306
+#endif
307
+ print("\n");
308
309
#if defined(__GNUC__) && !defined(__clang__)
310
- fmt::print(COLOR_YELLOW "{:<17}" COLOR_OFF " GCC {}.{}\n", "Compiler:", __GNUC__, __GNUC_MINOR__);
311
+ print(COLOR_YELLOW "{:<17}" COLOR_OFF " GCC {}.{}\n", "Compiler:", __GNUC__, __GNUC_MINOR__);
312
#endif
313
314
#ifdef __clang__
315
- fmt::print(COLOR_YELLOW "{:<17}" COLOR_OFF " "
316
+ print(COLOR_YELLOW "{:<17}" COLOR_OFF " "
317
#ifdef __apple_build_version__
318
"Apple "
319
#endif
320
321
#endif
322
323
#ifdef _MSC_VER
324
- fmt::print(COLOR_YELLOW "{:<17}" COLOR_OFF " Microsoft C/C++ {:.2f}\n", "Compiler:", (float) _MSC_VER / 100.0f);
325
+ print(COLOR_YELLOW "{:<17}" COLOR_OFF " Microsoft C/C++ {:.2f}\n", "Compiler:", (float) _MSC_VER / 100.0f);
326
#endif
327
328
- fmt::print(COLOR_YELLOW "{:<17}" COLOR_OFF " " __DATE__ "\n", "Build Date:");
329
+ print(COLOR_YELLOW "{:<17}" COLOR_OFF " " BUILD_DATE "\n", "Build Date:");
330
}
331
rsgain-3.3-source.tar.xz/src/rsgain.hpp -> rsgain-3.5.1.tar.gz/src/rsgain.hpp
Changed
36
1
2
#pragma once
3
4
-#define CMD_HELP(CMDL, CMDS, MSG) fmt::print(" {}{:<8} {:<20}{} {}.\n", COLOR_YELLOW, CMDS ",", CMDL, COLOR_OFF, MSG);
5
-#define CMD_CMD(CMD, MSG) fmt::print(" {}{:<22}{} {}.\n", COLOR_YELLOW, CMD, COLOR_OFF, MSG);
6
-#define CMD_CONT(MSG) fmt::print(" {}{:<8} {:<20}{} {}.\n", COLOR_YELLOW, "", "", COLOR_OFF, MSG);
7
+#define CMD_HELP(CMDL, CMDS, MSG) print(" {}{:<8} {:<20}{} {}.\n", COLOR_YELLOW, CMDS ",", CMDL, COLOR_OFF, MSG);
8
+#define CMD_CMD(CMD, MSG) print(" {}{:<22}{} {}.\n", COLOR_YELLOW, CMD, COLOR_OFF, MSG);
9
+#define CMD_CONT(MSG) print(" {}{:<8} {:<20}{} {}.\n", COLOR_YELLOW, "", "", COLOR_OFF, MSG);
10
#define MATCH(x,y) !strcmp(x,y)
11
#define STR_CAT(a) #a
12
#define STR(a) STR_CAT(a)
13
14
bool do_album;
15
OutputType tab_output;
16
bool sep_header;
17
+ bool sort_alphanum;
18
bool lowercase;
19
unsigned int id3v2version;
20
char opus_mode;
21
+ bool skip_mp4;
22
+ bool preserve_mtimes;
23
};
24
25
26
27
#define parse_tag_mode_easy(value, mode) parse_mode("tag", "disn", value, mode)
28
#define parse_tag_mode_custom(value, mode) parse_mode("tag", "dis", value, mode)
29
#define parse_clip_mode(value, mode) parse_mode("clip", "npa", value, mode)
30
-#define parse_opus_mode(value, mode) parse_mode("Opus", "drta", value, mode)
31
+#define parse_opus_mode(value, mode) parse_mode("Opus", "drtas", value, mode)
32
bool parse_target_loudness(const char *value, double &target_loudness);
33
bool parse_id3v2_version(const char *value, unsigned int &version);
34
bool parse_max_peak_level(const char *value, double &peak);
35
+std::pair<bool, bool> parse_output_mode(const std::string_view arg);
36
rsgain-3.3-source.tar.xz/src/scan.cpp -> rsgain-3.5.1.tar.gz/src/scan.cpp
Changed
394
1
2
{".spx", FileType::OGG},
3
{".opus", FileType::OPUS},
4
{".m4a", FileType::M4A},
5
+ {".mp4", FileType::M4A},
6
{".wma", FileType::WMA},
7
{".wav", FileType::WAV},
8
{".aiff", FileType::AIFF},
9
10
{".snd", FileType::AIFF},
11
{".wv", FileType::WAVPACK},
12
{".ape", FileType::APE},
13
+ {".tak", FileType::TAK},
14
{".mpc", FileType::MPC}
15
};
16
std::string extensionlower = extension;
17
18
std::vector<Track> tracks;
19
20
for (const std::filesystem::directory_entry &entry : std::filesystem::directory_iterator(path)) {
21
- if (entry.is_regular_file() && entry.path().has_extension() &&
22
- (file_type = determine_filetype(entry.path().extension().string())) != FileType::INVALID) {
23
- tracks.emplace_back(entry.path().string(), file_type);
24
+ if (entry.is_regular_file() && entry.path().has_extension()
25
+ && ((file_type = determine_filetype(entry.path().extension().string())) != FileType::INVALID)
26
+ && !(file_type == FileType::M4A && get_config(file_type).skip_mp4 && entry.path().extension().string() == ".mp4")) {
27
+ tracks.emplace_back(entry.path(), file_type);
28
extensions.insert(file_type);
29
}
30
}
31
if (tracks.empty())
32
return nullptr;
33
file_type = extensions.size() > 1 ? FileType::DEFAULT : *extensions.begin();
34
- return new ScanJob(path.string(), std::move(tracks), get_config(file_type));
35
+ const Config &config = get_config(file_type);
36
+ if (config.tag_mode == 'n')
37
+ return nullptr;
38
+ return new ScanJob(path, tracks, config, file_type);
39
}
40
41
ScanJob* ScanJob::factory(char **files, size_t nb_files, const Config &config)
42
43
FileType file_type;
44
std::filesystem::path path;
45
std::vector<Track> tracks;
46
+ std::unordered_set<FileType> types;
47
for (size_t i = 0; i < nb_files; i++) {
48
path = filesi;
49
- if ((file_type = determine_filetype(path.extension().string())) == FileType::INVALID)
50
+ if (!std::filesystem::exists(path)) {
51
+ output_error("File '{}' does not exist", path.string());
52
+ return nullptr;
53
+ }
54
+ else if ((file_type = determine_filetype(path.extension().string())) == FileType::INVALID) {
55
output_error("File '{}' is not of a supported type", filesi);
56
- else
57
- tracks.emplace_back(path.string(), file_type);
58
+ return nullptr;
59
+ }
60
+ else {
61
+ tracks.emplace_back(path, file_type);
62
+ types.insert(file_type);
63
+ }
64
}
65
if (tracks.empty())
66
return nullptr;
67
- return new ScanJob("", std::move(tracks), config);
68
+ return new ScanJob(tracks, config, types.size() > 1 ? FileType::DEFAULT : *types.begin());
69
}
70
71
void free_ebur128(ebur128_state *ebur128_state)
72
73
{
74
ProgressBar progress_bar;
75
int rc, stream_id = -1;
76
- int start = 0, len = 0, pos = 0;
77
uint8_t *swr_out_data1;
78
bool ret = false;
79
bool repeat = false;
80
int peak_mode;
81
+ double time_base;
82
bool output_progress = !quiet && !multithread && config.tag_mode != 'd';
83
std::unique_lock<std::mutex> *lk = nullptr;
84
ebur128_state *ebur128 = nullptr;
85
86
AVFrame *frame = nullptr;
87
SwrContext *swr = nullptr;
88
AVFormatContext *format_ctx = nullptr;
89
+ const AVStream *stream = nullptr;
90
91
// For Opus files, FFmpeg always adjusts the decoded audio samples by the header output
92
// gain with no way to disable. To get the actual loudness of the audio signal,
93
// we need to set the header output gain to 0 dB before decoding
94
if (type == FileType::OPUS && config.tag_mode != 's')
95
- set_opus_header_gain(path.c_str(), 0);
96
+ set_opus_header_gain(path.string().c_str(), 0);
97
98
if (m)
99
lk = new std::unique_lock<std::mutex>(*m, std::defer_lock);
100
if (output_progress)
101
- output_ok("Scanning '{}'", path);
102
+ output_ok("Scanning '{}'", path.string());
103
104
if (lk)
105
lk->lock();
106
- rc = avformat_open_input(&format_ctx, path.c_str(), nullptr, nullptr);
107
+ rc = avformat_open_input(&format_ctx, format("file:{}", path.string()).c_str(), nullptr, nullptr);
108
if (rc < 0) {
109
output_fferror(rc, "Could not open input");
110
goto end;
111
112
output_error("Could not find audio stream");
113
goto end;
114
}
115
+ stream = format_ctx->streamsstream_id;
116
+ time_base = av_q2d(stream->time_base);
117
118
// Initialize the decoder
119
do {
120
121
output_error("Could not allocate audio codec context");
122
goto end;
123
}
124
- avcodec_parameters_to_context(codec_ctx, format_ctx->streamsstream_id->codecpar);
125
+ avcodec_parameters_to_context(codec_ctx, stream->codecpar);
126
rc = avcodec_open2(codec_ctx, codec, nullptr);
127
if (rc < 0) {
128
if (!repeat) {
129
130
output_ok("Stream #{}: {}, {}{:L} Hz, {} ch",
131
stream_id,
132
codec->long_name,
133
- codec_ctx->bits_per_raw_sample > 0 ? fmt::format("{} bit, ", codec_ctx->bits_per_raw_sample) : "",
134
+ codec_ctx->bits_per_raw_sample > 0 ? format("{} bit, ", codec_ctx->bits_per_raw_sample) : "",
135
codec_ctx->sample_rate,
136
nb_channels
137
);
138
139
// Initialize libebur128
140
peak_mode = config.true_peak ? EBUR128_MODE_TRUE_PEAK : EBUR128_MODE_SAMPLE_PEAK;
141
ebur128 = ebur128_init((unsigned int) nb_channels,
142
- (unsigned long) codec_ctx->sample_rate,
143
+ (size_t) codec_ctx->sample_rate,
144
EBUR128_MODE_I | peak_mode
145
);
146
if (!ebur128) {
147
148
}
149
150
if (output_progress) {
151
- if (format_ctx->streamsstream_id->duration == AV_NOPTS_VALUE)
152
+ if (stream->duration == AV_NOPTS_VALUE)
153
output_progress = false;
154
else {
155
- if (format_ctx->streamsstream_id->start_time != AV_NOPTS_VALUE)
156
- start = (int) std::round((double) (format_ctx->streamsstream_id->start_time)
157
- * av_q2d(format_ctx->streamsstream_id->time_base));
158
- len = (int) std::round((double) (format_ctx->streamsstream_id->duration)
159
- * av_q2d(format_ctx->streamsstream_id->time_base));
160
- if (len > 0)
161
- progress_bar.begin(start, len);
162
+ int start = 0;
163
+ if (stream->start_time != AV_NOPTS_VALUE)
164
+ start = (int) std::round((double) stream->start_time * time_base);
165
+ progress_bar.begin(start, (int) std::round((double) stream->duration * time_base));
166
}
167
}
168
169
170
if (packet->stream_index == stream_id) {
171
if ((rc = avcodec_send_packet(codec_ctx, packet)) == 0) {
172
while ((rc = avcodec_receive_frame(codec_ctx, frame)) >= 0) {
173
- pos = (int) std::round((double) (frame->pkt_dts)
174
- * av_q2d(format_ctx->streamsstream_id->time_base));
175
#if OLD_CHANNEL_LAYOUT
176
if (frame->channels == nb_channels) {
177
#else
178
179
else
180
ebur128_add_frames_short(ebur128, (short*) frame->data0, static_cast<size_t>(frame->nb_samples));
181
182
- if (output_progress && pos >= 0)
183
- progress_bar.update(pos);
184
+ if (output_progress) {
185
+ int pos = (int) std::round((double) frame->pts * time_base);
186
+ if (pos >= 0)
187
+ progress_bar.update(pos);
188
+ }
189
}
190
av_frame_unref(frame);
191
}
192
193
194
void ScanJob::calculate_loudness()
195
{
196
+ if (tracks.empty())
197
+ return;
198
+
199
// Track loudness calculations
200
- for (auto track = tracks.begin(); track != tracks.end();) {
201
- if (!track->calculate_loudness(config)) {
202
- tracks.erase(track);
203
- nb_files--;
204
- }
205
- else
206
- ++track;
207
- }
208
+ for (Track &track : tracks)
209
+ track.calculate_loudness(config);
210
211
// Album loudness calculations
212
if (config.do_album)
213
214
215
void ScanJob::tag_tracks()
216
{
217
+ if (tracks.empty())
218
+ return;
219
std::FILE *stream = nullptr;
220
if (config.tab_output != OutputType::NONE) {
221
if (config.tab_output == OutputType::FILE) {
222
- std::filesystem::path output_file = std::filesystem::path(path) / "replaygain.csv";
223
+ std::filesystem::path output_file = path / "replaygain.csv";
224
stream = fopen(output_file.string().c_str(), "wb");
225
}
226
else
227
228
// Tag the files
229
bool tab_output = config.tab_output != OutputType::NONE && stream != nullptr;
230
bool human_output = !multithread && !quiet && config.tag_mode != 'd';
231
+ if (config.sort_alphanum)
232
+ std::sort(tracks.begin(), tracks.end(), (const auto &a, const auto &b){ return a.path.string() < b.path.string(); });
233
for (Track &track : tracks) {
234
if (config.tag_mode != 's')
235
tag_track(track, config);
236
237
if (tab_output) {
238
// Filename;Loudness;Gain (dB);Peak;Peak (dB);Peak Type;Clipping Adjustment;
239
- fmt::print(stream, "{}\t", std::filesystem::path(track.path).filename().string());
240
- fmt::print(stream, "{:.2f}\t", track.result.track_loudness);
241
- fmt::print(stream, "{:.2f}\t", track.result.track_gain);
242
- fmt::print(stream, "{:.6f}\t", track.result.track_peak);
243
- fmt::print(stream, "{:.2f}\t", 20.0 * log10(track.result.track_peak));
244
- fmt::print(stream, "{}\t", config.true_peak ? "True" : "Sample");
245
- fmt::print(stream, "{}\n", track.tclip ? "Y" : "N");
246
+ print(stream, "{}\t", track.path.filename().string());
247
+ track.result.track_loudness == -HUGE_VAL ? print(stream, "-∞\t") : print(stream, "{:.2f}\t", track.result.track_loudness);
248
+ print(stream, "{:.2f}\t", track.result.track_gain);
249
+ print(stream, "{:.6f}\t", track.result.track_peak);
250
+ track.result.track_peak == 0.0 ? print(stream, "-∞\t") : print(stream, "{:.2f}\t", 20.0 * log10(track.result.track_peak));
251
+ print(stream, "{}\t", config.true_peak ? "True" : "Sample");
252
+ print(stream, "{}\n", track.tclip ? "Y" : "N");
253
if (config.do_album && ((size_t) (&track - &tracks0) == (nb_files - 1))) {
254
- fmt::print(stream, "{}\t", "Album");
255
- fmt::print(stream, "{:.2f}\t", track.result.album_loudness);
256
- fmt::print(stream, "{:.2f}\t", track.result.album_gain);
257
- fmt::print(stream, "{:.6f}\t", track.result.album_peak);
258
- fmt::print(stream, "{:.2f}\t", 20.0 * log10(track.result.album_peak));
259
- fmt::print(stream, "{}\t", config.true_peak ? "True" : "Sample");
260
- fmt::print(stream, "{}\n", track.aclip ? "Y" : "N");
261
+ print(stream, "{}\t", "Album");
262
+ track.result.album_loudness == -HUGE_VAL ? print(stream, "-∞\t") : print(stream, "{:.2f}\t", track.result.album_loudness);
263
+ print(stream, "{:.2f}\t", track.result.album_gain);
264
+ print(stream, "{:.6f}\t", track.result.album_peak);
265
+ track.result.album_peak == 0.0 ? print(stream, "-∞\t") : print(stream, "{:.2f}\t", 20.0 * log10(track.result.album_peak));
266
+ print(stream, "{}\t", config.true_peak ? "True" : "Sample");
267
+ print(stream, "{}\n", track.aclip ? "Y" : "N");
268
}
269
}
270
271
// Human-readable output
272
if (human_output) {
273
- fmt::print("\nTrack: {}\n", track.path);
274
- fmt::print(" Loudness: {:8.2f} LUFS\n", track.result.track_loudness);
275
- fmt::print(" Peak: {:8.6f} ({:.2f} dB)\n", track.result.track_peak, 20.0 * log10(track.result.track_peak));
276
- fmt::print(" Gain: {:8.2f} dB {}{}\n",
277
+ print("\nTrack: {}\n", track.path.string());
278
+ print(" Loudness: {} LUFS\n", track.result.track_loudness == -HUGE_VAL ? " -∞" : format("{:8.2f}", track.result.track_loudness));
279
+ print(" Peak: {:8.6f} ({} dB)\n",
280
+ track.result.track_peak,
281
+ track.result.track_peak == 0.0 ? "-∞" : format("{:.2f}", 20.0 * log10(track.result.track_peak))
282
+ );
283
+ print(" Gain: {:8.2f} dB {}{}\n",
284
track.result.track_gain,
285
- track.type == FileType::OPUS && config.opus_mode != 'd' ? fmt::format("({})", GAIN_TO_Q78(track.result.track_gain)) : "",
286
+ track.type == FileType::OPUS && (config.opus_mode == 'r' || config.opus_mode == 's') ? format("({})", GAIN_TO_Q78(track.result.track_gain)) : "",
287
track.tclip ? " (adjusted to prevent clipping)" : ""
288
);
289
290
if (config.do_album && ((size_t) (&track - &tracks0) == (nb_files - 1))) {
291
- fmt::print("\nAlbum:\n");
292
- fmt::print(" Loudness: {:8.2f} LUFS\n", track.result.album_loudness);
293
- fmt::print(" Peak: {:8.6f} ({:.2f} dB)\n", track.result.album_peak, 20.0 * log10(track.result.album_peak));
294
- fmt::print(" Gain: {:8.2f} dB {}{}\n",
295
+ print("\nAlbum:\n");
296
+ print(" Loudness: {} LUFS\n", track.result.album_loudness == -HUGE_VAL ? " -∞" : format("{:8.2f}", track.result.album_loudness));
297
+ print(" Peak: {:8.6f} ({} dB)\n",
298
+ track.result.album_peak,
299
+ track.result.album_peak == 0.0 ? "-∞" : format("{:.2f}", 20.0 * log10(track.result.album_peak))
300
+ );
301
+ print(" Gain: {:8.2f} dB {}{}\n",
302
track.result.album_gain,
303
- track.type == FileType::OPUS && config.opus_mode != 'd' ? fmt::format("({})", GAIN_TO_Q78(track.result.album_gain)) : "",
304
+ type == FileType::OPUS && (config.opus_mode == 'r' || config.opus_mode == 's') ? format("({})", GAIN_TO_Q78(track.result.album_gain)) : "",
305
track.aclip ? " (adjusted to prevent clipping)" : ""
306
);
307
}
308
- fmt::print("\n");
309
+ print("\n");
310
}
311
}
312
if (config.tab_output == OutputType::FILE && stream != nullptr)
313
314
void ScanJob::update_data(ScanData &data)
315
{
316
if (error) {
317
- data.error_directories.push_back(path);
318
+ data.error_directories.push_back(path.string());
319
return;
320
}
321
data.files += nb_files;
322
323
}
324
}
325
326
-bool ScanJob::Track::calculate_loudness(const Config &config)
327
+void ScanJob::Track::calculate_loudness(const Config &config)
328
{
329
- unsigned channel = 0;
330
+ unsigned int channel = 0;
331
double track_loudness, track_peak;
332
333
if (ebur128_loudness_global(ebur128.get(), &track_loudness) != EBUR128_SUCCESS)
334
track_loudness = config.target_loudness;
335
336
- if (track_loudness == -HUGE_VAL) // Don't bother tagging silent tracks
337
- return false;
338
-
339
- std::vector<double> peaks(ebur128->channels);
340
- int (*get_peak)(ebur128_state*, unsigned int, double*) = config.true_peak ? ebur128_true_peak : ebur128_sample_peak;
341
- for (double &pk : peaks)
342
- get_peak(ebur128.get(), channel++, &pk);
343
- track_peak = *std::max_element(peaks.begin(), peaks.end());
344
+ // Edge case for completely silent tracks
345
+ if (track_loudness == -HUGE_VAL) {
346
+ result.track_gain = 0.0;
347
+ result.track_peak = 0.0;
348
+ result.track_loudness = -HUGE_VAL;
349
+ }
350
351
- result.track_gain = config.target_loudness - track_loudness;
352
- result.track_peak = track_peak;
353
- result.track_loudness = track_loudness;
354
- return true;
355
+ else {
356
+ std::vector<double> peaks(ebur128->channels);
357
+ int (*get_peak)(ebur128_state*, unsigned int, double*) = config.true_peak ? ebur128_true_peak : ebur128_sample_peak;
358
+ for (double &pk : peaks)
359
+ get_peak(ebur128.get(), channel++, &pk);
360
+ track_peak = *std::max_element(peaks.begin(), peaks.end());
361
+
362
+ result.track_gain = (type == FileType::OPUS && config.opus_mode == 's' ? -23.0 : config.target_loudness)
363
+ - track_loudness;
364
+ result.track_peak = track_peak;
365
+ result.track_loudness = track_loudness;
366
+ }
367
}
368
369
void ScanJob::calculate_album_loudness()
370
371
size_t nb_states = tracks.size();
372
std::vector<ebur128_state*> states(nb_states);
373
for (const Track &track : tracks)
374
- states(size_t) (&track - &tracks0) = track.ebur128.get();
375
+ if (track.result.track_loudness != -HUGE_VAL)
376
+ states.emplace_back(track.ebur128.get());
377
378
- if (ebur128_loudness_global_multiple(states.data(), nb_states, &album_loudness) != EBUR128_SUCCESS)
379
+ if (ebur128_loudness_global_multiple(states.data(), states.size(), &album_loudness) != EBUR128_SUCCESS)
380
album_loudness = config.target_loudness;
381
382
album_peak = std::max_element(tracks.begin(),
383
tracks.end(),
384
- (const auto &a, const auto &b) {return a.result.track_peak < b.result.track_peak;}
385
+ (const auto &a, const auto &b) { return a.result.track_peak < b.result.track_peak; }
386
)->result.track_peak;
387
388
- double album_gain = config.target_loudness - album_loudness;
389
+ double album_gain = (type == FileType::OPUS && config.opus_mode == 's' ? -23.0 : config.target_loudness)
390
+ - album_loudness;
391
for (Track &track : tracks) {
392
track.result.album_gain = album_gain;
393
track.result.album_peak = album_peak;
394
rsgain-3.3-source.tar.xz/src/scan.hpp -> rsgain-3.5.1.tar.gz/src/scan.hpp
Changed
44
1
2
AIFF,
3
WAVPACK,
4
APE,
5
+ TAK,
6
MPC
7
};
8
9
10
class ScanJob {
11
public:
12
struct Track {
13
- std::string path;
14
+ std::filesystem::path path;
15
FileType type;
16
std::unique_ptr<ebur128_state, decltype(&free_ebur128)> ebur128;
17
std::string container;
18
19
bool tclip = false;
20
bool aclip = false;
21
22
- Track(const std::string &path, FileType type) : path(path), type(type), ebur128(nullptr, free_ebur128) {};
23
+ Track(const std::filesystem::path &path, FileType type) : path(path), type(type), ebur128(nullptr, free_ebur128) {};
24
bool scan(const Config &config, std::mutex *ffmpeg_mutex);
25
- bool calculate_loudness(const Config &config);
26
+ void calculate_loudness(const Config &config);
27
};
28
29
- std::string path;
30
+ std::filesystem::path path;
31
size_t nb_files;
32
const Config &config;
33
FileType type;
34
35
size_t clipping_adjustments = 0;
36
size_t skipped = 0;
37
38
- ScanJob(const std::string &path, std::vector<Track> &&tracks, const Config &config) : path(path), nb_files(tracks.size()), config(config), tracks(std::move(tracks)) {}
39
+ ScanJob(const std::filesystem::path &path, std::vector<Track> &tracks, const Config &config, FileType &type) : path(path), nb_files(tracks.size()), config(config), type(type), tracks(std::move(tracks)) {}
40
+ ScanJob(std::vector<Track> &tracks, const Config &config, FileType type) : nb_files(tracks.size()), config(config), type(type), tracks(std::move(tracks)) {}
41
static ScanJob* factory(char **files, size_t nb_files, const Config &config);
42
static ScanJob* factory(const std::filesystem::path &path);
43
bool scan(std::mutex *ffmpeg_mutex = nullptr);
44
rsgain-3.3-source.tar.xz/src/tag.cpp -> rsgain-3.5.1.tar.gz/src/tag.cpp
Changed
355
1
2
#include "output.hpp"
3
4
#define TAGLIB_VERSION (TAGLIB_MAJOR_VERSION * 10000 + TAGLIB_MINOR_VERSION * 100 + TAGLIB_PATCH_VERSION)
5
-#define FORMAT_GAIN(gain) fmt::format("{:.2f} dB", gain)
6
-#define FORMAT_PEAK(peak) fmt::format("{:.6f}", peak)
7
+#define FORMAT_GAIN(gain) format("{:.2f} dB", gain)
8
+#define FORMAT_PEAK(peak) format("{:.6f}", peak)
9
#define OPUS_HEADER_SIZE 47
10
#define OGG_ROW_SIZE 4
11
#define OPUS_HEAD_OFFSET 7 * OGG_ROW_SIZE
12
#define OGG_CRC_OFFSET 5 * OGG_ROW_SIZE + 2
13
+#define OGG_SEGMENT_TABLE_OFFSET 27
14
#define OPUS_GAIN_OFFSET 11 * OGG_ROW_SIZE
15
#define RG_TAGS_UPPERCASE 1
16
#define RG_TAGS_LOWERCASE 2
17
18
19
#define MP4_ATOM_STRING "----:com.apple.iTunes:"
20
#define FORMAT_MP4_TAG(s, tag) s.append(MP4_ATOM_STRING).append(tag)
21
-#define tag_error(t) output_error("Couldn't write to: {}", t.path)
22
+#define tag_error(t) output_error("Couldn't write to: {}", t.path.string())
23
24
using RGTagsArray = std::array<TagLib::String, 7>;
25
26
27
static void tag_write(TagLib::Ogg::XiphComment *tag, const ScanResult &result, const Config &config);
28
static void tag_clear(TagLib::MP4::Tag *tag);
29
static void tag_write(TagLib::MP4::Tag *tag, const ScanResult &result, const Config &config);
30
-static void tag_clearv2(TagLib::APE::Tag *tag);
31
-static void tag_writev2(TagLib::APE::Tag *tag, const ScanResult &result, const Config &config);
32
+static void tag_clear(TagLib::APE::Tag *tag);
33
+static void tag_write(TagLib::APE::Tag *tag, const ScanResult &result, const Config &config);
34
static void tag_clear(TagLib::ASF::Tag *tag);
35
static void tag_write(TagLib::ASF::Tag *tag, const ScanResult &result, const Config &config);
36
37
38
39
void tag_track(ScanJob::Track &track, const Config &config)
40
{
41
+ std::filesystem::file_time_type mtime;
42
+ if (config.preserve_mtimes)
43
+ mtime = std::filesystem::last_write_time(track.path);
44
+
45
switch (track.type) {
46
case FileType::MP2:
47
case FileType::MP3:
48
49
if (!tag_apev2<TagLib::WavPack::File>(track, config))
50
tag_error(track);
51
break;
52
-
53
+
54
case FileType::APE:
55
+ case FileType::TAK:
56
if (!tag_apev2<TagLib::APE::File>(track, config))
57
tag_error(track);
58
break;
59
60
default:
61
break;
62
}
63
+ if (config.preserve_mtimes)
64
+ std::filesystem::last_write_time(track.path, mtime);
65
}
66
67
bool tag_exists(const ScanJob::Track &track)
68
69
70
case FileType::WAVPACK:
71
return tag_exists_ape<TagLib::WavPack::File>(track);
72
-
73
+
74
case FileType::APE:
75
+ case FileType::TAK:
76
return tag_exists_ape<TagLib::APE::File>(track);
77
78
case FileType::MPC:
79
80
static bool tag_exists_id3(const ScanJob::Track &track)
81
{
82
const TagLib::ID3v2::Tag *tag = nullptr;
83
- T file(track.path.c_str(), false);
84
+ T file(track.path.string().c_str(), false);
85
if constexpr (std::is_same_v<T, TagLib::RIFF::AIFF::File>)
86
tag = file.tag();
87
else
88
89
{
90
bool ret = false;
91
const TagLib::Ogg::XiphComment *tag = nullptr;
92
- T file(track.path.c_str(), false);
93
+ T file(track.path.string().c_str(), false);
94
if constexpr(std::is_same_v<T, TagLib::FLAC::File>)
95
tag = file.xiphComment();
96
else
97
98
}
99
}
100
101
- TagLib::MP4::File file(track.path.c_str(), false);
102
+ TagLib::MP4::File file(track.path.string().c_str(), false);
103
const TagLib::MP4::Tag *tag = file.tag();
104
if (tag) {
105
for (const auto &key : keys) {
106
107
template<typename T>
108
static bool tag_exists_ape(const ScanJob::Track &track)
109
{
110
- T file(track.path.c_str(), false);
111
+ T file(track.path.string().c_str(), false);
112
const TagLib::APE::Tag *tag = file.APETag();
113
if (tag) {
114
const auto &map = tag->itemListMap();
115
116
117
static bool tag_exists_asf(const ScanJob::Track &track)
118
{
119
- TagLib::ASF::File file(track.path.c_str(), false);
120
+ TagLib::ASF::File file(track.path.string().c_str(), false);
121
const TagLib::ASF::Tag *tag = file.tag();
122
return tag->contains(RG_STRING_UPPERstatic_cast<int>(RGTag::TRACK_GAIN)) ||
123
tag->contains(RG_STRING_LOWERstatic_cast<int>(RGTag::TRACK_GAIN));
124
125
126
static bool tag_mp3(ScanJob::Track &track, const Config &config)
127
{
128
- TagLib::MPEG::File file(track.path.c_str());
129
+ TagLib::MPEG::File file(track.path.string().c_str());
130
TagLib::ID3v2::Tag *tag = file.ID3v2Tag(true);
131
+ if (!tag)
132
+ return false;
133
unsigned int id3v2version = config.id3v2version;
134
if (id3v2version == ID3V2_KEEP)
135
id3v2version = tag->isEmpty() ? 3: tag->header()->majorVersion();
136
137
138
static bool tag_flac(ScanJob::Track &track, const Config &config)
139
{
140
- TagLib::FLAC::File file(track.path.c_str());
141
+ TagLib::FLAC::File file(track.path.string().c_str());
142
TagLib::Ogg::XiphComment *tag = file.xiphComment(true);
143
+ if (!tag)
144
+ return false;
145
tag_clear<TagLib::FLAC::File>(tag);
146
if (config.tag_mode == 'i')
147
tag_write<TagLib::FLAC::File>(tag, track.result, config);
148
149
150
template<typename T>
151
static bool tag_ogg(ScanJob::Track &track, const Config &config) {
152
- T file(track.path.c_str());
153
+ T file(track.path.string().c_str());
154
TagLib::Ogg::XiphComment *tag = nullptr;
155
- if constexpr(std::is_same_v<T, TagLib::FileRef>) {
156
+ if constexpr(std::is_same_v<T, TagLib::FileRef>)
157
tag = dynamic_cast<TagLib::Ogg::XiphComment*>(file.tag());
158
- if (!tag)
159
- return false;
160
- }
161
else
162
tag = file.tag();
163
+ if (!tag)
164
+ return false;
165
tag_clear<T>(tag);
166
if (config.tag_mode == 'i' && (!std::is_same_v<T, TagLib::Ogg::Opus::File> ||
167
(config.opus_mode != 't' && config.opus_mode != 'a')))
168
169
170
bool ret = file.save();
171
if (!std::is_same_v<T, TagLib::Ogg::Opus::File> || config.tag_mode == 's' ||
172
- config.opus_mode == 'd' || config.opus_mode == 'r' || !ret)
173
+ !(config.opus_mode == 't' || config.opus_mode == 'a') || !ret)
174
return ret;
175
176
int16_t gain = config.opus_mode == 'a' && config.do_album ?
177
GAIN_TO_Q78(track.result.album_gain) : GAIN_TO_Q78(track.result.track_gain);
178
- return set_opus_header_gain(track.path.c_str(), gain);
179
+ return set_opus_header_gain(track.path.string().c_str(), gain);
180
}
181
182
static bool tag_mp4(ScanJob::Track &track, const Config &config)
183
{
184
- TagLib::MP4::File file(track.path.c_str());
185
+ TagLib::MP4::File file(track.path.string().c_str());
186
TagLib::MP4::Tag *tag = file.tag();
187
+ if (!tag)
188
+ return false;
189
tag_clear(tag);
190
if (config.tag_mode == 'i')
191
tag_write(tag, track.result, config);
192
193
template <typename T>
194
static bool tag_apev2(ScanJob::Track &track, const Config &config)
195
{
196
- T file(track.path.c_str());
197
+ T file(track.path.string().c_str());
198
TagLib::APE::Tag *tag = file.APETag(true);
199
- tag_clearv2(tag);
200
+ if (!tag)
201
+ return false;
202
+ tag_clear(tag);
203
if (config.tag_mode == 'i')
204
- tag_writev2(tag, track.result, config);
205
+ tag_write(tag, track.result, config);
206
if constexpr(!std::is_same_v<T, TagLib::MPC::File>)
207
return file.save();
208
else {
209
bool ret = file.save();
210
if (ret)
211
- ret = set_mpc_packet_rg(track.path.c_str());
212
+ ret = set_mpc_packet_rg(track.path.string().c_str());
213
return ret;
214
}
215
}
216
217
static bool tag_wma(ScanJob::Track &track, const Config &config)
218
{
219
- TagLib::ASF::File file(track.path.c_str());
220
+ TagLib::ASF::File file(track.path.string().c_str());
221
TagLib::ASF::Tag *tag = file.tag();
222
+ if (!tag)
223
+ return false;
224
tag_clear(tag);
225
if (config.tag_mode == 'i')
226
tag_write(tag, track.result, config);
227
228
template<typename T>
229
static bool tag_riff(ScanJob::Track &track, const Config &config)
230
{
231
- T file(track.path.c_str());
232
- TagLib::ID3v2::Tag *tag;
233
+ T file(track.path.string().c_str());
234
+ TagLib::ID3v2::Tag *tag = nullptr;
235
if constexpr (std::is_same_v<T, TagLib::RIFF::WAV::File>)
236
tag = file.ID3v2Tag();
237
else if constexpr (std::is_same_v<T, TagLib::RIFF::AIFF::File>)
238
tag = file.tag();
239
+ if (!tag)
240
+ return false;
241
unsigned int id3v2version = config.id3v2version;
242
if (id3v2version == ID3V2_KEEP)
243
id3v2version = tag->isEmpty() ? 3: tag->header()->majorVersion();
244
245
const RGTagsArray &RG_STRING = RG_STRING_UPPER;
246
247
// Opus RFC 7845 tag
248
- if (std::is_same_v<T, TagLib::Ogg::Opus::File> && config.opus_mode == 'r') {
249
+ if (std::is_same_v<T, TagLib::Ogg::Opus::File> && (config.opus_mode == 'r' || config.opus_mode == 's')) {
250
tag->addField(R128_STRINGstatic_cast<int>(R128Tag::TRACK_GAIN),
251
- fmt::format("{}", GAIN_TO_Q78(result.track_gain))
252
+ format("{}", GAIN_TO_Q78(result.track_gain))
253
);
254
255
if (config.do_album) {
256
tag->addField(R128_STRINGstatic_cast<int>(R128Tag::ALBUM_GAIN),
257
- fmt::format("{}", GAIN_TO_Q78(result.album_gain))
258
+ format("{}", GAIN_TO_Q78(result.album_gain))
259
);
260
}
261
}
262
263
);
264
}
265
266
-static void tag_clearv2(TagLib::APE::Tag *tag)
267
+static void tag_clear(TagLib::APE::Tag *tag)
268
{
269
tag_clear_map<RG_TAGS_UPPERCASE>(
270
&(const TagLib::String &t) {
271
272
);
273
}
274
275
-static void tag_writev2(TagLib::APE::Tag *tag, const ScanResult &result, const Config &config)
276
+static void tag_write(TagLib::APE::Tag *tag, const ScanResult &result, const Config &config)
277
{
278
const RGTagsArray &RG_STRING = RG_STRING_UPPER;
279
write_rg_tags(result,
280
281
static_assert(-1 == ~0); // 2's complement for signed integers
282
bool set_opus_header_gain(const char *path, int16_t gain)
283
{
284
- char bufferOPUS_HEADER_SIZE; // 47 bytes
285
uint32_t crc;
286
if constexpr(std::endian::native == std::endian::big)
287
gain = static_cast<int16_t>((gain << 8) & 0xff00) | ((gain >> 8) & 0x00ff);
288
289
- // Read header into memory
290
- std::unique_ptr<std::FILE, decltype(&fclose)> file(fopen(path, "rb+"), fclose);
291
- size_t read = fread(buffer, 1, sizeof(buffer), file.get());
292
+ std::unique_ptr<std::FILE, int (*)(FILE*)> file(fopen(path, "rb+"), fclose);
293
+ char buffer8;
294
+ size_t page_size = 0;
295
+ size_t opus_header_size = 0;
296
+
297
+ // Check for OggS header
298
+ if (fseek(file.get(), 0, SEEK_SET)
299
+ || fread(buffer, 1, 4, file.get()) != 4
300
+ || strncmp(buffer, "OggS", 4))
301
+ return false;
302
303
- // Make sure we have a valid Ogg/Opus header
304
- if (read != sizeof(buffer) || strncmp(buffer, "OggS", 4) ||
305
- strncmp(buffer + OPUS_HEAD_OFFSET, "OpusHead", 8))
306
+ // Check for OpusHead header
307
+ if (fseek(file.get(), OPUS_HEAD_OFFSET, SEEK_SET)
308
+ || fread(buffer, 1, 8, file.get()) != 8
309
+ || strncmp(buffer, "OpusHead", 8))
310
+ return false;
311
+
312
+ // Read the size of the Opus header
313
+ if (fseek(file.get(), OGG_SEGMENT_TABLE_OFFSET, SEEK_SET)
314
+ || fread((void*) &opus_header_size, 1, 1, file.get()) != 1)
315
+ return false;
316
+ page_size = OPUS_HEAD_OFFSET + opus_header_size;
317
+
318
+ // To verify the page size, make sure the next Ogg page is where we expect it
319
+ if (fseek(file.get(), page_size, SEEK_SET)
320
+ || fread(buffer, 1, 4, file.get()) != 4
321
+ || strncmp(buffer, "OggS", 4))
322
+ return false;
323
+
324
+ // Read the entire Ogg page into memory
325
+ auto page = std::make_unique<char>(page_size);
326
+ if (fseek(file.get(), 0, SEEK_SET)
327
+ || fread(page.get(), 1, page_size, file.get()) != page_size)
328
return false;
329
330
// Clear CRC, set gain
331
- memset(buffer + OGG_CRC_OFFSET, 0, sizeof(crc));
332
- memcpy(buffer + OPUS_GAIN_OFFSET, &gain, sizeof(gain));
333
-
334
+ memset(page.get() + OGG_CRC_OFFSET, 0, sizeof(crc));
335
+ memcpy(page.get() + OPUS_GAIN_OFFSET, &gain, sizeof(gain));
336
+
337
// Calculate new CRC
338
static const CRC::Table<uint32_t, 32> table({0x04C11DB7, 0, 0, false, false});
339
- crc = CRC::Calculate(buffer, sizeof(buffer), table);
340
-
341
+ crc = CRC::Calculate(page.get(), page_size, table);
342
+
343
// Write new CRC and gain to file
344
fseek(file.get(), OGG_CRC_OFFSET, SEEK_SET);
345
fwrite(&crc, sizeof(crc), 1, file.get());
346
347
std::FILE *fp = fopen(path, "rb+");
348
if (fp == nullptr)
349
return false;
350
- std::unique_ptr<std::FILE, decltype(&fclose)> file(fp, fclose);
351
+ std::unique_ptr<std::FILE, int (*)(FILE*)> file(fp, fclose);
352
353
fseek(fp, 0L, SEEK_END);
354
size_t nb_bytes = static_cast<size_t>(ftell(fp));
355
rsgain-3.3-source.tar.xz/vcpkg.json -> rsgain-3.5.1.tar.gz/vcpkg.json
Changed
60
1
2
{
3
"dependencies":
4
- {
5
- "name": "libebur128",
6
- "platform": "windows"
7
- },
8
"taglib",
9
{
10
- "name": "ffmpeg",
11
- "platform": "windows",
12
- "default-features": false,
13
- "features": "avcodec", "avformat", "swresample", "fdk-aac"
14
- },
15
- {
16
- "name": "fdk-aac",
17
- "platform": "windows",
18
- "features": "he-aac"
19
- },
20
- "fmt",
21
- {
22
- "name": "inih",
23
- "platform": "windows"
24
- },
25
- {
26
"name": "getopt",
27
"platform": "windows"
28
}
29
-
30
+ ,
31
+ "features": {
32
+ "fmt": {
33
+ "description": "Use the fmtlib library for formatting",
34
+ "dependencies": "fmt"
35
+ },
36
+ "ffmpeg": {
37
+ "description": "Build FFmpeg",
38
+ "dependencies":
39
+ {
40
+ "name": "ffmpeg",
41
+ "default-features": false,
42
+ "features": "avcodec", "avformat", "swresample", "fdk-aac"
43
+ },
44
+ {
45
+ "name": "fdk-aac",
46
+ "features": "he-aac"
47
+ }
48
+
49
+ },
50
+ "libebur128": {
51
+ "description": "Build libebur128",
52
+ "dependencies": "libebur128"
53
+ },
54
+ "inih": {
55
+ "description": "Build inih",
56
+ "dependencies": "inih"
57
+ }
58
+ }
59
}
60
Refresh
No build results available
Refresh
No rpmlint results available
Login required, please
login
or
signup
in order to comment
Request History
Aloysius created request about 1 year ago
Update to version 3·5.1
Aloysius accepted request about 1 year ago