Merge pull request #152273 from yuuyins/audacity

audacity: 3.0.2 -> 3.1.3

authored by Silvan Mosberger and committed by GitHub d29bef5c 3f68060f

+58 -390
-355
pkgs/applications/audio/audacity/0001-Use-a-different-approach-to-estimate-the-disk-space-.patch
··· 1 - From deeb435829d73524df851f6f4c2d4be552c99230 Mon Sep 17 00:00:00 2001 2 - From: Dmitry Vedenko <dmitry@crsib.me> 3 - Date: Fri, 1 Oct 2021 16:21:22 +0300 4 - Subject: [PATCH] Use a different approach to estimate the disk space usage 5 - 6 - New a approach is a bit less precise, but removes the requirement for the "private" SQLite3 table and allows Audacity to be built against system SQLite3. 7 - --- 8 - cmake-proxies/sqlite/CMakeLists.txt | 5 - 9 - src/DBConnection.h | 4 +- 10 - src/ProjectFileIO.cpp | 269 +++++----------------------- 11 - 3 files changed, 44 insertions(+), 234 deletions(-) 12 - 13 - diff --git a/cmake-proxies/sqlite/CMakeLists.txt b/cmake-proxies/sqlite/CMakeLists.txt 14 - index 63d70637c..d7b9b95ef 100644 15 - --- a/cmake-proxies/sqlite/CMakeLists.txt 16 - +++ b/cmake-proxies/sqlite/CMakeLists.txt 17 - @@ -19,11 +19,6 @@ list( APPEND INCLUDES 18 - 19 - list( APPEND DEFINES 20 - PRIVATE 21 - - # 22 - - # We need the dbpage table for space calculations. 23 - - # 24 - - SQLITE_ENABLE_DBPAGE_VTAB=1 25 - - 26 - # Can't be set after a WAL mode database is initialized, so change 27 - # the default here to ensure all project files get the same page 28 - # size. 29 - diff --git a/src/DBConnection.h b/src/DBConnection.h 30 - index 16a7fc9d4..07d3af95e 100644 31 - --- a/src/DBConnection.h 32 - +++ b/src/DBConnection.h 33 - @@ -75,8 +75,8 @@ public: 34 - LoadSampleBlock, 35 - InsertSampleBlock, 36 - DeleteSampleBlock, 37 - - GetRootPage, 38 - - GetDBPage 39 - + GetSampleBlockSize, 40 - + GetAllSampleBlocksSize 41 - }; 42 - sqlite3_stmt *Prepare(enum StatementID id, const char *sql); 43 - 44 - diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp 45 - index 3b3e2e1fd..c9bc45af4 100644 46 - --- a/src/ProjectFileIO.cpp 47 - +++ b/src/ProjectFileIO.cpp 48 - @@ -35,6 +35,7 @@ Paul Licameli split from AudacityProject.cpp 49 - #include "widgets/ProgressDialog.h" 50 - #include "wxFileNameWrapper.h" 51 - #include "xml/XMLFileReader.h" 52 - +#include "MemoryX.h"` 53 - 54 - #undef NO_SHM 55 - #if !defined(__WXMSW__) 56 - @@ -2357,255 +2358,69 @@ int64_t ProjectFileIO::GetTotalUsage() 57 - } 58 - 59 - // 60 - -// Returns the amount of disk space used by the specified sample blockid or all 61 - -// of the sample blocks if the blockid is 0. It does this by using the raw SQLite 62 - -// pages available from the "sqlite_dbpage" virtual table to traverse the SQLite 63 - -// table b-tree described here: https://www.sqlite.org/fileformat.html 64 - +// Returns the estimation of disk space used by the specified sample blockid or all 65 - +// of the sample blocks if the blockid is 0. This does not include small overhead 66 - +// of the internal SQLite structures, only the size used by the data 67 - // 68 - int64_t ProjectFileIO::GetDiskUsage(DBConnection &conn, SampleBlockID blockid /* = 0 */) 69 - { 70 - - // Information we need to track our travels through the b-tree 71 - - typedef struct 72 - - { 73 - - int64_t pgno; 74 - - int currentCell; 75 - - int numCells; 76 - - unsigned char data[65536]; 77 - - } page; 78 - - std::vector<page> stack; 79 - - 80 - - int64_t total = 0; 81 - - int64_t found = 0; 82 - - int64_t right = 0; 83 - - int rc; 84 - + sqlite3_stmt* stmt = nullptr; 85 - 86 - - // Get the rootpage for the sampleblocks table. 87 - - sqlite3_stmt *stmt = 88 - - conn.Prepare(DBConnection::GetRootPage, 89 - - "SELECT rootpage FROM sqlite_master WHERE tbl_name = 'sampleblocks';"); 90 - - if (stmt == nullptr || sqlite3_step(stmt) != SQLITE_ROW) 91 - + if (blockid == 0) 92 - { 93 - - return 0; 94 - - } 95 - - 96 - - // And store it in our first stack frame 97 - - stack.push_back({sqlite3_column_int64(stmt, 0)}); 98 - + static const char* statement = 99 - +R"(SELECT 100 - + sum(length(blockid) + length(sampleformat) + 101 - + length(summin) + length(summax) + length(sumrms) + 102 - + length(summary256) + length(summary64k) + 103 - + length(samples)) 104 - +FROM sampleblocks;)"; 105 - 106 - - // All done with the statement 107 - - sqlite3_clear_bindings(stmt); 108 - - sqlite3_reset(stmt); 109 - - 110 - - // Prepare/retrieve statement to read raw database page 111 - - stmt = conn.Prepare(DBConnection::GetDBPage, 112 - - "SELECT data FROM sqlite_dbpage WHERE pgno = ?1;"); 113 - - if (stmt == nullptr) 114 - - { 115 - - return 0; 116 - + stmt = conn.Prepare(DBConnection::GetAllSampleBlocksSize, statement); 117 - } 118 - - 119 - - // Traverse the b-tree until we've visited all of the leaf pages or until 120 - - // we find the one corresponding to the passed in sample blockid. Because we 121 - - // use an integer primary key for the sampleblocks table, the traversal will 122 - - // be in ascending blockid sequence. 123 - - do 124 - + else 125 - { 126 - - // Acces the top stack frame 127 - - page &pg = stack.back(); 128 - + static const char* statement = 129 - +R"(SELECT 130 - + length(blockid) + length(sampleformat) + 131 - + length(summin) + length(summax) + length(sumrms) + 132 - + length(summary256) + length(summary64k) + 133 - + length(samples) 134 - +FROM sampleblocks WHERE blockid = ?1;)"; 135 - 136 - - // Read the page from the sqlite_dbpage table if it hasn't yet been loaded 137 - - if (pg.numCells == 0) 138 - - { 139 - - // Bind the page number 140 - - sqlite3_bind_int64(stmt, 1, pg.pgno); 141 - + stmt = conn.Prepare(DBConnection::GetSampleBlockSize, statement); 142 - + } 143 - 144 - - // And retrieve the page 145 - - if (sqlite3_step(stmt) != SQLITE_ROW) 146 - + auto cleanup = finally( 147 - + [stmt]() { 148 - + // Clear statement bindings and rewind statement 149 - + if (stmt != nullptr) 150 - { 151 - - // REVIEW: Likely harmless failure - says size is zero on 152 - - // this error. 153 - - // LLL: Yea, but not much else we can do. 154 - - return 0; 155 - + sqlite3_clear_bindings(stmt); 156 - + sqlite3_reset(stmt); 157 - } 158 - + }); 159 - 160 - - // Copy the page content to the stack frame 161 - - memcpy(&pg.data, 162 - - sqlite3_column_blob(stmt, 0), 163 - - sqlite3_column_bytes(stmt, 0)); 164 - - 165 - - // And retrieve the total number of cells within it 166 - - pg.numCells = get2(&pg.data[3]); 167 - - 168 - - // Reset statement for next usage 169 - - sqlite3_clear_bindings(stmt); 170 - - sqlite3_reset(stmt); 171 - - } 172 - - 173 - - //wxLogDebug("%*.*spgno %lld currentCell %d numCells %d", (stack.size() - 1) * 2, (stack.size() - 1) * 2, "", pg.pgno, pg.currentCell, pg.numCells); 174 - - 175 - - // Process an interior table b-tree page 176 - - if (pg.data[0] == 0x05) 177 - - { 178 - - // Process the next cell if we haven't examined all of them yet 179 - - if (pg.currentCell < pg.numCells) 180 - - { 181 - - // Remember the right-most leaf page number. 182 - - right = get4(&pg.data[8]); 183 - - 184 - - // Iterate over the cells. 185 - - // 186 - - // If we're not looking for a specific blockid, then we always push the 187 - - // target page onto the stack and leave the loop after a single iteration. 188 - - // 189 - - // Otherwise, we match the blockid against the highest integer key contained 190 - - // within the cell and if the blockid falls within the cell, we stack the 191 - - // page and stop the iteration. 192 - - // 193 - - // In theory, we could do a binary search for a specific blockid here, but 194 - - // because our sample blocks are always large, we will get very few cells 195 - - // per page...usually 6 or less. 196 - - // 197 - - // In both cases, the stacked page can be either an internal or leaf page. 198 - - bool stacked = false; 199 - - while (pg.currentCell < pg.numCells) 200 - - { 201 - - // Get the offset to this cell using the offset in the cell pointer 202 - - // array. 203 - - // 204 - - // The cell pointer array starts immediately after the page header 205 - - // at offset 12 and the retrieved offset is from the beginning of 206 - - // the page. 207 - - int celloff = get2(&pg.data[12 + (pg.currentCell * 2)]); 208 - - 209 - - // Bump to the next cell for the next iteration. 210 - - pg.currentCell++; 211 - - 212 - - // Get the page number this cell describes 213 - - int pagenum = get4(&pg.data[celloff]); 214 - - 215 - - // And the highest integer key, which starts at offset 4 within the cell. 216 - - int64_t intkey = 0; 217 - - get_varint(&pg.data[celloff + 4], &intkey); 218 - - 219 - - //wxLogDebug("%*.*sinternal - right %lld celloff %d pagenum %d intkey %lld", (stack.size() - 1) * 2, (stack.size() - 1) * 2, " ", right, celloff, pagenum, intkey); 220 - - 221 - - // Stack the described page if we're not looking for a specific blockid 222 - - // or if this page contains the given blockid. 223 - - if (!blockid || blockid <= intkey) 224 - - { 225 - - stack.push_back({pagenum, 0, 0}); 226 - - stacked = true; 227 - - break; 228 - - } 229 - - } 230 - - 231 - - // If we pushed a new page onto the stack, we need to jump back up 232 - - // to read the page 233 - - if (stacked) 234 - - { 235 - - continue; 236 - - } 237 - - } 238 - + if (blockid != 0) 239 - + { 240 - + int rc = sqlite3_bind_int64(stmt, 1, blockid); 241 - 242 - - // We've exhausted all the cells with this page, so we stack the right-most 243 - - // leaf page. Ensure we only process it once. 244 - - if (right) 245 - - { 246 - - stack.push_back({right, 0, 0}); 247 - - right = 0; 248 - - continue; 249 - - } 250 - - } 251 - - // Process a leaf table b-tree page 252 - - else if (pg.data[0] == 0x0d) 253 - + if (rc != SQLITE_OK) 254 - { 255 - - // Iterate over the cells 256 - - // 257 - - // If we're not looking for a specific blockid, then just accumulate the 258 - - // payload sizes. We will be reading every leaf page in the sampleblocks 259 - - // table. 260 - - // 261 - - // Otherwise we break out when we find the matching blockid. In this case, 262 - - // we only ever look at 1 leaf page. 263 - - bool stop = false; 264 - - for (int i = 0; i < pg.numCells; i++) 265 - - { 266 - - // Get the offset to this cell using the offset in the cell pointer 267 - - // array. 268 - - // 269 - - // The cell pointer array starts immediately after the page header 270 - - // at offset 8 and the retrieved offset is from the beginning of 271 - - // the page. 272 - - int celloff = get2(&pg.data[8 + (i * 2)]); 273 - - 274 - - // Get the total payload size in bytes of the described row. 275 - - int64_t payload = 0; 276 - - int digits = get_varint(&pg.data[celloff], &payload); 277 - - 278 - - // Get the integer key for this row. 279 - - int64_t intkey = 0; 280 - - get_varint(&pg.data[celloff + digits], &intkey); 281 - - 282 - - //wxLogDebug("%*.*sleaf - celloff %4d intkey %lld payload %lld", (stack.size() - 1) * 2, (stack.size() - 1) * 2, " ", celloff, intkey, payload); 283 - - 284 - - // Add this payload size to the total if we're not looking for a specific 285 - - // blockid 286 - - if (!blockid) 287 - - { 288 - - total += payload; 289 - - } 290 - - // Otherwise, return the payload size for a matching row 291 - - else if (blockid == intkey) 292 - - { 293 - - return payload; 294 - - } 295 - - } 296 - + conn.ThrowException(false); 297 - } 298 - + } 299 - 300 - - // Done with the current branch, so pop back up to the previous one (if any) 301 - - stack.pop_back(); 302 - - } while (!stack.empty()); 303 - - 304 - - // Return the total used for all sample blocks 305 - - return total; 306 - -} 307 - - 308 - -// Retrieves a 2-byte big-endian integer from the page data 309 - -unsigned int ProjectFileIO::get2(const unsigned char *ptr) 310 - -{ 311 - - return (ptr[0] << 8) | ptr[1]; 312 - -} 313 - - 314 - -// Retrieves a 4-byte big-endian integer from the page data 315 - -unsigned int ProjectFileIO::get4(const unsigned char *ptr) 316 - -{ 317 - - return ((unsigned int) ptr[0] << 24) | 318 - - ((unsigned int) ptr[1] << 16) | 319 - - ((unsigned int) ptr[2] << 8) | 320 - - ((unsigned int) ptr[3]); 321 - -} 322 - - 323 - -// Retrieves a variable length integer from the page data. Returns the 324 - -// number of digits used to encode the integer and the stores the 325 - -// value at the given location. 326 - -int ProjectFileIO::get_varint(const unsigned char *ptr, int64_t *out) 327 - -{ 328 - - int64_t val = 0; 329 - - int i; 330 - + int rc = sqlite3_step(stmt); 331 - 332 - - for (i = 0; i < 8; ++i) 333 - + if (rc != SQLITE_ROW) 334 - { 335 - - val = (val << 7) + (ptr[i] & 0x7f); 336 - - if ((ptr[i] & 0x80) == 0) 337 - - { 338 - - *out = val; 339 - - return i + 1; 340 - - } 341 - + conn.ThrowException(false); 342 - } 343 - 344 - - val = (val << 8) + (ptr[i] & 0xff); 345 - - *out = val; 346 - + const int64_t size = sqlite3_column_int64(stmt, 0); 347 - 348 - - return 9; 349 - + return size; 350 - } 351 - 352 - InvisibleTemporaryProject::InvisibleTemporaryProject() 353 - -- 354 - 2.33.1 355 -
···
+58 -35
pkgs/applications/audio/audacity/default.nix
··· 3 , fetchFromGitHub 4 , fetchpatch 5 , cmake 6 , pkg-config 7 , python3 8 , gettext ··· 20 , libsndfile 21 , soxr 22 , flac 23 , twolame 24 , expat 25 , libid3tag 26 , libopus 27 , ffmpeg_4 28 , soundtouch 29 , pcre 30 - /*, portaudio - given up fighting their portaudio.patch */ 31 , linuxHeaders 32 , alsa-lib 33 , at-spi2-core ··· 36 , libXdmcp 37 , libXtst 38 , libpthreadstubs 39 , libselinux 40 , libsepol 41 , libxkbcommon 42 , util-linux 43 , wxGTK 44 , AppKit ? null 45 , AudioToolbox ? null 46 , AudioUnit ? null ··· 58 59 let 60 inherit (lib) optionals; 61 62 wxWidgets_src = fetchFromGitHub { 63 - owner = "audacity"; 64 repo = "wxWidgets"; 65 - rev = "07e7d832c7a337aedba3537b90b2c98c4d8e2985"; 66 - sha256 = "1mawnkcrmqj98jp0jxlnh9xkc950ca033ccb51c7035pzmi9if9a"; 67 fetchSubmodules = true; 68 }; 69 ··· 74 wxmac' = wxmac.overrideAttrs (oldAttrs: rec { 75 src = wxWidgets_src; 76 }); 77 - 78 - in 79 - stdenv.mkDerivation rec { 80 - pname = "audacity"; 81 - # nixpkgs-update: no auto update 82 - # Humans too! Let's wait to see how the situation with 83 - # https://github.com/audacity/audacity/issues/1213 develops before 84 - # pulling any updates that are subject to this privacy policy. We 85 - # may wish to switch to a fork, but at the time of writing 86 - # (2021-07-05) it's too early to tell how well any of the forks will 87 - # be maintained. 88 - version = "3.0.2"; 89 90 src = fetchFromGitHub { 91 - owner = "audacity"; 92 - repo = "audacity"; 93 rev = "Audacity-${version}"; 94 - sha256 = "035qq2ff16cdl2cb9iply2bfjmhfl1dpscg79x6c9l0i9m8k41zj"; 95 }; 96 97 - patches = [ 98 - (fetchpatch { 99 - url = "https://github.com/audacity/audacity/commit/7f8135e112a0e1e8e906abab9339680d1e491441.patch"; 100 - sha256 = "0zp2iydd46analda9cfnbmzdkjphz5m7dynrdj5qdnmq6j3px9fw"; 101 - name = "audacity_xdg_paths.patch"; 102 - }) 103 - # This is required to make audacity work with nixpkgs’ sqlite 104 - # https://github.com/audacity/audacity/pull/1802 rebased onto 3.0.2 105 - ./0001-Use-a-different-approach-to-estimate-the-disk-space-.patch 106 - ]; 107 - 108 postPatch = '' 109 - touch src/RevisionIdent.h 110 '' + lib.optionalString stdenv.isLinux '' 111 - substituteInPlace src/FileNames.cpp \ 112 --replace /usr/include/linux/magic.h ${linuxHeaders}/include/linux/magic.h 113 ''; 114 ··· 119 python3 120 ] ++ optionals stdenv.isLinux [ 121 linuxHeaders 122 ]; 123 124 buildInputs = [ ··· 126 ffmpeg_4 127 file 128 flac 129 libid3tag 130 libjack2 131 libmad 132 libopus 133 libsndfile 134 libvorbis 135 lilv 136 lv2 137 pcre 138 serd 139 sord 140 soundtouch ··· 143 sratom 144 suil 145 twolame 146 ] ++ optionals stdenv.isLinux [ 147 alsa-lib # for portaudio 148 at-spi2-core ··· 154 libxkbcommon 155 libselinux 156 libsepol 157 util-linux 158 wxGTK' 159 wxGTK'.gtk ··· 163 Cocoa 164 CoreAudioKit 165 AudioUnit AudioToolbox CoreAudio CoreServices Carbon # for portaudio 166 ]; 167 168 cmakeFlags = [ 169 - "-Daudacity_use_ffmpeg=linked" 170 "-DDISABLE_DYNAMIC_LOADING_FFMPEG=ON" 171 ]; 172 173 doCheck = false; # Test fails 174 175 meta = with lib; { 176 description = "Sound editor with graphical UI"; 177 - homepage = "https://www.audacityteam.org/"; 178 - license = licenses.gpl2Plus; 179 maintainers = with maintainers; [ lheckemann veprbl ]; 180 platforms = platforms.unix; 181 }; 182 }
··· 3 , fetchFromGitHub 4 , fetchpatch 5 , cmake 6 + , makeWrapper 7 , pkg-config 8 , python3 9 , gettext ··· 21 , libsndfile 22 , soxr 23 , flac 24 + , lame 25 , twolame 26 , expat 27 , libid3tag 28 , libopus 29 + , libuuid 30 , ffmpeg_4 31 , soundtouch 32 , pcre 33 + , portaudio # given up fighting their portaudio.patch? 34 + , portmidi 35 , linuxHeaders 36 , alsa-lib 37 , at-spi2-core ··· 40 , libXdmcp 41 , libXtst 42 , libpthreadstubs 43 + , libsbsms_2_3_0 44 , libselinux 45 , libsepol 46 , libxkbcommon 47 , util-linux 48 , wxGTK 49 + , libpng 50 + , libjpeg 51 , AppKit ? null 52 , AudioToolbox ? null 53 , AudioUnit ? null ··· 65 66 let 67 inherit (lib) optionals; 68 + pname = "audacity"; 69 + version = "3.1.3"; 70 71 wxWidgets_src = fetchFromGitHub { 72 + owner = pname; 73 repo = "wxWidgets"; 74 + rev = "v${version}-${pname}"; 75 + sha256 = "sha256-KrmYYv23DHBYKIuxMYBioCQ2e4KWdgmuREnimtm0XNU="; 76 fetchSubmodules = true; 77 }; 78 ··· 83 wxmac' = wxmac.overrideAttrs (oldAttrs: rec { 84 src = wxWidgets_src; 85 }); 86 + in stdenv.mkDerivation rec { 87 + inherit pname version; 88 89 src = fetchFromGitHub { 90 + owner = pname; 91 + repo = pname; 92 rev = "Audacity-${version}"; 93 + sha256 = "sha256-sdI4paxIHDZgoWTCekjrkFR4JFpQC6OatcnJdVXCCZk="; 94 }; 95 96 postPatch = '' 97 + mkdir src/private 98 '' + lib.optionalString stdenv.isLinux '' 99 + substituteInPlace libraries/lib-files/FileNames.cpp \ 100 --replace /usr/include/linux/magic.h ${linuxHeaders}/include/linux/magic.h 101 ''; 102 ··· 107 python3 108 ] ++ optionals stdenv.isLinux [ 109 linuxHeaders 110 + makeWrapper 111 ]; 112 113 buildInputs = [ ··· 115 ffmpeg_4 116 file 117 flac 118 + lame 119 libid3tag 120 libjack2 121 libmad 122 libopus 123 + libsbsms_2_3_0 124 libsndfile 125 libvorbis 126 lilv 127 lv2 128 pcre 129 + portmidi 130 serd 131 sord 132 soundtouch ··· 135 sratom 136 suil 137 twolame 138 + portaudio 139 ] ++ optionals stdenv.isLinux [ 140 alsa-lib # for portaudio 141 at-spi2-core ··· 147 libxkbcommon 148 libselinux 149 libsepol 150 + libuuid 151 util-linux 152 wxGTK' 153 wxGTK'.gtk ··· 157 Cocoa 158 CoreAudioKit 159 AudioUnit AudioToolbox CoreAudio CoreServices Carbon # for portaudio 160 + libpng 161 + libjpeg 162 ]; 163 164 cmakeFlags = [ 165 + "-DAUDACITY_REV_LONG=nixpkgs" 166 + "-DAUDACITY_REV_TIME=nixpkgs" 167 "-DDISABLE_DYNAMIC_LOADING_FFMPEG=ON" 168 + "-Daudacity_conan_enabled=Off" 169 + "-Daudacity_use_ffmpeg=loaded" 170 ]; 171 172 doCheck = false; # Test fails 173 174 + # Replace audacity's wrapper, to: 175 + # - put it in the right place, it shouldn't be in "$out/audacity" 176 + # - Add the ffmpeg dynamic dependency 177 + postInstall = lib.optionalString stdenv.isLinux '' 178 + rm "$out/audacity" 179 + wrapProgram "$out/bin/audacity" \ 180 + --prefix LD_LIBRARY_PATH : "$out/lib/audacity":${lib.makeLibraryPath [ ffmpeg_4 ]} \ 181 + --suffix AUDACITY_MODULES_PATH : "$out/lib/audacity/modules" \ 182 + --suffix AUDACITY_PATH : "$out/share/audacity" 183 + ''; 184 + 185 meta = with lib; { 186 description = "Sound editor with graphical UI"; 187 + homepage = "https://www.audacityteam.org"; 188 + changelog = "https://github.com/audacity/audacity/releases"; 189 + license = with licenses; [ 190 + gpl2Plus 191 + # Must be GPL3 when building with "technologies that require it, 192 + # such as the VST3 audio plugin interface". 193 + # https://github.com/audacity/audacity/discussions/2142. 194 + gpl3 195 + # Documentation. 196 + cc-by-30 197 + ]; 198 maintainers = with maintainers; [ lheckemann veprbl ]; 199 platforms = platforms.unix; 200 + # darwin-aarch due to qtbase broken for it. 201 + # darwin-x86_64 due to 202 + # https://logs.nix.ci/?attempt_id=5cbc4581-09b4-4148-82fe-0326411a56b3&key=nixos%2Fnixpkgs.152273. 203 + broken = stdenv.isDarwin; 204 }; 205 }