Overview

Request 6060 (accepted)

Update to version 3·5.1

Submit package home:Aloysius:branches:Multimedia / rsgain to package Multimedia / rsgain

rsgain.changes Changed
x
 
1
@@ -1,4 +1,41 @@
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
@@ -1,6 +1,7 @@
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
@@ -16,39 +17,46 @@
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
@@ -13,10 +13,6 @@
2
 
3
   workflow_dispatch:
4
 
5
-defaults:
6
-  run:
7
-    shell: bash
8
-
9
 permissions:
10
   actions: none
11
   checks: none
12
@@ -28,6 +24,11 @@
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
@@ -35,7 +36,6 @@
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
@@ -46,10 +46,12 @@
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
@@ -60,8 +62,9 @@
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
@@ -96,50 +99,73 @@
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
@@ -168,6 +194,15 @@
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
@@ -175,20 +210,57 @@
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
@@ -1,3 +1,28 @@
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
@@ -5,8 +5,13 @@
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
@@ -15,6 +20,7 @@
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
@@ -27,6 +33,23 @@
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
@@ -38,6 +61,27 @@
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
@@ -49,8 +93,6 @@
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
@@ -63,10 +105,6 @@
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
@@ -77,7 +115,15 @@
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
@@ -104,7 +150,7 @@
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
@@ -137,14 +183,28 @@
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,10 +214,15 @@
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
@@ -167,14 +232,11 @@
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
@@ -1,6 +1,6 @@
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
@@ -0,0 +1,28 @@
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
@@ -4,6 +4,12 @@
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
@@ -14,7 +20,7 @@
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
@@ -22,12 +28,12 @@
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,58 +45,101 @@
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
@@ -112,7 +161,7 @@
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
@@ -125,11 +174,12 @@
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
@@ -185,6 +235,12 @@
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
@@ -194,7 +250,7 @@
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
@@ -222,13 +278,14 @@
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
@@ -322,7 +379,7 @@
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
@@ -351,23 +408,23 @@
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
@@ -380,7 +437,7 @@
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
@@ -1,5 +1,5 @@
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
@@ -6,8 +6,9 @@
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
@@ -17,7 +18,8 @@
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
@@ -26,6 +28,7 @@
23
 #ClipMode=p
24
 #MaxPeakLevel=0.0
25
 #TruePeak=false
26
+#PreserveMtimes=false
27
 
28
 Ogg
29
 #TagMode=i
30
@@ -34,6 +37,7 @@
31
 #ClipMode=p
32
 #MaxPeakLevel=0.0
33
 #TruePeak=false
34
+#PreserveMtimes=false
35
 
36
 Opus
37
 #TagMode=i
38
@@ -43,6 +47,7 @@
39
 #MaxPeakLevel=0.0
40
 #TruePeak=false
41
 #OpusMode=d
42
+#PreserveMtimes=false
43
 
44
 M4A
45
 #TagMode=i
46
@@ -52,6 +57,8 @@
47
 #MaxPeakLevel=0.0
48
 #TruePeak=false
49
 #Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
 
53
 WMA
54
 #TagMode=i
55
@@ -61,6 +68,7 @@
56
 #MaxPeakLevel=0.0
57
 #TruePeak=false
58
 #Lowercase=false
59
+#PreserveMtimes=false
60
 
61
 MP2
62
 #TagMode=i
63
@@ -70,7 +78,8 @@
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
@@ -80,7 +89,8 @@
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
@@ -90,7 +100,8 @@
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
@@ -99,6 +110,7 @@
94
 #ClipMode=p
95
 #MaxPeakLevel=0.0
96
 #TruePeak=false
97
+#PreserveMtimes=false
98
 
99
 APE
100
 #TagMode=i
101
@@ -107,6 +119,16 @@
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
@@ -115,3 +137,4 @@
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
@@ -6,8 +6,9 @@
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
@@ -17,7 +18,8 @@
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
@@ -26,6 +28,7 @@
23
 #ClipMode=p
24
 #MaxPeakLevel=-1.0
25
 #TruePeak=true
26
+#PreserveMtimes=false
27
 
