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 3 , fetchFromGitHub 4 4 , fetchpatch 5 5 , cmake 6 + , makeWrapper 6 7 , pkg-config 7 8 , python3 8 9 , gettext ··· 20 21 , libsndfile 21 22 , soxr 22 23 , flac 24 + , lame 23 25 , twolame 24 26 , expat 25 27 , libid3tag 26 28 , libopus 29 + , libuuid 27 30 , ffmpeg_4 28 31 , soundtouch 29 32 , pcre 30 - /*, portaudio - given up fighting their portaudio.patch */ 33 + , portaudio # given up fighting their portaudio.patch? 34 + , portmidi 31 35 , linuxHeaders 32 36 , alsa-lib 33 37 , at-spi2-core ··· 36 40 , libXdmcp 37 41 , libXtst 38 42 , libpthreadstubs 43 + , libsbsms_2_3_0 39 44 , libselinux 40 45 , libsepol 41 46 , libxkbcommon 42 47 , util-linux 43 48 , wxGTK 49 + , libpng 50 + , libjpeg 44 51 , AppKit ? null 45 52 , AudioToolbox ? null 46 53 , AudioUnit ? null ··· 58 65 59 66 let 60 67 inherit (lib) optionals; 68 + pname = "audacity"; 69 + version = "3.1.3"; 61 70 62 71 wxWidgets_src = fetchFromGitHub { 63 - owner = "audacity"; 72 + owner = pname; 64 73 repo = "wxWidgets"; 65 - rev = "07e7d832c7a337aedba3537b90b2c98c4d8e2985"; 66 - sha256 = "1mawnkcrmqj98jp0jxlnh9xkc950ca033ccb51c7035pzmi9if9a"; 74 + rev = "v${version}-${pname}"; 75 + sha256 = "sha256-KrmYYv23DHBYKIuxMYBioCQ2e4KWdgmuREnimtm0XNU="; 67 76 fetchSubmodules = true; 68 77 }; 69 78 ··· 74 83 wxmac' = wxmac.overrideAttrs (oldAttrs: rec { 75 84 src = wxWidgets_src; 76 85 }); 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"; 86 + in stdenv.mkDerivation rec { 87 + inherit pname version; 89 88 90 89 src = fetchFromGitHub { 91 - owner = "audacity"; 92 - repo = "audacity"; 90 + owner = pname; 91 + repo = pname; 93 92 rev = "Audacity-${version}"; 94 - sha256 = "035qq2ff16cdl2cb9iply2bfjmhfl1dpscg79x6c9l0i9m8k41zj"; 93 + sha256 = "sha256-sdI4paxIHDZgoWTCekjrkFR4JFpQC6OatcnJdVXCCZk="; 95 94 }; 96 95 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 96 postPatch = '' 109 - touch src/RevisionIdent.h 97 + mkdir src/private 110 98 '' + lib.optionalString stdenv.isLinux '' 111 - substituteInPlace src/FileNames.cpp \ 99 + substituteInPlace libraries/lib-files/FileNames.cpp \ 112 100 --replace /usr/include/linux/magic.h ${linuxHeaders}/include/linux/magic.h 113 101 ''; 114 102 ··· 119 107 python3 120 108 ] ++ optionals stdenv.isLinux [ 121 109 linuxHeaders 110 + makeWrapper 122 111 ]; 123 112 124 113 buildInputs = [ ··· 126 115 ffmpeg_4 127 116 file 128 117 flac 118 + lame 129 119 libid3tag 130 120 libjack2 131 121 libmad 132 122 libopus 123 + libsbsms_2_3_0 133 124 libsndfile 134 125 libvorbis 135 126 lilv 136 127 lv2 137 128 pcre 129 + portmidi 138 130 serd 139 131 sord 140 132 soundtouch ··· 143 135 sratom 144 136 suil 145 137 twolame 138 + portaudio 146 139 ] ++ optionals stdenv.isLinux [ 147 140 alsa-lib # for portaudio 148 141 at-spi2-core ··· 154 147 libxkbcommon 155 148 libselinux 156 149 libsepol 150 + libuuid 157 151 util-linux 158 152 wxGTK' 159 153 wxGTK'.gtk ··· 163 157 Cocoa 164 158 CoreAudioKit 165 159 AudioUnit AudioToolbox CoreAudio CoreServices Carbon # for portaudio 160 + libpng 161 + libjpeg 166 162 ]; 167 163 168 164 cmakeFlags = [ 169 - "-Daudacity_use_ffmpeg=linked" 165 + "-DAUDACITY_REV_LONG=nixpkgs" 166 + "-DAUDACITY_REV_TIME=nixpkgs" 170 167 "-DDISABLE_DYNAMIC_LOADING_FFMPEG=ON" 168 + "-Daudacity_conan_enabled=Off" 169 + "-Daudacity_use_ffmpeg=loaded" 171 170 ]; 172 171 173 172 doCheck = false; # Test fails 174 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 + 175 185 meta = with lib; { 176 186 description = "Sound editor with graphical UI"; 177 - homepage = "https://www.audacityteam.org/"; 178 - license = licenses.gpl2Plus; 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 + ]; 179 198 maintainers = with maintainers; [ lheckemann veprbl ]; 180 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; 181 204 }; 182 205 }