28
 Ogg
29
 #TagMode=i
30
@@ -34,6 +37,7 @@
31
 #ClipMode=p
32
 #MaxPeakLevel=-1.0
33
 #TruePeak=true
34
+#PreserveMtimes=false
35
 
36
 Opus
37
 #TagMode=i
38
@@ -43,6 +47,7 @@
39
 #MaxPeakLevel=-1.0
40
 #TruePeak=true
41
 #OpusMode=d
42
+#PreserveMtimes=false
43
 
44
 M4A
45
 #TagMode=i
46
@@ -52,6 +57,8 @@
47
 #MaxPeakLevel=-1.0
48
 #TruePeak=true
49
 #Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
 
53
 WMA
54
 #TagMode=i
55
@@ -61,6 +68,7 @@
56
 #MaxPeakLevel=-1.0
57
 #TruePeak=true
58
 #Lowercase=false
59
+#PreserveMtimes=false
60
 
61
 MP2
62
 #TagMode=i
63
@@ -70,7 +78,8 @@
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
@@ -80,7 +89,8 @@
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
@@ -90,7 +100,8 @@
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
@@ -99,6 +110,7 @@
94
 #ClipMode=p
95
 #MaxPeakLevel=-1.0
96
 #TruePeak=true
97
+#PreserveMtimes=false
98
 
99
 APE
100
 #TagMode=i
101
@@ -107,6 +119,16 @@
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
@@ -115,3 +137,4 @@
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
@@ -8,6 +8,7 @@
2
 Lowercase=true
3
 ID3v2Version=3
4
 OpusMode=r
5
+PreserveMtimes=false
6
 
7
 MP3
8
 #TagMode=i
9
@@ -18,6 +19,7 @@
10
 #TruePeak=true
11
 #Lowercase=true
12
 #ID3v2Version=3
13
+#PreserveMtimes=false
14
 
15
 FLAC
16
 #TagMode=i
17
@@ -26,6 +28,7 @@
18
 #ClipMode=a
19
 #MaxPeakLevel=-1.0
20
 #TruePeak=true
21
+#PreserveMtimes=false
22
 
23
 Ogg
24
 #TagMode=i
25
@@ -34,6 +37,7 @@
26
 #ClipMode=a
27
 #MaxPeakLevel=-1.0
28
 #TruePeak=true
29
+#PreserveMtimes=false
30
 
31
 Opus
32
 #TagMode=i
33
@@ -43,6 +47,7 @@
34
 #MaxPeakLevel=-1.0
35
 #TruePeak=true
36
 #OpusMode=r
37
+#PreserveMtimes=false
38
 
39
 M4A
40
 #TagMode=i
41
@@ -52,6 +57,8 @@
42
 #MaxPeakLevel=-1.0
43
 #TruePeak=true
44
 #Lowercase=true
45
+#SkipMP4=false
46
+#PreserveMtimes=false
47
 
48
 WMA
49
 #TagMode=i
50
@@ -61,6 +68,7 @@
51
 #MaxPeakLevel=-1.0
52
 #TruePeak=true
53
 #Lowercase=true
54
+#PreserveMtimes=false
55
 
56
 MP2
57
 #TagMode=i
58
@@ -71,6 +79,7 @@
59
 #TruePeak=true
60
 #Lowercase=true
61
 #ID3v2Version=3
62
+#PreserveMtimes=false
63
 
64
 WAV
65
 #TagMode=i
66
@@ -81,6 +90,7 @@
67
 #TruePeak=true
68
 #Lowercase=true
69
 #ID3v2Version=3
70
+#PreserveMtimes=false
71
 
72
 AIFF
73
 #TagMode=i
74
@@ -91,6 +101,7 @@
75
 #TruePeak=true
76
 #Lowercase=true
77
 #ID3v2Version=3
78
+#PreserveMtimes=false
79
 
80
 Wavpack
81
 #TagMode=i
82
@@ -99,6 +110,7 @@
83
 #ClipMode=a
84
 #MaxPeakLevel=-1.0
85
 #TruePeak=true
86
+#PreserveMtimes=false
87
 
88
 APE
89
 #TagMode=i
90
@@ -107,6 +119,16 @@
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
@@ -115,3 +137,4 @@
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
@@ -6,8 +6,9 @@
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
@@ -17,7 +18,8 @@
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
@@ -26,6 +28,7 @@
23
 #ClipMode=p
24
 #MaxPeakLevel=0.0
25
 #TruePeak=false
26
+#PreserveMtimes=false
27
 
28
 Ogg
29
 #TagMode=i
30
@@ -34,6 +37,7 @@
31
 #ClipMode=p
32
 #MaxPeakLevel=0.0
33
 #TruePeak=false
34
+#PreserveMtimes=false
35
 
36
 Opus
37
 #TagMode=i
38
@@ -43,6 +47,7 @@
39
 #MaxPeakLevel=0.0
40
 #TruePeak=false
41
 #OpusMode=d
42
+#PreserveMtimes=false
43
 
44
 M4A
45
 #TagMode=i
46
@@ -52,6 +57,8 @@
47
 #MaxPeakLevel=0.0
48
 #TruePeak=false
49
 #Lowercase=false
50
+#SkipMP4=false
51
+#PreserveMtimes=false
52
 
53
 WMA
54
 #TagMode=i
55
@@ -61,6 +68,7 @@
56
 #MaxPeakLevel=0.0
57
 #TruePeak=false
58
 #Lowercase=false
59
+#PreserveMtimes=false
60
 
61
 MP2
62
 #TagMode=i
63
@@ -70,7 +78,8 @@
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
@@ -80,7 +89,8 @@
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
@@ -90,7 +100,8 @@
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
@@ -99,6 +110,7 @@
94
 #ClipMode=p
95
 #MaxPeakLevel=0.0
96
 #TruePeak=false
97
+#PreserveMtimes=false
98
 
99
 APE
100
 #TagMode=i
101
@@ -107,6 +119,16 @@
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
@@ -115,3 +137,4 @@
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
@@ -4,6 +4,7 @@
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
@@ -0,0 +1,31 @@
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,22 +2,28 @@
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
@@ -53,7 +59,7 @@
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
@@ -113,8 +119,7 @@
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
@@ -0,0 +1,181 @@
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
@@ -1,9 +1,14 @@
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
@@ -23,7 +28,6 @@
17
     ${LIBSWRESAMPLE}
18
     ${TAGLIB}
19
     ${LIBEBUR128}
20
-    ${FMT}
21
     ${GETOPT}
22
     ${INIH}
23
     FDK-AAC::fdk-aac
24
@@ -31,6 +35,7 @@
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
@@ -45,12 +50,28 @@
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
@@ -19,8 +19,6 @@
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
@@ -29,7 +27,7 @@
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
@@ -52,9 +50,11 @@
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
@@ -68,9 +68,11 @@
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
@@ -84,9 +86,11 @@
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
@@ -100,9 +104,11 @@
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
@@ -116,9 +122,11 @@
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
@@ -132,9 +140,11 @@
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
@@ -148,9 +158,11 @@
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
@@ -164,9 +176,11 @@
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
@@ -180,9 +194,11 @@
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
@@ -196,9 +212,11 @@
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
@@ -212,9 +230,11 @@
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
@@ -228,11 +248,31 @@
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
@@ -244,9 +284,11 @@
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
@@ -320,13 +362,10 @@
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
@@ -347,7 +386,7 @@
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
@@ -378,6 +417,7 @@
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
@@ -472,6 +512,15 @@
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
@@ -500,68 +549,71 @@
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
@@ -572,7 +624,7 @@
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
@@ -631,24 +683,23 @@
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
@@ -687,7 +738,7 @@
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
@@ -702,15 +753,15 @@
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
@@ -721,11 +772,11 @@
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
@@ -736,22 +787,22 @@
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
@@ -759,42 +810,46 @@
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
@@ -6,7 +6,6 @@
2
 #include <mutex>
3
 #include <filesystem>
4
 #include <condition_variable>
5
-#include <fmt/core.h>
6
 #include "scan.hpp"
7
 
8
 class WorkerThread {
9
@@ -35,5 +34,5 @@
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
@@ -48,7 +48,6 @@
2
 #include <sys/ioctl.h>
3
 #endif
4
 
5
-#include <fmt/core.h>
6
 #include "output.hpp"
7
 #include "config.h"
8
 
9
@@ -63,9 +62,6 @@
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
@@ -85,17 +81,17 @@
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
@@ -121,7 +117,7 @@
41
 
42
    delete buffer;
43
    buffer = nullptr;
44
-   fmt::print("\n");
45
+   print("\n");
46
 }
47
 
48
 inline int ProgressBar::get_console_width()
49
@@ -148,7 +144,7 @@
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
@@ -49,7 +49,18 @@
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    "&#x1b;1;32m"
19
 #define COLOR_YELLOW   "&#x1b;1;33m"
20
@@ -76,16 +87,16 @@
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
@@ -103,7 +114,7 @@
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
@@ -45,8 +45,11 @@
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
@@ -55,10 +58,10 @@
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
@@ -156,6 +159,22 @@
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
@@ -163,25 +182,26 @@
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
@@ -195,9 +215,12 @@
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
@@ -235,12 +258,9 @@
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
@@ -249,6 +269,10 @@
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
@@ -291,7 +315,7 @@
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
@@ -307,8 +331,8 @@
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
@@ -362,53 +386,53 @@
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
@@ -416,33 +440,35 @@
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
@@ -450,26 +476,36 @@
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
@@ -477,8 +513,8 @@
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
@@ -1,8 +1,8 @@
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
@@ -29,9 +29,12 @@
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
@@ -40,7 +43,8 @@
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
@@ -73,6 +73,7 @@
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
@@ -80,6 +81,7 @@
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
@@ -95,16 +97,20 @@
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
@@ -112,16 +118,25 @@
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
@@ -171,11 +186,11 @@
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
@@ -190,21 +205,22 @@
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
@@ -226,6 +242,8 @@
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
@@ -234,7 +252,7 @@
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
@@ -272,7 +290,7 @@
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
@@ -322,7 +340,7 @@
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
@@ -345,16 +363,13 @@
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
@@ -362,8 +377,6 @@
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
@@ -394,8 +407,11 @@
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
@@ -429,15 +445,12 @@
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
@@ -483,10 +496,12 @@
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
@@ -502,52 +517,60 @@
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
@@ -557,7 +580,7 @@
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
@@ -580,27 +603,33 @@
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
@@ -609,17 +638,19 @@
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
@@ -21,6 +21,7 @@
2
     AIFF,
3
     WAVPACK,
4
     APE,
5
+   TAK,
6
    MPC
7
 };
8
 
9
@@ -49,7 +50,7 @@
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
@@ -58,12 +59,12 @@
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
@@ -71,7 +72,8 @@
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
@@ -65,12 +65,13 @@
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
@@ -78,7 +79,7 @@
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
@@ -105,8 +106,8 @@
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
@@ -167,6 +168,10 @@
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
@@ -237,8 +242,9 @@
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
@@ -251,6 +257,8 @@
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
@@ -283,8 +291,9 @@
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
@@ -300,7 +309,7 @@
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
@@ -327,7 +336,7 @@
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
@@ -358,7 +367,7 @@
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
@@ -372,7 +381,7 @@
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
@@ -383,7 +392,7 @@
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
@@ -402,8 +411,10 @@
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
@@ -423,8 +434,10 @@
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
@@ -433,15 +446,14 @@
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
@@ -449,18 +461,20 @@
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
@@ -471,25 +485,29 @@
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
@@ -500,12 +518,14 @@
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
@@ -614,14 +634,14 @@
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
@@ -661,7 +681,7 @@
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
@@ -670,7 +690,7 @@
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
@@ -704,28 +724,53 @@
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
@@ -739,7 +784,7 @@
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
@@ -1,29 +1,37 @@
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

Request History
Luigi Baldoni's avatar

Aloysius created request about 1 year ago

Update to version 3·5.1


Luigi Baldoni's avatar

Aloysius accepted request about 1 year ago