././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/0000755000175000017500000000000000000000000014670 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071152.0 rgain3-1.1.1/CHANGES.md0000644000175000017500000000454200000000000016267 0ustar00christianchristian00000000000000Changes ======= Unreleased ---------- rgain3 1.1.1 (2021-07-23) ------------------------- - Always convert tag values to strings, which fixes a `TypeError` when mutagen returns `bytes` values from audio metadata fields. (#38) rgain3 1.1.0 (2020-11-12) ------------------------- - Added support for Python 3.8 and 3.9 - Added this file to the source distribution - Added files necessary for the tests to the source distribution - Fixed some deprecation warnings rgain3 1.0.0 (2020-01-06) ------------------------- - Added support for Python 3.5, 3.6 and 3.7 - Dropped support for Python 2.7 - Fixed issue with MP3 files that did not contain ID3 headers rgain 1.3.4 (2016-05-06) ------------------------ - Support an additional format of MusicBrainz tags for MP3 files. - Album artist tags for MP3 files are now case-sensitive. - Fix a potential bug where custom reference levels would still store the default reference level (89 dB). - Update readme and PyPI description re: inactivity. rgain 1.3.3 (2014-10-09) ------------------------ - Fixed swapped album gain and track peak tags. rgain 1.3.2 (2014-05-24) ------------------------ - Fixed some problems with non-UTF8 file names. They should now work as long as any file names touched by **rgain** match the system encoding. (https://bitbucket.org/fk/rgain/issue/12/unicodedecodeerror-ascii-codec-cant-decode) - Misc. bug fixes. rgain 1.3.1 (2013-11-29) ------------------------ - Support MP4/AAC (courtesy of Yevgeny Bezman). rgain 1.3 (2013-10-28) ---------------------- - Work around a bug in some pygobject 3.10 releases (https://bugzilla.gnome.org/show_bug.cgi?id=710447) - Properly recognise file extensions even with different capitalisation. - Overhaul album ID algorithm to be hopefully better at grouping files that belong to an album and, conversely, not mis-grouping files. Note that this change will invalidate any cache files you might still have so your entire collection will be re-scanned next time you run **collectiongain**. - Assorted bug fixes. rgain 1.2.1 (2013-10-18) ------------------------ - Fix issue with reading MP3 reference loudness tags. rgain 1.2 (2013-05-04) ---------------------- - Port to GStreamer 1.0. - Support default GStreamer command-line options for **replaygain** and **collectiongain**. All known GStreamer options can be listed by using the **--help-gst** flag. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/COPYING0000644000175000017500000004325400000000000015733 0ustar00christianchristian00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/MANIFEST.in0000644000175000017500000000031600000000000016426 0ustar00christianchristian00000000000000include CHANGES.md include COPYING include MANIFEST.in include man/* include requirements.txt include test-requirements.txt include test/data/*.flac include test/data/*.mp3 include tests.sh include tox.ini ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8643498 rgain3-1.1.1/PKG-INFO0000644000175000017500000000333200000000000015766 0ustar00christianchristian00000000000000Metadata-Version: 2.1 Name: rgain3 Version: 1.1.1 Summary: Multi-format Replay Gain utilities Home-page: https://github.com/chaudum/rgain Author: Felix Krull Author-email: f_krull@gmx.de Maintainer: Christian Haudum Maintainer-email: christian@christianhaudum.at License: GNU General Public License (v2 or later) Description: A set of Python modules and utility programmes to deal with Replay Gain information -- calculate it (with GStreamer), read and write it (with Mutagen). It has support for Ogg Vorbis (or probably anything stored in an Ogg container), Flac, WavPack, MP4 (aka AAC) and MP3 (in different incarnations). There‘s also a command-line programme, ``replaygain``, that works very similar to its like-named cousins, most prominently ``vorbisgain`` and ``mp3gain`` -- only that itworks for all those supported formats alike. ``collectiongain`` on the other hand is a kind of fire-and-forget tool for big amounts of music files. Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: End Users/Desktop Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.5 Provides-Extra: test ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/README.md0000644000175000017500000001760300000000000016156 0ustar00christianchristian00000000000000**This repository is a fork of Felix Krull's `rgain` repository on Bitbucket which aims to port the codebase to a modern Python 3 version.** # rgain3 -- ReplayGain tools and Python library This Python package provides modules to read, write and calculate Replay Gain as well as 2 scripts that utilize these modules to do Replay Gain. [Replay Gain][1] is a proposed standard (and has been for some time -- but it's widely accepted) that's designed to solve the problem of varying volumes between different audio files. I won't lay it all out for you here, go read it yourself. ## Requirements - Python >= 3.5 -- http://python.org/ - GStreamer -- http://gstreamer.org/ - Cairo 2D -- https://www.cairographics.org/ To install these dependencies on Debian or Ubuntu (16.10 or newer): ```console $ apt install \ gir1.2-gstreamer-1.0 \ gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly \ libcairo2-dev \ libgirepository1.0-dev \ python3 ``` You will also need GStreamer decoding plugins for any audio formats you want to use. ## Installation Just install it like any other Python package using `pip`: ```console $ python3 -m pip install --user rgain3 ``` ## `replaygain` This is a program like, say, **vorbisgain** or **mp3gain**, the difference being that instead of supporting a mere one format, it supports several: - Ogg Vorbis (or probably anything you can put into an Ogg container) - Flac - WavPack - MP4 (commonly using the AAC codec) - MP3 Basic usage is simple: ```console $ replaygain AUDIOFILE1 AUDIOFILE2 ... ``` There are some options; see them by running: ```console $ replaygain --help ``` ## `collectiongain` This program is designed to apply Replay Gain to whole music collections, plus the ability to simply add new files, run **collectiongain** and have it replay-gain those files without asking twice. To use it, simply run: ```console $ collectiongain PATH_TO_MUSIC ``` and re-run it whenever you add new files. Run: ```console $ collectiongain --help ``` to see possible options. If, however, you want to find out how exactly **collectiongain** works, read on (but be warned: It's long, boring, technical, incomprehensible and awesome). **collectiongain** runs in two phases: The file collecting phase and the actual run. Prior to analyzing any audio data, **collectiongain** gathers all audio files in the directory and determines a so-called album ID for each from the file's tags: - If the file contains a Musicbrainz album ID, that is used. - Otherwise, if the file contains an *album* tag, it is joined with either * a MusicBrainz album artist ID, if that exists * an *albumartist* tag, if that exists, * or the *artist* tag * or nothing if none of the above tags exist. The resulting artist-album combination is the album ID for that file. - If the file doesn't contain a Musicbrainz album ID or an *album* tag, it is presumed to be a single track without album; it will only get track gain, no album gain. Since this step takes a relatively long time, the album IDs are cached between several runs of **collectiongain**. If a file was modified or a new file was added, the album ID will be (re-)calculated for that file only. The program will also cache an educated guess as to whether a file was already processed and had Replay Gain added -- if **collectiongain** thinks so, that file will totally ignored for the actual run. This flag is set whenever the file is processed in the actual run phase (save for dry runs, which you can enable with the **--dry-run** switch) and is cleared whenever a file was changed. You can pass the **ignore-cache** switch to make **collectiongain** totally ignore the cache; in that case, it will behave as if no cache was present and read your collection from scratch. For the actual run, **collectiongain** will simply look at all files that have survived the cleansing described above; for files that don't contain Replay Gain information, **collectiongain** will calculate it and write it to the files (use the **--force** flag to calculate gain even if the file already has gain data). Here comes the big moment of the album ID: files that have the same album ID are considered to be one album (duh) for the calculation of album gain. If only one file of an album is missing gain information, the whole album will be recalculated to make sure the data is up-to-date. ## MP3 formats Proper Replay Gain support for MP3 files is a bit of a mess: on the one hand, there is the **mp3gain** [application][2] which was relatively widely used (I don't know if it still is) -- it directly modifies the audio data which has the advantage that it works with pretty much any player, but it also means you have to decide ahead of time whether you want track gain or album gain. Besides, it's just not very elegant. On the other hand, there are at least two commonly used ways [to store proper Replay Gain information in ID3v2 tags][3]. Now, in general you don't have to worry about this when using this package: by default, **replaygain** and **collectiongain** will read and write Replay Gain information in the two most commonly used formats. However, if for whatever reason you need more control over the MP3 Replay Gain information, you can use the **--mp3-format** option (supported by both programs) to change the behaviour. Possible choices with this switch are: *replaygain.org* (alias: *fb2k*) Replay Gain information is stored in ID3v2 TXXX frames. This format is specified on the replaygain.org website as the recommended format for MP3 files. Notably, this format is also used by the [foobar2000 music player for Windows][4]. *legacy* (alias: *ql*) Replay Gain information is stored in ID3v2.4 RVA2 frames. This format is described as "legacy" by replaygain.org; however, it is still the primary format for at least the [Quod Libet music player][5] and possibly others. It should be noted that this format does not support volume adjustments of more than 64 dB: if the calculated gain value is smaller than -64 dB or greater than or equal to +64 dB, it is clamped to these limit values. *default* This is the default implementation used by both **replaygain** and **collectiongain**. When writing Replay Gain data, both the *replaygain.org* as well as the *legacy* format are written. As for reading, if a file contains data in both formats, both data sets are read and then compared. If they match up, that Replay Gain information is returned for the file. However, if they don't match, no Replay Gain data is returned to signal that this file does not contain valid (read: consistent) Replay Gain information. # Development Fork and clone this repository. Inside the checkout create a `virtualenv` and install `rgain3` in develop mode: Note that developing from source requires the Python headers and therefore the `python3.x-dev` system package to be installed. ```console $ python3 -m venv env $ source env/bin/activate (env) $ python -m pip install -Ue . ``` ### Running Tests To run the tests with the Python version of your current virtualenv, simply invoke `pytest` installing `test` extras: ```console (env) $ python -m pip install -Ue ".[test]" (env) $ pytest ``` You can run tests for all supported Python version using `tox` like so: ```console (env) $ tox ``` # Copyright With the exception of the manpages, all files are:: - Copyright (c) 2009-2015 Felix Krull - Copyright (c) 2019-2020 Christian Haudum The manpages were originally written for the Debian project and are:: - Copyright (c) 2011 Simon Chopin - Copyright (c) 2012-2015 Felix Krull [1]: https://wiki.hydrogenaud.io/index.php?title=ReplayGain [2]: http://mp3gain.sourceforce.net [3]: http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_specification#ID3v2 [4]: http://foobar2000.org [5]: http://code.google.com/p/quodlibet ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/man/0000755000175000017500000000000000000000000015443 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/man/collectiongain.rst0000644000175000017500000001000700000000000021165 0ustar00christianchristian00000000000000================ collectiongain ================ ------------------------------------------ large scale Replay Gain calculating tool ------------------------------------------ :Version: VERSION :Manual section: 1 :Manual group: rgain SYNOPSIS ======== | **collectiongain** [*options*] *music_dir* | **collectiongain** --help | **collectiongain** --version DESCRIPTION =========== **collectiongain** is a script calculating the Replay Gain values of a large set of music files inside *music_dir*. Files belonging to the same album will be identified using the file tags and album Replay Gain data will be calculated for them. OPTIONS ======= --version Display the version of the software. -h, --help Display a short summary of the available options. -f, --force Recalculate Replay Gain even if the file already contains gain information. -d, --dry-run Don't actually modify any files. -r REF, --reference-loudness=REF Set the reference loudness to REF dB (default: 89 dB) --mp3-format=MP3_FORMAT Choose the Replay Gain data format for MP3 files. The default setting should be compatible with most decent software music players, so it is generally not necessary to mess with this setting. See below for more information. --ignore-cache Do not use the file cache at all. --regain Fully reprocess everything. Same as ``--force --ignore-cache``. -j JOBS, --jobs=JOBS Run JOBS jobs simultaneously. Must be >= 1. By default, this is set to the number of CPU cores in the system to provide best performance. MP3 formats =========== Proper Replay Gain support for MP3 files is a bit of a mess: on the one hand, there is the **mp3gain** application [1] which was relatively widely used (I don't know if it still is) -- it directly modifies the audio data which has the advantage that it works with pretty much any player, but it also means you have to decide ahead of time whether you want track gain or album gain. Besides, it's just not very elegant. On the other hand, there are at least two commonly used ways to store proper Replay Gain information in ID3v2 tags [2]. Now, in general you don't have to worry about this when using this package: by default, **replaygain** and **collectiongain** will read and write Replay Gain information in the two most commonly used formats. However, if for whatever reason you need more control over the MP3 Replay Gain information, you can use the **--mp3-format** option (supported by both programs) to change the behaviour. Possible choices with this switch are: - *replaygain.org* (alias: *fb2k*) Replay Gain information is stored in ID3v2 TXXX frames. This format is specified on the replaygain.org website as the recommended format for MP3 files. Notably, this format is also used by the foobar2000 music player for Windows [3]. - *legacy* (alias: *ql*) Replay Gain information is stored in ID3v2.4 RVA2 frames. This format is described as "legacy" by replaygain.org; however, it is still the primary format for at least the Quod Libet music player [4] and possibly others. It should be noted that this format does not support volume adjustments of more than 64 dB: if the calculated gain value is smaller than -64 dB or greater than or equal to +64 dB, it is clamped to these limit values. - *default* This is the default implementation used by both **replaygain** and **collectiongain**. When writing Replay Gain data, both the *replaygain.org* as well as the *legacy* format are written. As for reading, if a file contains data in both formats, both data sets are read and then compared. If they match up, that Replay Gain information is returned for the file. However, if they don't match, no Replay Gain data is returned to signal that this file does not contain valid (read: consistent) Replay Gain information. [1] http://mp3gain.sourceforce.net [2] http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_specification#ID3v2 [3] http://foobar2000.org [4] http://code.google.com/p/quodlibet SEE ALSO ======== **replaygain(1)** ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/man/replaygain.rst0000644000175000017500000000753400000000000020341 0ustar00christianchristian00000000000000============ replaygain ============ -------------------------------- single file Replay Gain editor -------------------------------- :Version: VERSION :Manual section: 1 :Manual group: rgain SYNOPSIS ======== | **replaygain** [*options*] *AUDIO_FILE* [*AUDIO_FILE* ...] | **replaygain** --help | **replaygain** --version DESCRIPTION =========== **replaygain** applies or displays Replay Gain information for audio files. By default, all given files be assumed to be part of a single album and album gain data will be calculated for them. OPTIONS ======= --version Display the version of the software. -h, --help Display a short documentation. -f, --force Recalculate Replay Gain even if the file already contains gain information. -d, --dry-run Don't actually modify any files. -r REF, --reference-loudness=REF Set the reference loudness to REF dB (default: 89 dB) --mp3-format=MP3_FORMAT Choose the Replay Gain data format for MP3 files. The default setting should be compatible with most decent software music players, so it is generally not necessary to mess with this setting. See below for more information. --no-album Don't write any album gain information. --show Don't calculate anything, simply show Replay Gain information for the specified files. In this mode, all options other than **--mp3-format** are ignored. MP3 formats =========== Proper Replay Gain support for MP3 files is a bit of a mess: on the one hand, there is the **mp3gain** application [1] which was relatively widely used (I don't know if it still is) -- it directly modifies the audio data which has the advantage that it works with pretty much any player, but it also means you have to decide ahead of time whether you want track gain or album gain. Besides, it's just not very elegant. On the other hand, there are at least two commonly used ways to store proper Replay Gain information in ID3v2 tags [2]. Now, in general you don't have to worry about this when using this package: by default, **replaygain** and **collectiongain** will read and write Replay Gain information in the two most commonly used formats. However, if for whatever reason you need more control over the MP3 Replay Gain information, you can use the **--mp3-format** option (supported by both programs) to change the behaviour. Possible choices with this switch are: - *replaygain.org* (alias: *fb2k*) Replay Gain information is stored in ID3v2 TXXX frames. This format is specified on the replaygain.org website as the recommended format for MP3 files. Notably, this format is also used by the foobar2000 music player for Windows [3]. - *legacy* (alias: *ql*) Replay Gain information is stored in ID3v2.4 RVA2 frames. This format is described as "legacy" by replaygain.org; however, it is still the primary format for at least the Quod Libet music player [4] and possibly others. It should be noted that this format does not support volume adjustments of more than 64 dB: if the calculated gain value is smaller than -64 dB or greater than or equal to +64 dB, it is clamped to these limit values. - *default* This is the default implementation used by both **replaygain** and **collectiongain**. When writing Replay Gain data, both the *replaygain.org* as well as the *legacy* format are written. As for reading, if a file contains data in both formats, both data sets are read and then compared. If they match up, that Replay Gain information is returned for the file. However, if they don't match, no Replay Gain data is returned to signal that this file does not contain valid (read: consistent) Replay Gain information. [1] http://mp3gain.sourceforce.net [2] http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_specification#ID3v2 [3] http://foobar2000.org [4] http://code.google.com/p/quodlibet SEE ALSO ======== **collectiongain(1)** ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/requirements.txt0000644000175000017500000000004200000000000020150 0ustar00christianchristian00000000000000PyGObject>=3.34.0 mutagen>=1.43.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/rgain3/0000755000175000017500000000000000000000000016053 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/__init__.py0000644000175000017500000000464000000000000020170 0ustar00christianchristian00000000000000# Copyright (c) 2009-2015 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import enum from .version import __version__ __all__ = ["__version__", "GainData"] class GainType(enum.Enum): TP_UNDEFINED = "TP_UNDEFINED" TP_TRACK = "TP_TRACK" TP_ALBUM = "TP_ALBUM" class GainData: """A class that contains Replay Gain data. Arguments for ``__init__`` are also instance variables. These are: - ``gain``: the gain (in dB, relative to ``ref_level``) - ``peak``: the peak - ``ref_level``: the used reference level (in dB) """ def __init__(self, gain, peak=1.0, ref_level=89, gain_type=GainType.TP_UNDEFINED): self.gain = gain self.peak = peak self.ref_level = ref_level self.gain_type = gain_type def __str__(self): return "gain={.2f} dB; peak={.8f}; reference-level={} dB".format( self.gain, self.peak, self.ref_level ) def __repr__(self): return "{}({}, {}, {}, {})".format( self.__class__.__name__, self.gain, self.peak, self.ref_level, self.gain_type ) def __eq__(self, other): return isinstance(other, GainData) and ( self.gain == other.gain and self.peak == other.peak and self.ref_level == other.ref_level and self.gain_type == other.gain_type) def __ne__(self, other): return not self.__eq__(other) class GSTError(Exception): def __init__(self, gerror, debug): self.domain = gerror.domain self.code = gerror.code self.message = gerror.message self.debug = debug def __str__(self): return "GST error: {} ({})".format(self.message, self.debug) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/albumid.py0000644000175000017500000000762100000000000020050 0ustar00christianchristian00000000000000# Copyright (c) 2009-2015 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from functools import partial from mutagen.id3 import ID3FileType def _get_simple_tag(tags, mp3_keys, default_key): """Retrieve a tag value, using either one of a few MP3 tags or a generic one for other formats.""" if isinstance(tags, ID3FileType): for k in mp3_keys: frame = tags.get(k, None) if frame: return frame.text[0] else: vs = tags.get(default_key, None) if vs: return vs[0] # default fall-through return None get_musicbrainz_album_id = partial( _get_simple_tag, mp3_keys=[ "TXXX:MusicBrainz Album Id", "TXXX:MUSICBRAINZ_ALBUMID", ], default_key="musicbrainz_albumid", ) get_musicbrainz_albumartist_id = partial( _get_simple_tag, mp3_keys=[ "TXXX:MusicBrainz Album Artist Id", "TXXX:MUSICBRAINZ_ALBUMARTISTID", ], default_key="musicbrainz_albumartistid", ) get_musicbrainz_artist_id = partial( _get_simple_tag, mp3_keys=[ "TXXX:MusicBrainz Artist Id", "TXXX:MUSICBRAINZ_ARTISTID", ], default_key="musicbrainz_artistid", ) get_album = partial( _get_simple_tag, mp3_keys=["TALB"], default_key="album", ) get_artist = partial( _get_simple_tag, mp3_keys=["TPE1"], default_key="artist", ) # XXX: We're not doing case-insensitive checking anymore. Let's hope that # doesn't regress anything... # For MP3, in that order: # - a generic "TXXX:albumartist" # - QL's "TXXX:QuodLibet::albumartist" # - fb2k's legacy "TXXX:ALBUM ARTIST" # - finally, "TPE2" as used by at least fb2k and Picard. According to # the ID3 standard, this is performer, but fb2k uses it for album # artist since 1.1.6, citing "compatibility with other players"; see # http://wiki.hydrogenaudio.org/index.php?title=Foobar2000:ID3_Tag_Mapping get_albumartist = partial( _get_simple_tag, mp3_keys=[ "TXXX:albumartist", "TXXX:QuodLibet::albumartist", "TXXX:ALBUM ARTIST", "TPE2", ], default_key="albumartist", ) def _take_first_tag(tags, default, functions): """Return the first tag value that isn't None.""" for f in functions: value = f(tags) if value is not None: return value return default def get_album_id(tags): """Try to determine an album id based on the given tags. The basic logic is as follows: - If a MusicBrainz album ID exists, use that. - If an album tag exists, combine that with: - a MusicBrainz album artist ID if it exists, - otherwise an album artist tag if it exists, - otherwise an artist tag if it exists, - otherwise, nothing and use the result. - Otherwise, assume non-album track. """ mb_album_id = get_musicbrainz_album_id(tags) if mb_album_id is not None: return mb_album_id album = get_album(tags) if album is not None: artist_part = _take_first_tag(tags, None, [ get_musicbrainz_albumartist_id, get_albumartist, get_artist]) if artist_part is None: return album else: return "{} - {}".format(artist_part, album) else: return None ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/rgcalc.py0000644000175000017500000002457700000000000017677 0ustar00christianchristian00000000000000# Copyright (c) 2009-2015 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """Replay Gain analysis using GStreamer. See ``ReplayGain`` class for full documentation or use the ``calculate`` function. """ import gi gi.require_version('Gst', '1.0') from gi.repository import GLib, GObject, Gst # noqa isort:skip from rgain3 import GainData, GainType, GSTError, util # noqa isort:skip class MissingPluginsError(Exception): """We're most likely missing some GStreamer plugins.""" pass class ReplayGain(GObject.GObject): """Perform a Replay Gain analysis on some files. This class doesn't actually write any Replay Gain information - that is left as an exercise to the user. It only analyzes the files and presents the result. Basic usage is as follows: - instantiate the class, passing it a list of file names and optionally the reference loudness level to use (defaults to 89 dB), - connect to the signals the class provides, - get yourself a glib main loop (e.g. ``GLib.MainLoop`` or the one from GTK), - call ``replaygain_instance.start()`` to start processing, - start your main loop to dispatch events and - wait. Once you've done that, you can retrieve the data from ``track_data`` (which is a dict: keys are file names, values are ``GainData`` instances) and ``album_data`` (a 'GainData' instance, even though it may contain only ``None`` values if album gain isn't calculated). Note that the values don't contain any kind of unit, which might be needed. """ __gsignals__ = { "all-finished": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT)), "track-started": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), "track-finished": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING, GObject.TYPE_PYOBJECT)), "error": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_PYOBJECT,)), } def __init__(self, files, force=False, ref_lvl=89): super().__init__() self.files = files self.ref_lvl = ref_lvl # TODO: force is apparently unused now. Should remove it in a cleanup. self._setup_pipeline() self._setup_rg_elem() self._files_iter = iter(self.files) # this holds all track gain data self.track_data = {} self.album_data = GainData(0, ref_level=self.ref_lvl, gain_type=GainType.TP_ALBUM) def start(self): """Start processing. For it to work correctly, you'll need to run some GObject main loop (e.g. the Gtk one) or process any events manually (though I have no idea how or if that works). """ if not self._next_file(): raise ValueError("no file names supplied") self.pipe.set_state(Gst.State.PLAYING) def pause(self, pause): if pause: self.pipe.set_state(Gst.State.PAUSED) else: self.pipe.set_state(Gst.State.PLAYING) def stop(self): self.pipe.set_state(Gst.State.NULL) # internal stuff def _check_elem(self, elem): if elem is None: # that element couldn't be created, maybe because plugins are # missing? raise MissingPluginsError("failed to construct pipeline (did you " "install all necessary GStreamer " "plugins?)") else: return elem def _setup_pipeline(self): """Setup the pipeline.""" self.pipe = Gst.Pipeline() # elements self.src = self._check_elem(Gst.ElementFactory.make("filesrc", "src")) self.pipe.add(self.src) self.decbin = self._check_elem(Gst.ElementFactory.make("decodebin", "decbin")) self.pipe.add(self.decbin) self.conv = self._check_elem(Gst.ElementFactory.make("audioconvert", "conv")) self.pipe.add(self.conv) self.res = self._check_elem(Gst.ElementFactory.make("audioresample", "res")) self.pipe.add(self.res) self.rg = self._check_elem(Gst.ElementFactory.make("rganalysis", "rg")) self.pipe.add(self.rg) self.sink = self._check_elem(Gst.ElementFactory.make("fakesink", "sink")) self.pipe.add(self.sink) # Set num-tracks to the number of files we have to process so they're # all treated as one album. Fixes #8. self.rg.set_property("num-tracks", len(self.files)) # link self.src.link(self.decbin) self.conv.link(self.res) self.res.link(self.rg) self.rg.link(self.sink) self.decbin.connect("pad-added", self._on_pad_added) self.decbin.connect("pad-removed", self._on_pad_removed) bus = self.pipe.get_bus() bus.add_signal_watch() bus.connect("message", self._on_message) def _setup_rg_elem(self): # there's no way to specify 'forced', as it's usually useless self.rg.set_property("forced", True) self.rg.set_property("reference-level", self.ref_lvl) def _next_file(self): """Load the next file to analyze. Returns False if everything is done and the pipeline shouldn't be started again; True otherwise. """ # get the next file try: fname = next(self._files_iter) except StopIteration: self.emit("all-finished", self.track_data, self.album_data) return False # By default, GLib (and therefore GStreamer) assume any filename to be # UTF-8 encoded, regardless of locale settings (though most Unix # systems, Linux at least, should be configured for UTF-8 anyways these # days). The file name we pass to GStreamer is encoded with the system # default encoding here: if that's UTF-8, everyone's happy, if it isn't, # GLib's UTF-8 assumption needs to be overridden using the # G_FILENAME_ENCODING environment variable (set to locale to tell GLib # that all file names passed to it are encoded in the system encoding). # That way, people on non-UTF-8 systems or with non-UTF-8 file names can # still force all file name processing into a different encoding. self.src.set_property("location", fname) self._current_file = fname self.emit("track-started", fname) return True def _process_tags(self, msg): """Process a tag message.""" tags = msg.parse_tag() trackdata = self.track_data.setdefault( self._current_file, GainData(0, ref_level=self.ref_lvl, gain_type=GainType.TP_TRACK)) def handle_tag(taglist, tag, userdata): if tag == Gst.TAG_TRACK_GAIN: _, trackdata.gain = taglist.get_double(tag) elif tag == Gst.TAG_TRACK_PEAK: _, trackdata.peak = taglist.get_double(tag) elif tag == Gst.TAG_REFERENCE_LEVEL: _, trackdata.ref_level = taglist.get_double(tag) elif tag == Gst.TAG_ALBUM_GAIN: _, self.album_data.gain = taglist.get_double(tag) elif tag == Gst.TAG_ALBUM_PEAK: _, self.album_data.peak = taglist.get_double(tag) tags.foreach(handle_tag, None) # event handlers def _on_pad_added(self, decbin, new_pad): sinkpad = self.conv.get_compatible_pad(new_pad, None) if sinkpad is not None: new_pad.link(sinkpad) def _on_pad_removed(self, decbin, old_pad): peer = old_pad.get_peer() if peer is not None: old_pad.unlink(peer) def _on_message(self, bus, msg): if msg.type == Gst.MessageType.TAG: self._process_tags(msg) elif msg.type == Gst.MessageType.EOS: self.emit("track-finished", self._current_file, self.track_data[self._current_file]) # Preserve rganalysis state self.rg.set_locked_state(True) self.pipe.set_state(Gst.State.NULL) ret = self._next_file() if ret: self.pipe.set_state(Gst.State.PLAYING) # For some reason, GStreamer 1.0's rganalysis element produces # an error here unless a flush has been performed. pad = self.rg.get_static_pad("src") pad.send_event(Gst.Event.new_flush_start()) pad.send_event(Gst.Event.new_flush_stop(True)) self.rg.set_locked_state(False) elif msg.type == Gst.MessageType.ERROR: self.pipe.set_state(Gst.State.NULL) err, debug = msg.parse_error() self.emit("error", GSTError(err, debug)) def calculate(*args, **kwargs): """Analyze some files. This is only a convenience interface to the ``ReplayGain`` class: it takes the same arguments, but setups its own main loop and returns the results once everything's finished. """ exc_slot = [None] def on_finished(evsrc, trackdata, albumdata): # all done loop.quit() def on_error(evsrc, exc): exc_slot[0] = exc loop.quit() rg = ReplayGain(*args, **kwargs) with util.gobject_signals( rg, ("all-finished", on_finished), ("error", on_error),): loop = GLib.MainLoop() rg.start() loop.run() if exc_slot[0] is not None: raise exc_slot[0] return (rg.track_data, rg.album_data) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/rgio.py0000644000175000017500000003170600000000000017374 0ustar00christianchristian00000000000000# -*- coding: utf-8 -*- # # Copyright (c) 2009-2014 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import abc import os import warnings import mutagen from mutagen.easyid3 import EasyID3 from mutagen.id3._util import ID3NoHeaderError from rgain3 import GainData from rgain3.util import almost_equal, parse_db, parse_peak class AudioFormatError(Exception): def __init__(self, filename): super().__init__("Did not understand file: {}".format(filename)) # interface for ReplayGain reading/writing class class BaseTagReaderWriter(abc.ABC): @abc.abstractmethod def read_gain(self, filename): raise NotImplementedError() @abc.abstractmethod def write_gain(self, filename, track_gain, album_gain): raise NotImplementedError() # class to read and write ReplayGain data from/to simple tags. The default tags # match the rg.org specification for Ogg (at least Vorbis), Flac and WavPack # files class SimpleTagReaderWriter(BaseTagReaderWriter): TRACK_GAIN_TAG = "replaygain_track_gain" TRACK_PEAK_TAG = "replaygain_track_peak" ALBUM_GAIN_TAG = "replaygain_album_gain" ALBUM_PEAK_TAG = "replaygain_album_peak" REF_LOUDNESS_TAGS = ["replaygain_reference_loudness"] # default behaviour; override in a subclass if necessary, e.g. for MP3 def _get_tags_object(self, filename): return mutagen.File(filename) def read_gain(self, filename): tags = self._get_tags_object(filename) if tags is None: raise AudioFormatError(filename) track_gain = self._read_gain_data(tags, self.TRACK_GAIN_TAG, self.TRACK_PEAK_TAG) album_gain = self._read_gain_data(tags, self.ALBUM_GAIN_TAG, self.ALBUM_PEAK_TAG) ref_level = self._read_ref_loudness(tags) if ref_level is not None: if track_gain: track_gain.ref_level = ref_level if album_gain: album_gain.ref_level = ref_level return track_gain, album_gain def _read_gain_data(self, tags, gain_tag, peak_tag): if gain_tag in tags: gain = parse_db(tags[gain_tag][0]) if gain is None: return None gaindata = GainData(gain) if peak_tag in tags: peak = parse_peak(tags[peak_tag][0]) if peak is not None: gaindata.peak = peak else: gaindata = None return gaindata def _read_ref_loudness(self, tags): for tag in self.REF_LOUDNESS_TAGS: if tag in tags: ref_level = parse_db(tags[tag][0]) if ref_level is not None: return ref_level return None def write_gain(self, filename, track_gain, album_gain): tags = self._get_tags_object(filename) if tags is None: raise AudioFormatError(filename) if track_gain: tags[self.TRACK_GAIN_TAG] = self._dump_gain(track_gain.gain) tags[self.TRACK_PEAK_TAG] = self._dump_peak(track_gain.peak) for tag in self.REF_LOUDNESS_TAGS: tags[tag] = self._dump_ref_level(track_gain.ref_level) if album_gain: tags[self.ALBUM_GAIN_TAG] = self._dump_gain(album_gain.gain) tags[self.ALBUM_PEAK_TAG] = self._dump_peak(album_gain.peak) tags.save() def _dump_gain(self, gain): return "%.8f dB" % gain def _dump_peak(self, peak): return "%.8f" % peak def _dump_ref_level(self, ref_level): return "%i dB" % ref_level # MP4 support class MP4TagReaderWriter(SimpleTagReaderWriter): FORMAT = "----:com.apple.iTunes:replaygain_%s_%s" TRACK_GAIN_TAG = FORMAT % ("track", "gain") TRACK_PEAK_TAG = FORMAT % ("track", "peak") ALBUM_GAIN_TAG = FORMAT % ("album", "gain") ALBUM_PEAK_TAG = FORMAT % ("album", "peak") REF_LOUDNESS_TAGS = [] # Mutagen 1.22 has a bug (?) such that MP4 values cannot be unicode objects # so we encode everything to ASCII here # https://code.google.com/p/mutagen/issues/detail?id=164 def _dump_gain(self, gain): return SimpleTagReaderWriter._dump_gain(self, gain).encode("ascii") def _dump_peak(self, peak): return SimpleTagReaderWriter._dump_peak(self, peak).encode("ascii") def _dump_ref_level(self, ref_level): return SimpleTagReaderWriter._dump_ref_level( self, ref_level).encode("ascii") # MP3 support base class class MP3TagReaderWriter(SimpleTagReaderWriter): _EXTRA_TXXX_TAGS = [ "replaygain_track_gain", "replaygain_track_peak", "replaygain_album_gain", "replaygain_album_peak", "replaygain_reference_loudness", "QuodLibet::replaygain_reference_loudness", ] class _ReplaygainEasyID3(EasyID3): pass for key in _EXTRA_TXXX_TAGS: _ReplaygainEasyID3.RegisterTXXXKey("TXXX:%s" % key, key) def _get_tags_object(self, filename): try: return self._ReplaygainEasyID3(filename) except ID3NoHeaderError: tags = self._ReplaygainEasyID3() tags.filename = filename return tags # ID3v2 support for TXXX:replaygain_* frames as specified in # http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_specification#ID3v2 # and as implemented by at least foobar2000. class MP3rgorgTagReaderWriter(MP3TagReaderWriter): TRACK_GAIN_TAG = "TXXX:replaygain_track_gain" TRACK_PEAK_TAG = "TXXX:replaygain_track_peak" ALBUM_GAIN_TAG = "TXXX:replaygain_album_gain" ALBUM_PEAK_TAG = "TXXX:replaygain_album_peak" REF_LOUDNESS_TAGS = ["TXXX:replaygain_reference_loudness"] # clamp RVA2 values to certain limits so that they do not overflow RVA2_GAIN_MIN = -64 RVA2_GAIN_MAX = float(64 * 512 - 1) / 512.0 RVA2_PEAK_MIN = 0 RVA2_PEAK_MAX = float(2 ** 16 - 1) / float(2 ** 15) def clamp(v, min, max): clamped = False if v < min: v = min clamped = True if v > max: v = max clamped = True return v, clamped def clamp_rva2_gain(v): v, clamped = clamp(v, RVA2_GAIN_MIN, RVA2_GAIN_MAX) if clamped: warnings.warn("gain value was out of bounds for RVA2 frame and was " "clamped to %.2f" % v) return v # I'm not sure if this situation could even reasonably happen, but # can't hurt to check, right? Right!? def clamp_rva2_peak(v): v, clamped = clamp(v, RVA2_PEAK_MIN, RVA2_PEAK_MAX) if clamped: warnings.warn("peak value was out of bounds for RVA2 frame and was " "clamped to %.5f" % v) return v def clamp_gain_data(gain_data): if gain_data is None: return None else: return GainData(clamp_rva2_gain(gain_data.gain), clamp_rva2_peak(gain_data.peak), gain_data.ref_level) # ID3v2 support for legacy RVA2-frames-based format according to # http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_specification#ID3v2 class MP3RVA2TagReaderWriter(MP3TagReaderWriter): # EasyID3 maps these to RVA2 by default TRACK_GAIN_TAG = "replaygain_track_gain" TRACK_PEAK_TAG = "replaygain_track_peak" ALBUM_GAIN_TAG = "replaygain_album_gain" ALBUM_PEAK_TAG = "replaygain_album_peak" # since there's no proper reference loudness tag for the legacy format, we # use reasonably common TXXX tags; these were registered in the superclass REF_LOUDNESS_TAGS = [ "TXXX:replaygain_reference_loudness", "TXXX:QuodLibet::replaygain_reference_loudness", ] def _dump_gain(self, gain): return SimpleTagReaderWriter._dump_gain(self, clamp_rva2_gain(gain)) def _dump_peak(self, peak): return SimpleTagReaderWriter._dump_peak(self, clamp_rva2_peak(peak)) # Special compatible MP3 support that # - reads both rg.org and legacy gain, compares them, returns them if they # match, else returns no gain data # - writes both rg.org and legacy gain class MP3DefaultTagReaderWriter(BaseTagReaderWriter): def __init__(self, rgorg_readerwriter, rva2_readerwriter): self.rgorg = rgorg_readerwriter self.rva2 = rva2_readerwriter def read_gain(self, filename): rgorg_track_gain, rgorg_album_gain = self.rgorg.read_gain(filename) rva2_track_gain, rva2_album_gain = self.rva2.read_gain(filename) # We want to ensure we have all bits of data so if we only have one # format, we say we have none to enforce recalculation. if rgorg_track_gain is None or rva2_track_gain is None: # ensure that track gain exists for both return (None, None) if (not gaindata_almost_equal(rgorg_track_gain, rva2_track_gain) or not gaindata_almost_equal(rgorg_album_gain, rva2_album_gain)): # The different formats are not similar enough. return (None, None) else: # the formats seem to match, we obviously use the non-clamped one return (rgorg_track_gain, rgorg_album_gain) def write_gain(self, filename, track_gain, album_gain): self.rgorg.write_gain(filename, track_gain, album_gain) self.rva2.write_gain(filename, track_gain, album_gain) GAIN_EPSILON = 0.1 PEAK_EPSILON = 0.001 REF_LEVEL_EPSILON = 0.1 # For these three functions, b is always the legacy values, i.e. the # potentially clamped ones. def gain_almost_equal(a, b): return (almost_equal(a, b, GAIN_EPSILON) or almost_equal(clamp_rva2_gain(a), b, GAIN_EPSILON)) def peak_almost_equal(a, b): return (almost_equal(a, b, PEAK_EPSILON) or almost_equal(clamp_rva2_peak(a), b, PEAK_EPSILON)) def gaindata_almost_equal(a, b): # Ensure neither element is None. if a is None: return b is None if b is None: return a is None if a == b: return True with warnings.catch_warnings(): warnings.filterwarnings("ignore") return (gain_almost_equal(a.gain, b.gain) and peak_almost_equal(a.peak, b.peak) and almost_equal(a.ref_level, b.ref_level, REF_LEVEL_EPSILON)) # code to pull everything together class UnknownFiletype(Exception): pass class BaseFormatsMap(object): _simplereaderwriter = SimpleTagReaderWriter() _mp4readerwriter = MP4TagReaderWriter() _mp3_rgorg_readerwriter = MP3rgorgTagReaderWriter() _mp3_rva2_readerwriter = MP3RVA2TagReaderWriter() _mp3_default_readerwriter = MP3DefaultTagReaderWriter( _mp3_rgorg_readerwriter, _mp3_rva2_readerwriter) BASE_MAP = { ".ogg": _simplereaderwriter, ".oga": _simplereaderwriter, ".flac": _simplereaderwriter, ".wv": _simplereaderwriter, ".m4a": _mp4readerwriter, ".mp4": _mp4readerwriter, } MP3_FORMATS = { None: _mp3_default_readerwriter, "default": _mp3_default_readerwriter, "replaygain.org": _mp3_rgorg_readerwriter, "fb2k": _mp3_rgorg_readerwriter, "legacy": _mp3_rva2_readerwriter, "ql": _mp3_rva2_readerwriter, } MP3_DISPLAY_FORMATS = ["default", "replaygain.org", "legacy", "ql", "fb2k"] MP3_DEFAULT_FORMAT = "default" def __init__(self, mp3_format=None, more_mappings=None): # yeah, you need to choose self.more_mappings = more_mappings if more_mappings else {} if mp3_format in self.MP3_FORMATS: self.more_mappings[".mp3"] = self.MP3_FORMATS[mp3_format] else: raise ValueError("invalid MP3 format %r" % mp3_format) def is_supported_format(self, ext): ext_lower = ext.lower() return ext_lower in self.BASE_MAP or ext_lower in self.more_mappings def read_gain(self, filename): ext = os.path.splitext(filename)[1].lower() if ext in self.more_mappings: accessor = self.more_mappings[ext] elif ext in self.BASE_MAP: accessor = self.BASE_MAP[ext] else: raise UnknownFiletype(ext) return accessor.read_gain(filename) def write_gain(self, filename, trackgain, albumgain): ext = os.path.splitext(filename)[1].lower() if ext in self.more_mappings: accessor = self.more_mappings[ext] elif ext in self.BASE_MAP: accessor = self.BASE_MAP[ext] else: raise UnknownFiletype(ext) accessor.write_gain(filename, trackgain, albumgain) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/rgain3/script/0000755000175000017500000000000000000000000017357 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/script/__init__.py0000644000175000017500000000776300000000000021505 0ustar00christianchristian00000000000000# -*- coding: utf-8 -*- # # Copyright (c) 2009-2014 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import sys import traceback from optparse import OptionParser import gi gi.require_version("Gst", "1.0") from gi.repository import Gst # noqa isort:skip import rgain3.rgio # noqa isort:skip from rgain3 import __version__ # noqa isort:skip __all__ = [ "Error", "init_gstreamer", "common_options", ] class Error(Exception): def __init__(self, message, exc_info=None): super().__init__(message) # as long as instances are only constructed in exception handlers, this # should get us what we want self.exc_info = exc_info if exc_info else sys.exc_info() def __str__(self): if not self._output_full_exception(): return super().__str__() else: return "".join(traceback.format_exception(*self.exc_info)) def _output_full_exception(self): return self.exc_info[0] not in [ IOError, rgain3.rgio.AudioFormatError, rgain3.GSTError, ] def init_gstreamer(): """Properly initialise GStreamer for the command-line interfaces. Specifically, GStreamer options are parsed and processed by GStreamer, but it is also kept from taking over the main help output (by pretending -h or --help wasn't passed, if necessary). --help-gst should be documented in the main help output as a switch to display GStreamer options.""" # Strip any --help options from the command line. stripped_options = [] for opt in ["-h", "--help"]: if opt in sys.argv: sys.argv.remove(opt) stripped_options.append(opt) # Then, pass any remaining options to GStreamer. sys.argv = Gst.init(sys.argv) # Finally, restore any help options so optparse can eat them. for opt in stripped_options: sys.argv.append(opt) def common_options(): opts = OptionParser(version="%%prog %s" % __version__) opts.add_option("-f", "--force", help="Recalculate Replay Gain even if the " "file already contains gain information.", dest="force", action="store_true") opts.add_option("-d", "--dry-run", help="Don't actually modify any files.", dest="dry_run", action="store_true") opts.add_option("-r", "--reference-loudness", help="Set the reference " "loudness to REF dB (default: %default dB)", metavar="REF", dest="ref_level", action="store", type="int") opts.add_option("--mp3-format", help="Choose the Replay Gain data format " "for MP3 files. The default setting should be compatible " "with most decent software music players, so it is " "generally not necessary to mess with this setting. Check " "the README or man page for more information.", dest="mp3_format", action="store", type="choice", choices=rgain3.rgio.BaseFormatsMap.MP3_DISPLAY_FORMATS) # This option only exists to show up in the help output; if it's actually # specified, GStreamer should eat it. opts.add_option("--help-gst", help="Show GStreamer options.", dest="help_gst", action="store_true") opts.set_defaults( force=False, dry_run=False, ref_level=89, mp3_format="default") return opts ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/script/collectiongain.py0000644000175000017500000003074700000000000022736 0ustar00christianchristian00000000000000# -*- coding: utf-8 -*- # # Copyright (c) 2009-2014 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import contextlib import io import multiprocessing import os.path import pickle import sys from hashlib import md5 import mutagen from rgain3 import albumid, rgio from rgain3.script import Error, common_options, init_gstreamer from rgain3.script.replaygain import do_gain CURRENT_CACHE_VERSION = 1 # all of collectiongain def relpath(path, base): size = len(base) if os.path.basename(base): # this means ``base`` does not end with a separator size += 1 return path[size:] def cache_entry_valid(filepath, record): return ( isinstance(filepath, str) and hasattr(record, "__getitem__") and hasattr(record, "__len__") and len(record) == 3 and (isinstance(record[0], str) or record[0] is None) and (isinstance(record[1], int) or isinstance(record[1], float)) and isinstance(record[2], bool)) def read_cache(cache_file): if os.path.isfile(cache_file): try: with open(cache_file, "rb") as f: cache = pickle.load(f) if not isinstance(cache, tuple) or len(cache) != 2: print("Invalid cache, ignoring it") return {} cache_version = cache[0] if cache_version != CURRENT_CACHE_VERSION: print("Old cache format, ignoring it") return {} files = cache[1] if not isinstance(files, dict): print("Invalid cache, ignoring it") return {} to_remove = set() for filepath, record in files.items(): if not cache_entry_valid(filepath, record): to_remove.add(filepath) for filepath in to_remove: # remove fishy entries del files[filepath] return files except Exception as exc: print( "Error while reading the cache, continuing without it - %s" % (exc,)) return {} def write_cache(cache_file, files): cache_dir = os.path.dirname(cache_file) try: if not os.path.isdir(cache_dir): os.makedirs(cache_dir, 0o755) with open(cache_file, "wb") as f: pickle.dump((CURRENT_CACHE_VERSION, files), f, 2) except Exception as exc: print("Error while writing the cache - %s" % exc) def collect_files(music_dir, files, visited_cache, is_supported_format): i = 0 for dirpath, dirnames, filenames in os.walk(music_dir): for filename in filenames: filepath = relpath(os.path.join(dirpath, filename), music_dir) properpath = os.path.join(dirpath, filename) mtime = os.path.getmtime(properpath) # check the cache if filepath in visited_cache: visited_cache[filepath] = True record = files[filepath] if mtime <= record[1]: # the file's still ok continue ext = os.path.splitext(filename)[1] if is_supported_format(ext): i += 1 print(" [%i] %s |" % (i, filepath), end='') try: tags = mutagen.File(os.path.join(music_dir, filepath)) if tags is None: raise Exception() album_id = albumid.get_album_id(tags) print(album_id or "") # fields here: album_id, mtime, already_processed files[filepath] = (album_id, mtime, False) except Exception: # TODO: Maybe optionally abort here? print("IGNORED: unreadable file or unsupported format") def transform_cache(files): # transform ``files`` into lists of things to process albums = {} single_tracks = [] for filepath, (album_id, mtime, processed) in files.items(): if album_id is not None: albums.setdefault(album_id, []).append(filepath) else: single_tracks.append(filepath) # purge anything that's marked as processed for album_id, album_files in list(albums.items()): keep = False for filepath in album_files: if not files[filepath][2]: keep = True break if not keep: del albums[album_id] for filepath in single_tracks[:]: if files[filepath][2]: single_tracks.remove(filepath) return albums, single_tracks def update_cache(files, music_dir, tracks, album_id): for filepath in tracks: mtime = os.path.getmtime(os.path.join(music_dir, filepath)) files[filepath] = (album_id, mtime, True) @contextlib.contextmanager def stdstreams(stdout, stderr): old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = stdout sys.stderr = stderr try: yield finally: sys.stdout = old_stdout sys.stderr = old_stderr def do_gain_async(queue, job_key, files, ref_level, force, dry_run, album, mp3_format): output = io.StringIO() try: with stdstreams(output, output): if album: print("%s:" % job_key[1], end='') do_gain(files, ref_level, force, dry_run, album, mp3_format) print("") except BaseException as exc: # We can't reliably serialise and pass the exception information to the # driver process so we stringify it here. # And yes, we want to catch KeyboardInterrupt et al. queue.put((job_key, output.getvalue(), str(exc))) else: queue.put((job_key, output.getvalue(), None)) def do_gain_all(music_dir, albums, single_tracks, files, ref_level=89, force=False, dry_run=False, mp3_format=None, jobs=0, stop_on_error=False): pool = multiprocessing.Pool(None if jobs == 0 else jobs) manager = multiprocessing.Manager() queue = manager.Queue() num_jobs = 0 print("Dispatching jobs ...") if single_tracks: pool.apply_async( do_gain_async, [ queue, (single_tracks, None), [os.path.join(music_dir, path) for path in single_tracks], ref_level, force, dry_run, False, mp3_format]) num_jobs += 1 for album_id, album_files in albums.items(): pool.apply_async( do_gain_async, [ queue, (album_files, album_id), [os.path.join(music_dir, path) for path in album_files], ref_level, force, dry_run, True, mp3_format]) num_jobs += 1 pool.close() print("Now waiting for results ...") failed_jobs = [] try: all_jobs = num_jobs successful = 0 while num_jobs > 0: job_key, output, exc = queue.get() num_jobs -= 1 if exc: failed_jobs.append((job_key, output, exc)) else: successful += 1 print(output.strip()) print( "Successfully finished %s of %s." % (successful, all_jobs)) print("") # Update cache. if not dry_run: tracks, album_id = job_key update_cache(files, music_dir, tracks, album_id) finally: try: pool.terminate() except Exception: # terminate ends rather horribly so we just silence it. pass if len(failed_jobs) > 0: print("Unfortunately, there were some errors:") for key, output, exc in failed_jobs: print(output.strip()) print(exc, file=sys.stderr) print("") print("%s successful, %s failed." % (successful, len(failed_jobs))) def do_collectiongain(music_dir, ref_level=89, force=False, dry_run=False, mp3_format=None, ignore_cache=False, jobs=0): music_abspath = os.path.abspath(music_dir) musicpath_hash = md5(music_abspath.encode("utf-8")).hexdigest() cache_file = os.path.join(os.path.expanduser("~"), ".cache", "collectiongain-cache.%s" % musicpath_hash) # load the cache, if desired if not ignore_cache: files = read_cache(cache_file) else: files = {} print("Collecting files ...") # whenever this part is stopped (KeyboardInterrupt/other exception), the # cache is written to disk so all progress persists try: visited_cache = dict.fromkeys(iter(files.keys()), False) collect_files(music_dir, files, visited_cache, rgio.BaseFormatsMap(mp3_format).is_supported_format) # clean cache for filepath, visited in list(visited_cache.items()): if not visited: del visited_cache[filepath] del files[filepath] # hopefully gets rid of at least one huge data structure del visited_cache albums, single_tracks = transform_cache(files) # gain everything that has survived the cleansing do_gain_all( music_dir, albums, single_tracks, files, ref_level, force, dry_run, mp3_format, jobs) finally: write_cache(cache_file, files) print("All finished.") def collectiongain_options(): opts = common_options() opts.add_option("--ignore-cache", help="Do not use the file cache at all.", dest="ignore_cache", action="store_true") opts.add_option("--regain", help="Fully reprocess everything. Same as " "'--force --ignore-cache'.", dest="regain", action="store_true") opts.add_option("-j", "--jobs", help="Specifies the number of jobs to run " "simultaneously. Must be >= 1. By default, this is set to " "the number of CPU cores in the system to provide best " "performance.", dest="jobs", action="store", type="int") opts.set_defaults(ignore_cache=False, jobs=None) opts.set_usage("%prog [options] MUSIC_DIR") opts.set_description("Calculate Replay Gain for a large set of audio files " "without asking many questions. This program " "calculates an album ID for any audo file in " "MUSIC_DIR. Then, album gain will be applied to all " "files with the same album ID. The album ID is " "created from file tags as follows: If an 'album' tag " "is present, it is joined with the contents of an " "'albumartist' tag, or, if that isn't set, the " "contents of the 'artist' tag, or nothing if there is " "no 'artist' tag as well. On the other hand, if no " "'album' tag is present, the file is assumed to be a " "single track without album; in that case, no album " "gain will be calculated for that file.") return opts def collectiongain(): init_gstreamer() optparser = collectiongain_options() opts, args = optparser.parse_args() if len(args) != 1: optparser.error("pass one directory path") if opts.jobs is not None and opts.jobs < 1: optparser.error("jobs must be at least 1") if opts.regain: opts.force = opts.ignore_cache = True try: do_collectiongain(args[0], opts.ref_level, opts.force, opts.dry_run, opts.mp3_format, opts.ignore_cache, opts.jobs) except Error as exc: print("") print(str(exc), file=sys.stderr) sys.exit(1) except KeyboardInterrupt: print("Interrupted.") if __name__ == "__main__": collectiongain() ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/script/replaygain.py0000644000175000017500000001651500000000000022074 0ustar00christianchristian00000000000000# -*- coding: utf-8 -*- # # Copyright (c) 2009-2014 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import os.path import sys from gi.repository import GLib from rgain3 import rgcalc, rgio, util from rgain3.script import Error, common_options, init_gstreamer # calculate the gain for the given files def calculate_gain(files, ref_level): exc_slot = [None] # handlers def on_finished(evsrc, trackdata, albumdata): loop.quit() def on_trk_started(evsrc, filename): print(" %s:" % filename, end='', flush=True) def on_trk_finished(evsrc, filename, gaindata): if gaindata: print("%.2f dB" % (gaindata.gain,)) else: print("done") def on_error(evsrc, exc): exc_slot[0] = exc loop.quit() rg = rgcalc.ReplayGain(files, True, ref_level) with util.gobject_signals(rg, ("all-finished", on_finished), ("track-started", on_trk_started), ("track-finished", on_trk_finished), ("error", on_error),): loop = GLib.MainLoop() rg.start() loop.run() if exc_slot[0] is not None: raise exc_slot[0] return rg.track_data, rg.album_data # TODO: this looks like it can be fairly easily refactored into smaller pieces, # when there is decent coverage. def do_gain(files, ref_level=89, force=False, dry_run=False, album=True, # noqa mp3_format=None): formats_map = rgio.BaseFormatsMap(mp3_format) newfiles = [] for filename in files: if not formats_map.is_supported_format(os.path.splitext(filename)[1]): print("%s: not supported, ignoring it" % filename) else: newfiles.append(filename) files = newfiles if not force: print("Checking for Replay Gain information ...") newfiles = [] for filename in files: print(" %s:" % filename, end='') try: trackdata, albumdata = formats_map.read_gain(filename) except Exception as exc: raise Error("%s: %s" % (filename, exc)) else: if trackdata and albumdata: print("track and album") elif not trackdata and albumdata: print("album only") newfiles.append(filename) elif trackdata and not albumdata: print("track only") if album: newfiles.append(filename) else: print("none") newfiles.append(filename) if not album: files = newfiles elif not len(newfiles): files = newfiles if not files: # no files left print("Nothing to do.") return 0 # calculate gain print("Calculating Replay Gain information ...") try: tracks_data, albumdata = calculate_gain(files, ref_level) if album: print(" Album gain: %.2f dB" % (albumdata.gain,)) except Exception as exc: raise Error("Error while calculating gain - %s" % exc) if not album: albumdata = None # write gain if not dry_run: print("Writing Replay Gain information to files ...") for filename, trackdata in tracks_data.items(): print(" %s:" % filename, end='') try: formats_map.write_gain(filename, trackdata, albumdata) except Exception as exc: raise Error("%s: %s" % (filename, exc)) else: print("done") print("Done") # a simple Replay Gain dump def show_rgain_info(filenames, mp3_format=None): formats_map = rgio.BaseFormatsMap(mp3_format) for filename in filenames: print(filename) try: trackdata, albumdata = formats_map.read_gain(filename) except Exception as exc: print(" " % (exc,)) continue if not trackdata and not albumdata: print(" ") if trackdata and trackdata.ref_level: ref_level = trackdata.ref_level elif albumdata and albumdata.ref_level: ref_level = albumdata.ref_level else: ref_level = None if ref_level is not None: print(" Reference loudness %i dB" % ref_level) if trackdata: print(" Track gain %.2f dB" % trackdata.gain) print(" Track peak %.8f" % trackdata.peak) if albumdata: print(" Album gain %.2f dB" % albumdata.gain) print(" Album peak %.8f" % albumdata.peak) def rgain_options(): opts = common_options() opts.add_option("--no-album", help="Don't write any album gain " "information.", dest="album", action="store_false") opts.add_option("--show", help="Don't calculate anything, simply show " "Replay Gain information for the specified files. In this " "mode, all other options save for '--mp3-format' are " "ignored, for they would make no sense.", dest="show", action="store_true") opts.set_defaults(album=True, show=False) opts.set_usage("%prog [options] AUDIO_FILE [AUDIO_FILE ...]") opts.set_description("Apply or display Replay Gain information for audio " "files. This program is similar to the likes of " "'vorbisgain' or 'mp3gain': You pass in some files, " "they are analyzed and receive their share of Replay " "Gain. The difference is that '%prog' supports " "several file formats, namely Ogg Vorbis (anything " "you'd put into an Ogg container, actually), Flac, " "WavPack and MP3. Also, it allows you to view " "existing Replay Gain information in any of those " "file types.") return opts def replaygain(): init_gstreamer() optparser = rgain_options() opts, args = optparser.parse_args() if not args: optparser.error("pass one or several audio file names") if opts.show: show_rgain_info(args, opts.mp3_format) else: try: do_gain(args, opts.ref_level, opts.force, opts.dry_run, opts.album, opts.mp3_format) except Error as exc: print("") print(str(exc), file=sys.stderr) sys.exit(1) except KeyboardInterrupt: print("Interrupted.") if __name__ == "__main__": replaygain() ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070719.0 rgain3-1.1.1/rgain3/util.py0000644000175000017500000000512200000000000017402 0ustar00christianchristian00000000000000# Copyright (c) 2009-2015 Felix Krull # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import contextlib import logging import sys from typing import Optional, Union logger = logging.getLogger(__name__) def _ensure_str(value: Union[str, bytes]) -> str: if isinstance(value, str): return value elif isinstance(value, bytes): return value.decode() raise TypeError def _str_to_float(value: str) -> Optional[float]: try: return float(value) except ValueError: logger.info("Could not convert '%s' to float", value) return None def parse_db(value: Union[str, bytes]) -> Optional[float]: # The db value from mutagen _should_ by of type str, but there are cases # where we get bytes, see https://github.com/chaudum/rgain3/issues/38 value = _ensure_str(value.strip()) if value.lower().endswith("db"): value = value[:-2].strip() return _str_to_float(value) def parse_peak(value: str) -> Optional[float]: # The db value from mutagen _should_ by of type str, but there are cases # where we get bytes, see https://github.com/chaudum/rgain3/issues/38 value = _ensure_str(value.strip()) return _str_to_float(value) def almost_equal( a: Optional[float], b: Optional[float], epsilon: float ) -> bool: if a is None and b is None: return True elif a is None or b is None: return False return abs(a - b) <= epsilon def getfilesystemencoding(): # get file system encoding, making sure never to return None return sys.getfilesystemencoding() or sys.getdefaultencoding() @contextlib.contextmanager def gobject_signals(obj, *signals): """Context manager to connect and disconnect GObject signals using a ``with`` statement. """ signal_ids = [] try: for signal in signals: signal_ids.append(obj.connect(*signal)) yield finally: for signal_id in signal_ids: obj.disconnect(signal_id) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/rgain3/version.py0000644000175000017500000000032400000000000020111 0ustar00christianchristian00000000000000from pkg_resources import DistributionNotFound, get_distribution try: __version__ = get_distribution("rgain").version except DistributionNotFound: # rgain package is not installed __version__ = None ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/rgain3.egg-info/0000755000175000017500000000000000000000000017545 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071864.0 rgain3-1.1.1/rgain3.egg-info/PKG-INFO0000644000175000017500000000333200000000000020643 0ustar00christianchristian00000000000000Metadata-Version: 2.1 Name: rgain3 Version: 1.1.1 Summary: Multi-format Replay Gain utilities Home-page: https://github.com/chaudum/rgain Author: Felix Krull Author-email: f_krull@gmx.de Maintainer: Christian Haudum Maintainer-email: christian@christianhaudum.at License: GNU General Public License (v2 or later) Description: A set of Python modules and utility programmes to deal with Replay Gain information -- calculate it (with GStreamer), read and write it (with Mutagen). It has support for Ogg Vorbis (or probably anything stored in an Ogg container), Flac, WavPack, MP4 (aka AAC) and MP3 (in different incarnations). There‘s also a command-line programme, ``replaygain``, that works very similar to its like-named cousins, most prominently ``vorbisgain`` and ``mp3gain`` -- only that itworks for all those supported formats alike. ``collectiongain`` on the other hand is a kind of fire-and-forget tool for big amounts of music files. Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: End Users/Desktop Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.5 Provides-Extra: test ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071864.0 rgain3-1.1.1/rgain3.egg-info/SOURCES.txt0000644000175000017500000000223500000000000021433 0ustar00christianchristian00000000000000CHANGES.md COPYING MANIFEST.in README.md requirements.txt setup.cfg setup.py test-requirements.txt tests.sh tox.ini man/collectiongain.rst man/replaygain.rst rgain3/__init__.py rgain3/albumid.py rgain3/rgcalc.py rgain3/rgio.py rgain3/util.py rgain3/version.py rgain3.egg-info/PKG-INFO rgain3.egg-info/SOURCES.txt rgain3.egg-info/dependency_links.txt rgain3.egg-info/requires.txt rgain3.egg-info/top_level.txt rgain3/script/__init__.py rgain3/script/collectiongain.py rgain3/script/replaygain.py scripts/collectiongain scripts/replaygain test/test_albumid.py test/test_rgain_init.py test/test_rgcalc.py test/test_rgio.py test/test_util.py test/data/album-and-albumartist.mp3 test/data/album-and-mb-albumartist.mp3 test/data/album-artist.mp3 test/data/album-tag.flac test/data/album-tag.mp3 test/data/albumartist-TPE2.mp3 test/data/albumartist-TXXX_ALBUM_ARTIST.mp3 test/data/albumartist-TXXX_QL_albumartist.mp3 test/data/albumartist-TXXX_albumartist.mp3 test/data/albumartist.flac test/data/mb-album-id-and-more.flac test/data/mb-album-id-form1.mp3 test/data/mb-album-id-form2.mp3 test/data/mb-album-id.flac test/data/missing-headers.mp3 test/data/no-tags.flac test/data/no-tags.mp3././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071864.0 rgain3-1.1.1/rgain3.egg-info/dependency_links.txt0000644000175000017500000000000100000000000023613 0ustar00christianchristian00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071864.0 rgain3-1.1.1/rgain3.egg-info/requires.txt0000644000175000017500000000017700000000000022152 0ustar00christianchristian00000000000000PyGObject>=3.34.0 mutagen>=1.43.0 [test] tox<4.0,>=3.14 pytest<6.0,>=5.3 pytest-cov>=2.8 pytest-flake8>=1.0 pytest-isort>=0.3 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071864.0 rgain3-1.1.1/rgain3.egg-info/top_level.txt0000644000175000017500000000000700000000000022274 0ustar00christianchristian00000000000000rgain3 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/scripts/0000755000175000017500000000000000000000000016357 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/scripts/collectiongain0000755000175000017500000000020100000000000021270 0ustar00christianchristian00000000000000#!/usr/bin/env python3 from rgain3.script.collectiongain import collectiongain if __name__ == "__main__": collectiongain() ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/scripts/replaygain0000755000175000017500000000016500000000000020442 0ustar00christianchristian00000000000000#!/usr/bin/env python3 from rgain3.script.replaygain import replaygain if __name__ == "__main__": replaygain() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8643498 rgain3-1.1.1/setup.cfg0000644000175000017500000000067300000000000016517 0ustar00christianchristian00000000000000[bdist_wheel] universal = 1 [flake8] max-line-length = 80 [isort] combine_as_imports = true default_section = THIRDPARTY include_trailing_comma = true known_first_party = rgain3 line_length = 80 multi_line_output = 3 not_skip = __init__.py [tool:pytest] addopts = --showlocals --full-trace --flake8 --isort --cov rgain3 --cov-report term-missing flake8-max-line-length = 80 flake8-max-complexity = 20 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627071713.0 rgain3-1.1.1/setup.py0000755000175000017500000001404100000000000016405 0ustar00christianchristian00000000000000#!/usr/bin/env python3 import io import os import sys import tempfile from datetime import date from distutils.command.build import build from typing import List from pkg_resources.extern.packaging.version import Version # a version must be PEP 440 compliant __version__ = Version("1.1.1") def requirements(filename: str) -> List[str]: with io.open(filename, "r") as fp: return [line.strip() for line in fp if line.strip()] try: from setuptools import Command, Distribution, setup except ImportError: print("setuptools unavailable, falling back to distutils.", file=sys.stderr) from distutils.core import Command, Distribution, setup try: import docutils.core class ManpagesDistribution(Distribution): def __init__(self, attrs=None): self.rst_manpages = None self.rst_manpages_update_info = False self.rst_manpages_version = None self.rst_manpages_date = None Distribution.__init__(self, attrs) class build_manpages(Command): description = "Generate man pages." user_options = [ ("outputdir=", "b", "output directory for man pages"), ] def initialize_options(self): self.rst_manpages = None self.rst_manpages_update_info = False self.rst_manpages_version = "1.0" self.rst_manpages_date = date.today() self.outputdir = None def finalize_options(self): if not self.outputdir: self.outputdir = os.path.join("build", "man") self.rst_manpages = self.distribution.rst_manpages self.rst_manpages_update_info = \ self.distribution.rst_manpages_update_info self.rst_manpages_version = self.distribution.rst_manpages_version self.rst_manpages_date = self.distribution.rst_manpages_date def run(self): if not self.rst_manpages: return if not os.path.exists(self.outputdir): os.makedirs(self.outputdir, mode=0o755) for infile, outfile in self.rst_manpages: if self.rst_manpages_update_info: print("Updating %s info..." % infile, end="") with tempfile.NamedTemporaryFile("w", delete=False) as tmp: with open(infile, "r") as f: for line in f: if line.startswith(":Date:"): dt = self.rst_manpages_date tmp.write( ":Date: %s-%s-%s\n" % (dt.year, dt.month, dt.day)) elif line.startswith(":Version:"): tmp.write(":Version: %s\n" % self.rst_manpages_version) else: tmp.write(line) real_infile = tmp.name print("ok") else: real_infile = infile print("Converting %s to %s ..." % (infile, outfile), end="") docutils.core.publish_file( source_path=real_infile, destination_path=os.path.join(self.outputdir, outfile), writer_name="manpage") if real_infile != infile: os.remove(real_infile) print("ok") build.sub_commands.append(("build_manpages", None)) manpages_args = { "rst_manpages": [ ("man/replaygain.rst", "replaygain.1"), ("man/collectiongain.rst", "collectiongain.1"), ], "rst_manpages_update_info": True, "rst_manpages_version": __version__, "rst_manpages_date": date.today(), "cmdclass": {"build_manpages": build_manpages}, "distclass": ManpagesDistribution, } except ImportError: print("docutils not found, manpages won't be generated.", file=sys.stderr) manpages_args = {} setup( name="rgain3", version=str(__version__), description="Multi-format Replay Gain utilities", author="Felix Krull", author_email="f_krull@gmx.de", maintainer="Christian Haudum", maintainer_email="christian@christianhaudum.at", url="https://github.com/chaudum/rgain", license="GNU General Public License (v2 or later)", classifiers=[ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: End Users/Desktop", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Multimedia :: Sound/Audio :: Analysis", "Topic :: Software Development :: Libraries :: Python Modules", ], long_description="""\ A set of Python modules and utility programmes to deal with Replay Gain information -- calculate it (with GStreamer), read and write it (with Mutagen). It has support for Ogg Vorbis (or probably anything stored in an Ogg container), Flac, WavPack, MP4 (aka AAC) and MP3 (in different incarnations). There‘s also a command-line programme, ``replaygain``, that works very similar to its like-named cousins, most prominently ``vorbisgain`` and ``mp3gain`` -- only that itworks for all those supported formats alike. ``collectiongain`` on the other hand is a kind of fire-and-forget tool for big amounts of music files. """, packages=["rgain3", "rgain3.script"], scripts=["scripts/replaygain", "scripts/collectiongain"], install_requires=requirements("requirements.txt"), extras_require={ "test": ["tox>=3.14,<4.0"] + requirements("test-requirements.txt") }, python_requires=">=3.5", **manpages_args ) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/test/0000755000175000017500000000000000000000000015647 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1627071864.8603497 rgain3-1.1.1/test/data/0000755000175000017500000000000000000000000016560 5ustar00christianchristian00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/album-and-albumartist.mp30000644000175000017500000003372000000000000023373 0ustar00christianchristian00000000000000ID31TALBAlbum TitleTPE1ArtistTPE2Album ArtistdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAGArtistAlbum Title././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/album-and-mb-albumartist.mp30000644000175000017500000003370200000000000023767 0ustar00christianchristian00000000000000ID3#TALBAlbum TitleTXXX_MUSICBRAINZ_ALBUMARTISTIDMB Album Artist IDdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAGAlbum Title././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/album-artist.mp30000644000175000017500000003370200000000000021612 0ustar00christianchristian00000000000000ID3#TALBTest AlbumTPE1Test ArtistdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAGTest ArtistTest Album././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/album-tag.flac0000644000175000017500000006564700000000000021302 0ustar00christianchristian00000000000000fLaC" BD-oW < reference libFLAC 1.0.4 20141125ALBUM=Test Album@a9'I!$f&D'̦gIJ|9RJL3L>IIB)"%3338D !Jg(s̡C'% B D&e̦s9"'3)=Me2e  ɔ(s% ̙C9B!B$!IIC3&fg2H С32D Js9g?)HOI33 HPp p28g= H JJCBfsIC"L, (PLI9 ɔɔPC)  0JJ)@ФC)2(Re8tDI)2% gReСCINpP)JP)e&%D&RP B3<O!0e g&Pœəϔ̙I3(dJPaa,XD Hf)8S'%2S%2S3)Y%2D3)8s9̡I3)2ϟɔD2e 9ad̔L ɑ)I2P)R|!JM&DH s2?))C)Re HD,=PBPdL̦L"L.e$$ L )YN"s2y%&rS32S DP'C9a4)(i RP"JNN&$fsr\Re2RPdg(rg(D8DJ‡ 2Si2S39)  @"·DIIL') L")r33%3Rt“(g?):)2PNy)'&yI&PNRe JÙ)3BO9̡)(RyPɔ†%3 LP% Nfp …&e9C!O(iD&PIB!?33ß ɡ= 4(sr!C9C̑ r9 >333>S99R93 MC3'@L2JL Iy:aaȁɔɤJa3333")@P4h32iS2s%0t9)2?硆 pC<99&RS%hrB?ɡBRfd L IaB2̤$I9B&f9̦NR|Os`D9BJL>9 SD)%ds9™2gBpX2O2D\<)3C&Re L332e!ffps4 (gh9CL2rD e&XS39BRg3(Lad(s4)3IJ4 L92rP3e“%2egRe <ɔLΐ)ds%8RPePg3) 3L3 L p"!ɔI)re 2P"$C3 J 99g9C(Rs3̡̤dIB?)L)Nd d I)8Pd'IC94)2%2)’dD!Cr(fPJC LIIB$ΒS0B,)?,dJ%=2SPJJL(Xe32r))s32XrD8z9CPfs$I3%RP(faICINI&Lɦ )94Bs(PPzBPJ,>49dLI2P)I2)Xd(rs4)L02yLS Bs%RLL B!C9I@ %9(Re2RPfḑ%P3tM0(JS I3)RO?" A33yBI< rg33̤fppB~S$ JB!$( B1 4’̔8R~S38DhaL†faICg(hRP,I)’38D $(RdL<3") ri= 硜9(r O%2r2)&d:’' r!3D9?z"?NR JJ̔39(JzM3%0 hPɅ&S2Y4™ɔ(g$e$9C'pH!Lr9%2PBP)zdHPd29I2IB!̙™Rz))IPL))4(JPe pP9B49Cg?)ϡ?O8i?)y'(g3%2i""B$M% CК?aB C33%™2!ÅDBs%2D2S9 dCBy:d % 42RP32yCPB<I9ee2PС!PC%(D9(fP )29<),% Cg JaB2' ,)ffP 9)  KS2P̒yy'3PLP(|(s)™Bßfd HȒJOC99IIC3'(R8D8t9CɦJaC 0phS JCɔO8Pg%2rK0y48D92S34"8PrP,)O(Rf1$(iBzy&fdfyB2|"9J)(™(RP !(ga̔)% J2i)"C3339̔“† NNA NyL0J)2P`DfsB haIDD%9(XgB̦dB?)2efr3I%2P dNIa@$2B!(XD JLffs9$$49C™'RXP9 he2P333% L@sL @333(dHPœg2|$I3&X ,)LI9%gɜaLC<(hD% fO0II3&p JJ)C8RP9IJdJICM2Pd&Jə"2rs (P,”9(g !̔$Rr rg dNDICIJ$C%C0BdHD4(Ra2P:33i2!N!BRL%d9JL2$̞Re$3B)SPПA0afs%2t% JJp=% f9I<2y)&y6aNJ"(PaBe!@= (S0Bs%33332%B~PRe%32D%DRC

Re N?Ù) pfsBPBfhPhPФJ B'&PNRP.O<Y>t&D%9L BOLd%>4Ɉ9(sJ3)2hP(s% 'NP!… I(e&&PL0 B<2e&h(g9L̔0LȄ3%fs9Bs9>D JLȇa"L4)JfP&D0P a,4))L PrC% <&2r3@@a%9Ha̖P)(yNsL2 h 22R.̦ND&sS $R NN̦e'2S3%2&S9L(RP2RRNhp J̳,48D8P&PI0zhD S00dS M $Ry%2P̠XPI)>S%də%:C)'(Rpfs'CС)C3 IB KD2e'CrPB(fILœ8P3D,"B!IB&R|I),̤H0 3C'L ,œ8S0 ,"zIB$%39I)Nhr)C%2ФI%dP$Γ4&De)I(s3%2iɔ43!Be"&s9B!HS9BRe$‡ S$!$Pg0 $@D392!PSrS9C9BRg0D%$fO’hP@))9CHD$@,)C$@"(s%fd3)2œ!œg)Re&ffDS&(Rf,9B42S%2PIBdBdBe%2S%2S33">&I4…&f*"39a)C)2 RPL "rp L&Rd@g(s2pfp%)'"9C9!C,e!hg>y(XRRD%32P)D9i"%&!B… JfPs9))% %$C38S(JC@9LafJd B!2Д9LBs?C$I"NOgC8R d%2 s2D9 IȁD<%(K&IL̤'32eJd),(y4(Jr9‡$L2~s2S$C9D)2 L)pg%0NffM0 r|2PhRpSfPC2t3%&HM$Rs'(Nffr<̔D32PNdB3S' IHD93%'L)9C% JC)RfS'ϜO̞eRPfPIC333'Bt'&i"(P)()39.i>hg>I&S (JfrrJPRJ% RD3NBBs&S&J" D%0hPаrr&S3d(r)I s<fdI̡9= CILLCO)-q9C !L3%9IpRg9L @d@`J2 2S0JfPAaC99L)&r@ɅY(Re'C9d(S&Pp pIIL"d"dL,̤a.II(r?S LM L fRJpСP B Rg8S&R~XRP(s Nr=&):N>| BOP&r49C4))(RePBe geg8Sr%X JfdaJI9C'&hRf4e3 J)2hpJ} C&Pe0O&pC2y)RO PaI̖g3%!3%PC2redRRS39'3̤r)2fJJHIB0S%gIII%t(Ne%P$BP2Re&S2):RNe0y"C)% s(g pfe L3 $)%&&yJ2rRO$&PgBy)hr"̦g)2΅2P Re%XPЈ rg?)ȁfdBPJ332r p)"'&zM(gJPP(H@yCC99I(RȐS&gϜOIB!"8D4!<))‡L2S33$Bs29P @)2Pg(e$Bs&S J)3By4)(p @hfrxg?d )a$ rfrg!OsfPP̡(D3% fRg330JdIC392BdRDpCIB!“))(r)S$…2PСrg$JfrhRPСI%PB!:<(fR!a@(g:)ɔ9Ȅ%RPiIBJ ɔ)0JL LLS2z8t% x| h <ə)% BB)NfaB8Re39B%%%P󙓡"%3Сg4(g&prffOe$2e$,)" 9L%e9))dON % Ü$ RRr9BRg)I<I9BXP"JrPLaaBœ Ñ ϔ"L3hRs9"L"d29 RNr933&Rg(g )‡xd% fs(Ra&yC!2sg4(S%0%rRL(RgCS)Bt ̡!ž99BPPœIBdLD2S=)(fa)&R8Js9I99Ȅ"(gI!@0K3̑ BHD%9ffO JJILB')t2xs)!I23| Rs $ LC4'd&h„I%HNs9,)(S%3D&yNzaJe <,IC'$ 9BtП))8həB(d2pNPg J\32Ps aJILgd&rs2S3%%)0$&)(Rae LdIfr3ILdP"C<39C30C39PФRM3B )8g ''I(stɡByP2S& RP%8Y8Rt'L))Y垇>P?4aCɑ )IB<)"hh% I2e!™9&S2D2r}'C9 ̦Ba%&s2D Nd'(s3339L)3Lɤ"g)2=RRS' JJ)?d@H`I)9B!ɜ)2DD9 ̡ϡL9)4 !(Re0P d!Nr9aȄxg>S% (Rd@:I,"Iϔ'BC8| J92y NfffpaC)(Re3̅ dICJy4!3fJs3Be$™)BBM3(P rJ!BYN!& &s9Iy)<)HD9ɳ2S'IB Rs%(rPLCC,PNNhS'2D J i(Y33% "( BaJB!I40ɔC9Άe2yP 2HD932XD9Ù@)Be&&i%2y(pNLB'Ù2ÔyN~P)4)9̑ e2Pd(ffdLB9g32pNNg2D&D&D'Y$I%ffd LL…Yg(fd02S%39S%%3 J,)2(RfP/CBP(&RLIB)hP0(sL(rRL9IC339z%e$̙P)œΆJI3% C@r!Nf)!™)L)(Rs%%2S2Ps)2C3 JJ(s‡3&RJfffJa= Iœ?4 LJRJ93(p'0gs)%% rrLФdfyB LffpJdC&sCP J333̔)@ɜ dLɇ9“)(r% 2DxRpM3IA2PICC4(XP%S'0СLLI3"LdM'd҄ȄHr34,"8S39C“(g%fS%!)fe ̑ )H|I@faaNg(d"I4'C JJr\`A C3NPPФ&s3 &C8g3$@,(hSI9$L'BNfOIB8S3 Ls9̑ I9P̟42)s0: 9 Y%3&&PP%)9,2pJ%9) (rffg)2‡3@ Bd= 4)):J &&s2Lœ"'38S39@LL)2ffPJJ"(PФ"% Bɔ3&t% JOIC2hs(e!󔙙2&''BJafd2fS% C9L(adS&P΀kryPPr%&RJdffH‡ g drR &p(D&S33(4&sC’% IRPr0LP) 9'3%8SB'̤(he3 d̡…8r!2g PCBYBP$9Rf%3 @3 I(hhXS(p% ‡r rBPJHIfiBP$)3C33% Rr,)™IaN2g̡̦g(rrrfdRSSfaL0)rS3)I)339fJdg,(LC…!J>Rafe&D NRg)02ȇ C9BRP"dS&RfȆr0d(POee By% C9)2'%9gI)BPJ%P)'Y9ȆJr23")BRg>N%fs%PSC py"!9''C$@))'9,Xzs>e$!S$@ (fPI)(pRfCRL’%4 rOBdH~XD &ffJ!2S3333 paBC…%  afP(pdpL L)(P fd™>S&r2%&fRLIBœg(rL8S‡2&P)=PS fxYLOaeJ9BD ϟ<3(S3% ϙI„X|L92S%0硞e0Jd(|"%(,(D99IIp ̦JfJHI†J 0 g PIL)9)C8D% NP D9)S'%2S dIC3% )Nhr s:CS% % BJJrD9(d ɤD O(ffaL)(y(rdfdJIICaI3<3̑ ))% 䦀|:J"LY&PC)9?)RB3>S(ry(D8D)9):!BS=% dȁII@)3@0`IPzJH3L9C')CB!B΅8S<(s dgRe'dI"C!$I9dIL4s)&fD, 2d’@L40LIL9CɦJJffJfD&RY!’!9@IL)8P&g3&e LaL<9ICL73IC(Rg)Be ОIB| LRXr!!3$g?39s%2RrRar%2S%2S&)2 9dJJ(II3338S2e32&P99932SRDs dJp 33rBPdJJOdB(S33 Rs3)(RNP338SI )(s% IC2r=!ILg= yB@ œ8YCC 8D% fH)=% DP)(AaLC(RrP"LB!C9BhOC&RJd$g JJINLLIL̤"ddJB)RJI̤39dJ%?gC%9B(SRPIL3I"L"L2fpRaL)3z9fNLRP9ILɡ) B’(PhRs$Bri:Jxy)(sB dg= ɜ&P"S!|!B$^S NH?СCLP̔D,&h“(dRSi)PJJJa JO 2PJg(rfJfH!f9̔Ú) C9(S'(D&RPΒ994IB™"))IPB32S$Be)(r Je"9L38D(s̤&B&Ng Jae CC%%332@LIIIL)?)C dS39Nt(Rdə@ ?)3BPfL&e0NaI)),(rfaaȁaM a䔓9ILB94(J}92S)(Rs%2i(PP& )ffOCs0IrPI>rf|JHD,)L(rJa(PS p pe 9BPȆJ!3>g(J!NIL, C pC9@ 0O(y)")@9LLCIHP LPNB L(fdLg)) fp L3%C4L9)8Pha')=(d>RP4)(IfS3'92D2Rr2gIRO3(dd sL)% ϡS3BPPP”'2P"p"t3@ɡ)8939!D2i0NstfRe O=f  NRgC932PNJd))Bs%330J)3)sM 9(RfPP3()&$&|IILdfLЈp )9%02P))(SaL"L# 8rp0g0…L9@)XP4?)s9It9(d(&KIB(Pp2er@Άs INz)0 ffd)@P`P J)ar9IB3fd!',&DBs42 >L8S3Le"d̡(D3&P)$)hPaNL"9JLfJB,,24)$2ÙP)2Ϥ4(g)2PNP0a<3>g2Y&B 9fe ̙IBRfLrI2(P)",) N,2(S'0'))%$32P% LIȆJP8XD%J|)NH?Rx$a3I"(s3( @he3'C9)9B?@fd@()?ФfÅ 4 (g&e! Ls$(g(se&XXRD0hOȆJRP p sB&gȄ ϡCBP3)̳I9ddJdI(y(r(sCI 0adsJ&fsNP3ϔɔ’ X3)(!CI)”Ô'CS'OfaI2ffrRNPP,C% 'SNryIÄC'&3D hdrg(s LI)C3d2Jd"dRP9̔>g̡̤C)2C9ICIJICIB™9CI LBfIB!3OJdС')3)P9 !HP&r?I9JfL̚aIBpL39D B8D8S&bJNS&dNadP(Y3%,?30Ls)Raaf ))>Pg̡ RPNdB)(e&  T' N̔&RNddH Jp)š32垆P2s39S 2(pJP)))@™8D d,)Bs=fS3dIϙI'% JP?-qLФa?"dI9@28e2I$C%hJ(`t(fNd29@29Li= Cg9IBt'( B$IfJNe0œLI2s2~RPfJaIB9CRs3 dȄ$ᔒPɔ8R| 334 d,dϡ“2 s9PФr>0СB8fP<JfPM B XS%%zIePI)8Re0"% %332dJJ39$S')HP# % d(d @|L)(g% LRCg 2Ф!e4fJ,"2 C@,I@O PB(rft(Jhg=S%3% I3r)9(Iffe&XPO™94''(rIs?8D9̤̔&LJfM &D38PICɈ Na S2P IIg"(e L|I%L&L 4ϙ)&p2&e0 !B))PK0JJR"̤hC))|)&R&C$@)”9C3&Rr d"9"2XP9@$'3唔 )2(J| C 9C'HS&s3PdJa2S%PP%0 3) )g)332S%333(fs )2Y|Ʌ%0 "9@JLs9)!C9ɡI ILϞO B$(g2$$J2yСC)" >D JLrp)S%3%(g&fg2HJ9I0fJ:9Bg 2fLP32RP'ɤ(D̡CIФJ2PP9@ zM39CIp/ sBfLJdLa)$$M))))>IRr!(Re LNP3̡'0g0Jg2~S)% NaaC)Ne%JB)(g?)(2P4(e&RiB,"9RO%d"9LS!T(hLLP9)&fr: 8LP&R 2|)P2œ)3$B|,fPfyIaNz"8~S'):I3I4p"C%II>S'D4 C4='2%Pfg B…3I4aB!L̔932r>t0"B O %3 ̑ ̔NLaL)™ReLßȆNpd39I(pNaȁ̔39C<(X9NpdBJL"BHP,(@2RP,4)"" ) ɑ )Ls9)΁NyCIB9>Y)))(sCdS!D% (r=䤡2™)9P J' ,e JB!4%C2e 9" d(RPrfa)2Be釆RO%2irLɜ9Cɉ!y(r&zY% 9B&P B$8S3IC'L")32L9̡99IIIBI)(Rg40reg)02rffB!(S J9!"%PsPNLd s3)39B24 I|4<9B|fRJddMeLBPJp'&ffg%(ad fs")e!Chd!?)32)%$2JP)C&X(P hRe2XD9(pI“949C2~D8PNLpRiaC)9R ̡†g>p(f`y,"09LXPO)L9C)'IB’!(Re@" &r2fs̤4)28S3% Ns9$C' d s)2S4 hNP&)3g JHaL2!''2S3 &R S% dNkp JfB (JL™)2g30d)C8SLɔB99CBS%)i!@II%%%$C'3$B,B&fPyɤ4)2!S$BS$Be'It'C8D2SCL)C@t(g4ɥ J)")8S)0ze$:9B…& ~3C32S0J JCS' PȒHa  Jt')&PBBpO333 sI(p pde ?)(J99(RL43BJL,"C3% L%9™48D8|L"d RDL32e$BPg0e B)!2 B s&ddIsLIJ"IHNfJ9d 9I(ryL̔)9I@ t RINL9!…38S… ffg PJ(P pxrdae %&S Ld2e IIL(ffg S9IC)™2 sg)2)?ÙJPsCI!̜D(s)aL)(XS2L8S̑ .afhS'D%dIL$C$ 4™6af hPrfdC $:L̜)L3)RO%332S% IB))&b9):OfJBJHS%(s"@4 J̔ JC<2xg3)()r?(XC)'9,(D )Ά(O33332S0NJd NRNfdϡRP N !a)&P))>(e&S HIB))"%%0dA&'"'&RS39…M "%'L$IB2,f)CMg2!f̔9N4"38YI̡IL3(,P !8D2s LСI3,9"% a"ny C@e*YTԩ*jRE*YR*DKRҪ,JZ*iJZ-IU-JRVZYqjK,,R)TJKK*VTeJjR*Jh.-YeeEJ,Zԥ%,I-(R҉+**RT),-*i%UJiieeJʕ+Qk)-JYJ*UYT,J&RYiK-%Q,jI\e%,JZJIZRY*˒Y1rJVXETKQrJYY1Ye*URR*RʋTZ,ťRVRYRʥ,&.*XIJ(QKY*ZRZQ2ʕ%TJ-IKTҖYTQjJU%Z.YTYRRdʒUJRbqKR))YQ2ҩ*)IK,)H,%,))eK*eQJ*K,)Rʉ-*%,*T,JKJԥ%j+Y-d%ԖZT\Z\JRZUK$eb)RVJr,Yi)e*JRYRX䥤%K-,%JZdIJU*R%.&T-)J)EK*YeIJ-Qb-,TZUVITJZJRRJ,K)TJTUV)R)JR)R)JTJRT҉JRҤiJTLJTTLM--RLIIK-JQTIrjJJK*YJT)i-IR)jJZYqe*QRRjRʒZYRҲ%)jKRZ-)jQrTYR)Iie)VT-J&TT(%ITYIiV)I12XQjQjIjJZYR*TEIT8*RT)JT\LVZL,)rE+%&K-,TTYRԩiRҕ-**TT*).IZ-heJe)QKJde)JR%-)R).R\勔TL\ZJZRʔJU%ԪUJ)iZVYR-*RJU-)R-%)IM$RҪZTL奩JJ\*R,5YRR)iKJjJjRJU&*RTbk)dIe-IqeEKKR%,)QjJJU)RZZJY.YqUUV(d2ie)jJK*VZ*)JReKRKJT%+&*Z-J.)j-,J,ZYrR,iDRK-&&R+JTKERZʖTZV\Z*RVTJR\JJYK*&*RԕUKRRieRԔL)JZYie%iK-JRTK*-IjKTiUUeDʒUU$-eDʔqe)Rʥ%VIXbTť*IRʕU,(*vQ&-T)R)IhdKJZ&ZR%%)JR-%JTZb䔘JL&R-QjYieJ*-%R&T*ԖL+-)UZViVTғM(Rʋ,*,M)QiR&&RUU-E-$eBee&-,,)jR,Z,)RJbYRYJRU)%,E-,iV*ZXҪIJZT$-RZ-,)YQ2Q40EJ)-JRʔJ#),%-,Ek*UJ*IRZRԤ%&-,M*RJ*KKK+)TTe-E*R*JRK*JTTZʒYe*,UReJR)RҖ2U%iijQijKTX,JR-Qj)RV,-)LTRIKRUZRJRR**Q4e$KIk$IKIi)i*)K*RԕKYJT2)JYIj,)*QiK)RKRRJ&.JT,ijJ,UeK%*YjQrJT%JU,ŕ+*Y,VRZ*iJ),%ETUE)*Ԓ*ieRTTQ4d)TKVZRJZ*,ZZKRK+-J*T)IjRVRbԩDKQjʉKT%*JRKJ2Y2DҖK(y././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1618943458.0 rgain3-1.1.1/test/data/album-tag.mp30000644000175000017500000003370200000000000021057 0ustar00christianchristian00000000000000ID3#TALBTest AlbumdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAGTest Album././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/albumartist-TPE2.mp30000644000175000017500000003372000000000000022245 0ustar00christianchristian00000000000000ID31TPE25Test Album Artist - TPE2dXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/albumartist-TXXX_ALBUM_ARTIST.mp30000644000175000017500000003370200000000000024354 0ustar00christianchristian00000000000000ID3#TXXX4ALBUM ARTISTTest Album Artist - TXXX_ALBUM_ARTISTdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/albumartist-TXXX_QL_albumartist.mp30000644000175000017500000003370200000000000025351 0ustar00christianchristian00000000000000ID3#TXXX@QuodLibet::albumartistTest Album Artist - TXXX_QL_albumartistdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/albumartist-TXXX_albumartist.mp30000644000175000017500000003370200000000000024755 0ustar00christianchristian00000000000000ID3#TXXX2albumartistTest Album Artist - TXXX_albumartistdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/albumartist.flac0000644000175000017500000006566400000000000021757 0ustar00christianchristian00000000000000fLaC" BD-oW I reference libFLAC 1.0.4 20141125ALBUMARTIST=Test Album Artist@a9'I!$f&D'̦gIJ|9RJL3L>IIB)"%3338D !Jg(s̡C'% B D&e̦s9"'3)=Me2e  ɔ(s% ̙C9B!B$!IIC3&fg2H С32D Js9g?)HOI33 HPp p28g= H JJCBfsIC"L, (PLI9 ɔɔPC)  0JJ)@ФC)2(Re8tDI)2% gReСCINpP)JP)e&%D&RP B3<O!0e g&Pœəϔ̙I3(dJPaa,XD Hf)8S'%2S%2S3)Y%2D3)8s9̡I3)2ϟɔD2e 9ad̔L ɑ)I2P)R|!JM&DH s2?))C)Re HD,=PBPdL̦L"L.e$$ L )YN"s2y%&rS32S DP'C9a4)(i RP"JNN&$fsr\Re2RPdg(rg(D8DJ‡ 2Si2S39)  @"·DIIL') L")r33%3Rt“(g?):)2PNy)'&yI&PNRe JÙ)3BO9̡)(RyPɔ†%3 LP% Nfp …&e9C!O(iD&PIB!?33ß ɡ= 4(sr!C9C̑ r9 >333>S99R93 MC3'@L2JL Iy:aaȁɔɤJa3333")@P4h32iS2s%0t9)2?硆 pC<99&RS%hrB?ɡBRfd L IaB2̤$I9B&f9̦NR|Os`D9BJL>9 SD)%ds9™2gBpX2O2D\<)3C&Re L332e!ffps4 (gh9CL2rD e&XS39BRg3(Lad(s4)3IJ4 L92rP3e“%2egRe <ɔLΐ)ds%8RPePg3) 3L3 L p"!ɔI)re 2P"$C3 J 99g9C(Rs3̡̤dIB?)L)Nd d I)8Pd'IC94)2%2)’dD!Cr(fPJC LIIB$ΒS0B,)?,dJ%=2SPJJL(Xe32r))s32XrD8z9CPfs$I3%RP(faICINI&Lɦ )94Bs(PPzBPJ,>49dLI2P)I2)Xd(rs4)L02yLS Bs%RLL B!C9I@ %9(Re2RPfḑ%P3tM0(JS I3)RO?" A33yBI< rg33̤fppB~S$ JB!$( B1 4’̔8R~S38DhaL†faICg(hRP,I)’38D $(RdL<3") ri= 硜9(r O%2r2)&d:’' r!3D9?z"?NR JJ̔39(JzM3%0 hPɅ&S2Y4™ɔ(g$e$9C'pH!Lr9%2PBP)zdHPd29I2IB!̙™Rz))IPL))4(JPe pP9B49Cg?)ϡ?O8i?)y'(g3%2i""B$M% CК?aB C33%™2!ÅDBs%2D2S9 dCBy:d % 42RP32yCPB<I9ee2PС!PC%(D9(fP )29<),% Cg JaB2' ,)ffP 9)  KS2P̒yy'3PLP(|(s)™Bßfd HȒJOC99IIC3'(R8D8t9CɦJaC 0phS JCɔO8Pg%2rK0y48D92S34"8PrP,)O(Rf1$(iBzy&fdfyB2|"9J)(™(RP !(ga̔)% J2i)"C3339̔“† NNA NyL0J)2P`DfsB haIDD%9(XgB̦dB?)2efr3I%2P dNIa@$2B!(XD JLffs9$$49C™'RXP9 he2P333% L@sL @333(dHPœg2|$I3&X ,)LI9%gɜaLC<(hD% fO0II3&p JJ)C8RP9IJdJICM2Pd&Jə"2rs (P,”9(g !̔$Rr rg dNDICIJ$C%C0BdHD4(Ra2P:33i2!N!BRL%d9JL2$̞Re$3B)SPПA0afs%2t% JJp=% f9I<2y)&y6aNJ"(PaBe!@= (S0Bs%33332%B~PRe%32D%DRC

Re N?Ù) pfsBPBfhPhPФJ B'&PNRP.O<Y>t&D%9L BOLd%>4Ɉ9(sJ3)2hP(s% 'NP!… I(e&&PL0 B<2e&h(g9L̔0LȄ3%fs9Bs9>D JLȇa"L4)JfP&D0P a,4))L PrC% <&2r3@@a%9Ha̖P)(yNsL2 h 22R.̦ND&sS $R NN̦e'2S3%2&S9L(RP2RRNhp J̳,48D8P&PI0zhD S00dS M $Ry%2P̠XPI)>S%də%:C)'(Rpfs'CС)C3 IB KD2e'CrPB(fILœ8P3D,"B!IB&R|I),̤H0 3C'L ,œ8S0 ,"zIB$%39I)Nhr)C%2ФI%dP$Γ4&De)I(s3%2iɔ43!Be"&s9B!HS9BRe$‡ S$!$Pg0 $@D392!PSrS9C9BRg0D%$fO’hP@))9CHD$@,)C$@"(s%fd3)2œ!œg)Re&ffDS&(Rf,9B42S%2PIBdBdBe%2S%2S33">&I4…&f*"39a)C)2 RPL "rp L&Rd@g(s2pfp%)'"9C9!C,e!hg>y(XRRD%32P)D9i"%&!B… JfPs9))% %$C38S(JC@9LafJd B!2Д9LBs?C$I"NOgC8R d%2 s2D9 IȁD<%(K&IL̤'32eJd),(y4(Jr9‡$L2~s2S$C9D)2 L)pg%0NffM0 r|2PhRpSfPC2t3%&HM$Rs'(Nffr<̔D32PNdB3S' IHD93%'L)9C% JC)RfS'ϜO̞eRPfPIC333'Bt'&i"(P)()39.i>hg>I&S (JfrrJPRJ% RD3NBBs&S&J" D%0hPаrr&S3d(r)I s<fdI̡9= CILLCO)-q9C !L3%9IpRg9L @d@`J2 2S0JfPAaC99L)&r@ɅY(Re'C9d(S&Pp pIIL"d"dL,̤a.II(r?S LM L fRJpСP B Rg8S&R~XRP(s Nr=&):N>| BOP&r49C4))(RePBe geg8Sr%X JfdaJI9C'&hRf4e3 J)2hpJ} C&Pe0O&pC2y)RO PaI̖g3%!3%PC2redRRS39'3̤r)2fJJHIB0S%gIII%t(Ne%P$BP2Re&S2):RNe0y"C)% s(g pfe L3 $)%&&yJ2rRO$&PgBy)hr"̦g)2΅2P Re%XPЈ rg?)ȁfdBPJ332r p)"'&zM(gJPP(H@yCC99I(RȐS&gϜOIB!"8D4!<))‡L2S33$Bs29P @)2Pg(e$Bs&S J)3By4)(p @hfrxg?d )a$ rfrg!OsfPP̡(D3% fRg330JdIC392BdRDpCIB!“))(r)S$…2PСrg$JfrhRPСI%PB!:<(fR!a@(g:)ɔ9Ȅ%RPiIBJ ɔ)0JL LLS2z8t% x| h <ə)% BB)NfaB8Re39B%%%P󙓡"%3Сg4(g&prffOe$2e$,)" 9L%e9))dON % Ü$ RRr9BRg)I<I9BXP"JrPLaaBœ Ñ ϔ"L3hRs9"L"d29 RNr933&Rg(g )‡xd% fs(Ra&yC!2sg4(S%0%rRL(RgCS)Bt ̡!ž99BPPœIBdLD2S=)(fa)&R8Js9I99Ȅ"(gI!@0K3̑ BHD%9ffO JJILB')t2xs)!I23| Rs $ LC4'd&h„I%HNs9,)(S%3D&yNzaJe <,IC'$ 9BtП))8həB(d2pNPg J\32Ps aJILgd&rs2S3%%)0$&)(Rae LdIfr3ILdP"C<39C30C39PФRM3B )8g ''I(stɡByP2S& RP%8Y8Rt'L))Y垇>P?4aCɑ )IB<)"hh% I2e!™9&S2D2r}'C9 ̦Ba%&s2D Nd'(s3339L)3Lɤ"g)2=RRS' JJ)?d@H`I)9B!ɜ)2DD9 ̡ϡL9)4 !(Re0P d!Nr9aȄxg>S% (Rd@:I,"Iϔ'BC8| J92y NfffpaC)(Re3̅ dICJy4!3fJs3Be$™)BBM3(P rJ!BYN!& &s9Iy)<)HD9ɳ2S'IB Rs%(rPLCC,PNNhS'2D J i(Y33% "( BaJB!I40ɔC9Άe2yP 2HD932XD9Ù@)Be&&i%2y(pNLB'Ù2ÔyN~P)4)9̑ e2Pd(ffdLB9g32pNNg2D&D&D'Y$I%ffd LL…Yg(fd02S%39S%%3 J,)2(RfP/CBP(&RLIB)hP0(sL(rRL9IC339z%e$̙P)œΆJI3% C@r!Nf)!™)L)(Rs%%2S2Ps)2C3 JJ(s‡3&RJfffJa= Iœ?4 LJRJ93(p'0gs)%% rrLФdfyB LffpJdC&sCP J333̔)@ɜ dLɇ9“)(r% 2DxRpM3IA2PICC4(XP%S'0СLLI3"LdM'd҄ȄHr34,"8S39C“(g%fS%!)fe ̑ )H|I@faaNg(d"I4'C JJr\`A C3NPPФ&s3 &C8g3$@,(hSI9$L'BNfOIB8S3 Ls9̑ I9P̟42)s0: 9 Y%3&&PP%)9,2pJ%9) (rffg)2‡3@ Bd= 4)):J &&s2Lœ"'38S39@LL)2ffPJJ"(PФ"% Bɔ3&t% JOIC2hs(e!󔙙2&''BJafd2fS% C9L(adS&P΀kryPPr%&RJdffH‡ g drR &p(D&S33(4&sC’% IRPr0LP) 9'3%8SB'̤(he3 d̡…8r!2g PCBYBP$9Rf%3 @3 I(hhXS(p% ‡r rBPJHIfiBP$)3C33% Rr,)™IaN2g̡̦g(rrrfdRSSfaL0)rS3)I)339fJdg,(LC…!J>Rafe&D NRg)02ȇ C9BRP"dS&RfȆr0d(POee By% C9)2'%9gI)BPJ%P)'Y9ȆJr23")BRg>N%fs%PSC py"!9''C$@))'9,Xzs>e$!S$@ (fPI)(pRfCRL’%4 rOBdH~XD &ffJ!2S3333 paBC…%  afP(pdpL L)(P fd™>S&r2%&fRLIBœg(rL8S‡2&P)=PS fxYLOaeJ9BD ϟ<3(S3% ϙI„X|L92S%0硞e0Jd(|"%(,(D99IIp ̦JfJHI†J 0 g PIL)9)C8D% NP D9)S'%2S dIC3% )Nhr s:CS% % BJJrD9(d ɤD O(ffaL)(y(rdfdJIICaI3<3̑ ))% 䦀|:J"LY&PC)9?)RB3>S(ry(D8D)9):!BS=% dȁII@)3@0`IPzJH3L9C')CB!B΅8S<(s dgRe'dI"C!$I9dIL4s)&fD, 2d’@L40LIL9CɦJJffJfD&RY!’!9@IL)8P&g3&e LaL<9ICL73IC(Rg)Be ОIB| LRXr!!3$g?39s%2RrRar%2S%2S&)2 9dJJ(II3338S2e32&P99932SRDs dJp 33rBPdJJOdB(S33 Rs3)(RNP338SI )(s% IC2r=!ILg= yB@ œ8YCC 8D% fH)=% DP)(AaLC(RrP"LB!C9BhOC&RJd$g JJINLLIL̤"ddJB)RJI̤39dJ%?gC%9B(SRPIL3I"L"L2fpRaL)3z9fNLRP9ILɡ) B’(PhRs$Bri:Jxy)(sB dg= ɜ&P"S!|!B$^S NH?СCLP̔D,&h“(dRSi)PJJJa JO 2PJg(rfJfH!f9̔Ú) C9(S'(D&RPΒ994IB™"))IPB32S$Be)(r Je"9L38D(s̤&B&Ng Jae CC%%332@LIIIL)?)C dS39Nt(Rdə@ ?)3BPfL&e0NaI)),(rfaaȁaM a䔓9ILB94(J}92S)(Rs%2i(PP& )ffOCs0IrPI>rf|JHD,)L(rJa(PS p pe 9BPȆJ!3>g(J!NIL, C pC9@ 0O(y)")@9LLCIHP LPNB L(fdLg)) fp L3%C4L9)8Pha')=(d>RP4)(IfS3'92D2Rr2gIRO3(dd sL)% ϡS3BPPP”'2P"p"t3@ɡ)8939!D2i0NstfRe O=f  NRgC932PNJd))Bs%330J)3)sM 9(RfPP3()&$&|IILdfLЈp )9%02P))(SaL"L# 8rp0g0…L9@)XP4?)s9It9(d(&KIB(Pp2er@Άs INz)0 ffd)@P`P J)ar9IB3fd!',&DBs42 >L8S3Le"d̡(D3&P)$)hPaNL"9JLfJB,,24)$2ÙP)2Ϥ4(g)2PNP0a<3>g2Y&B 9fe ̙IBRfLrI2(P)",) N,2(S'0'))%$32P% LIȆJP8XD%J|)NH?Rx$a3I"(s3( @he3'C9)9B?@fd@()?ФfÅ 4 (g&e! Ls$(g(se&XXRD0hOȆJRP p sB&gȄ ϡCBP3)̳I9ddJdI(y(r(sCI 0adsJ&fsNP3ϔɔ’ X3)(!CI)”Ô'CS'OfaI2ffrRNPP,C% 'SNryIÄC'&3D hdrg(s LI)C3d2Jd"dRP9̔>g̡̤C)2C9ICIJICIB™9CI LBfIB!3OJdС')3)P9 !HP&r?I9JfL̚aIBpL39D B8D8S&bJNS&dNadP(Y3%,?30Ls)Raaf ))>Pg̡ RPNdB)(e&  T' N̔&RNddH Jp)š32垆P2s39S 2(pJP)))@™8D d,)Bs=fS3dIϙI'% JP?-qLФa?"dI9@28e2I$C%hJ(`t(fNd29@29Li= Cg9IBt'( B$IfJNe0œLI2s2~RPfJaIB9CRs3 dȄ$ᔒPɔ8R| 334 d,dϡ“2 s9PФr>0СB8fP<JfPM B XS%%zIePI)8Re0"% %332dJJ39$S')HP# % d(d @|L)(g% LRCg 2Ф!e4fJ,"2 C@,I@O PB(rft(Jhg=S%3% I3r)9(Iffe&XPO™94''(rIs?8D9̤̔&LJfM &D38PICɈ Na S2P IIg"(e L|I%L&L 4ϙ)&p2&e0 !B))PK0JJR"̤hC))|)&R&C$@)”9C3&Rr d"9"2XP9@$'3唔 )2(J| C 9C'HS&s3PdJa2S%PP%0 3) )g)332S%333(fs )2Y|Ʌ%0 "9@JLs9)!C9ɡI ILϞO B$(g2$$J2yСC)" >D JLrp)S%3%(g&fg2HJ9I0fJ:9Bg 2fLP32RP'ɤ(D̡CIФJ2PP9@ zM39CIp/ sBfLJdLa)$$M))))>IRr!(Re LNP3̡'0g0Jg2~S)% NaaC)Ne%JB)(g?)(2P4(e&RiB,"9RO%d"9LS!T(hLLP9)&fr: 8LP&R 2|)P2œ)3$B|,fPfyIaNz"8~S'):I3I4p"C%II>S'D4 C4='2%Pfg B…3I4aB!L̔932r>t0"B O %3 ̑ ̔NLaL)™ReLßȆNpd39I(pNaȁ̔39C<(X9NpdBJL"BHP,(@2RP,4)"" ) ɑ )Ls9)΁NyCIB9>Y)))(sCdS!D% (r=䤡2™)9P J' ,e JB!4%C2e 9" d(RPrfa)2Be釆RO%2irLɜ9Cɉ!y(r&zY% 9B&P B$8S3IC'L")32L9̡99IIIBI)(Rg40reg)02rffB!(S J9!"%PsPNLd s3)39B24 I|4<9B|fRJddMeLBPJp'&ffg%(ad fs")e!Chd!?)32)%$2JP)C&X(P hRe2XD9(pI“949C2~D8PNLpRiaC)9R ̡†g>p(f`y,"09LXPO)L9C)'IB’!(Re@" &r2fs̤4)28S3% Ns9$C' d s)2S4 hNP&)3g JHaL2!''2S3 &R S% dNkp JfB (JL™)2g30d)C8SLɔB99CBS%)i!@II%%%$C'3$B,B&fPyɤ4)2!S$BS$Be'It'C8D2SCL)C@t(g4ɥ J)")8S)0ze$:9B…& ~3C32S0J JCS' PȒHa  Jt')&PBBpO333 sI(p pde ?)(J99(RL43BJL,"C3% L%9™48D8|L"d RDL32e$BPg0e B)!2 B s&ddIsLIJ"IHNfJ9d 9I(ryL̔)9I@ t RINL9!…38S… ffg PJ(P pxrdae %&S Ld2e IIL(ffg S9IC)™2 sg)2)?ÙJPsCI!̜D(s)aL)(XS2L8S̑ .afhS'D%dIL$C$ 4™6af hPrfdC $:L̜)L3)RO%332S% IB))&b9):OfJBJHS%(s"@4 J̔ JC<2xg3)()r?(XC)'9,(D )Ά(O33332S0NJd NRNfdϡRP N !a)&P))>(e&S HIB))"%%0dA&'"'&RS39…M "%'L$IB2,f)CMg2!f̔9N4"38YI̡IL3(,P !8D2s LСI3,9"% a"ny C@e*YTԩ*jRE*YR*DKRҪ,JZ*iJZ-IU-JRVZYqjK,,R)TJKK*VTeJjR*Jh.-YeeEJ,Zԥ%,I-(R҉+**RT),-*i%UJiieeJʕ+Qk)-JYJ*UYT,J&RYiK-%Q,jI\e%,JZJIZRY*˒Y1rJVXETKQrJYY1Ye*URR*RʋTZ,ťRVRYRʥ,&.*XIJ(QKY*ZRZQ2ʕ%TJ-IKTҖYTQjJU%Z.YTYRRdʒUJRbqKR))YQ2ҩ*)IK,)H,%,))eK*eQJ*K,)Rʉ-*%,*T,JKJԥ%j+Y-d%ԖZT\Z\JRZUK$eb)RVJr,Yi)e*JRYRX䥤%K-,%JZdIJU*R%.&T-)J)EK*YeIJ-Qb-,TZUVITJZJRRJ,K)TJTUV)R)JR)R)JTJRT҉JRҤiJTLJTTLM--RLIIK-JQTIrjJJK*YJT)i-IR)jJZYqe*QRRjRʒZYRҲ%)jKRZ-)jQrTYR)Iie)VT-J&TT(%ITYIiV)I12XQjQjIjJZYR*TEIT8*RT)JT\LVZL,)rE+%&K-,TTYRԩiRҕ-**TT*).IZ-heJe)QKJde)JR%-)R).R\勔TL\ZJZRʔJU%ԪUJ)iZVYR-*RJU-)R-%)IM$RҪZTL奩JJ\*R,5YRR)iKJjJjRJU&*RTbk)dIe-IqeEKKR%,)QjJJU)RZZJY.YqUUV(d2ie)jJK*VZ*)JReKRKJT%+&*Z-J.)j-,J,ZYrR,iDRK-&&R+JTKERZʖTZV\Z*RVTJR\JJYK*&*RԕUKRRieRԔL)JZYie%iK-JRTK*-IjKTiUUeDʒUU$-eDʔqe)Rʥ%VIXbTť*IRʕU,(*vQ&-T)R)IhdKJZ&ZR%%)JR-%JTZb䔘JL&R-QjYieJ*-%R&T*ԖL+-)UZViVTғM(Rʋ,*,M)QiR&&RUU-E-$eBee&-,,)jR,Z,)RJbYRYJRU)%,E-,iV*ZXҪIJZT$-RZ-,)YQ2Q40EJ)-JRʔJ#),%-,Ek*UJ*IRZRԤ%&-,M*RJ*KKK+)TTe-E*R*JRK*JTTZʒYe*,UReJR)RҖ2U%iijQijKTX,JR-Qj)RV,-)LTRIKRUZRJRR**Q4e$KIk$IKIi)i*)K*RԕKYJT2)JYIj,)*QiK)RKRRJ&.JT,ijJ,UeK%*YjQrJT%JU,ŕ+*Y,VRZ*iJ),%ETUE)*Ԓ*ieRTTQ4d)TKVZRJZ*,ZZKRK+-J*T)IjRVRbԩDKQjʉKT%*JRKJ2Y2DҖK(y././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/mb-album-id-and-more.flac0000644000175000017500000006566600000000000023220 0ustar00christianchristian00000000000000fLaC" BD-oW  reference libFLAC 1.0.4 20141125ALBUM=Album TitleALBUMARTIST=Album Artist ARTIST=ArtistMUSICBRAINZ_ALBUMID=MB Album ID@a9'I!$f&D'̦gIJ|9RJL3L>IIB)"%3338D !Jg(s̡C'% B D&e̦s9"'3)=Me2e  ɔ(s% ̙C9B!B$!IIC3&fg2H С32D Js9g?)HOI33 HPp p28g= H JJCBfsIC"L, (PLI9 ɔɔPC)  0JJ)@ФC)2(Re8tDI)2% gReСCINpP)JP)e&%D&RP B3<O!0e g&Pœəϔ̙I3(dJPaa,XD Hf)8S'%2S%2S3)Y%2D3)8s9̡I3)2ϟɔD2e 9ad̔L ɑ)I2P)R|!JM&DH s2?))C)Re HD,=PBPdL̦L"L.e$$ L )YN"s2y%&rS32S DP'C9a4)(i RP"JNN&$fsr\Re2RPdg(rg(D8DJ‡ 2Si2S39)  @"·DIIL') L")r33%3Rt“(g?):)2PNy)'&yI&PNRe JÙ)3BO9̡)(RyPɔ†%3 LP% Nfp …&e9C!O(iD&PIB!?33ß ɡ= 4(sr!C9C̑ r9 >333>S99R93 MC3'@L2JL Iy:aaȁɔɤJa3333")@P4h32iS2s%0t9)2?硆 pC<99&RS%hrB?ɡBRfd L IaB2̤$I9B&f9̦NR|Os`D9BJL>9 SD)%ds9™2gBpX2O2D\<)3C&Re L332e!ffps4 (gh9CL2rD e&XS39BRg3(Lad(s4)3IJ4 L92rP3e“%2egRe <ɔLΐ)ds%8RPePg3) 3L3 L p"!ɔI)re 2P"$C3 J 99g9C(Rs3̡̤dIB?)L)Nd d I)8Pd'IC94)2%2)’dD!Cr(fPJC LIIB$ΒS0B,)?,dJ%=2SPJJL(Xe32r))s32XrD8z9CPfs$I3%RP(faICINI&Lɦ )94Bs(PPzBPJ,>49dLI2P)I2)Xd(rs4)L02yLS Bs%RLL B!C9I@ %9(Re2RPfḑ%P3tM0(JS I3)RO?" A33yBI< rg33̤fppB~S$ JB!$( B1 4’̔8R~S38DhaL†faICg(hRP,I)’38D $(RdL<3") ri= 硜9(r O%2r2)&d:’' r!3D9?z"?NR JJ̔39(JzM3%0 hPɅ&S2Y4™ɔ(g$e$9C'pH!Lr9%2PBP)zdHPd29I2IB!̙™Rz))IPL))4(JPe pP9B49Cg?)ϡ?O8i?)y'(g3%2i""B$M% CК?aB C33%™2!ÅDBs%2D2S9 dCBy:d % 42RP32yCPB<I9ee2PС!PC%(D9(fP )29<),% Cg JaB2' ,)ffP 9)  KS2P̒yy'3PLP(|(s)™Bßfd HȒJOC99IIC3'(R8D8t9CɦJaC 0phS JCɔO8Pg%2rK0y48D92S34"8PrP,)O(Rf1$(iBzy&fdfyB2|"9J)(™(RP !(ga̔)% J2i)"C3339̔“† NNA NyL0J)2P`DfsB haIDD%9(XgB̦dB?)2efr3I%2P dNIa@$2B!(XD JLffs9$$49C™'RXP9 he2P333% L@sL @333(dHPœg2|$I3&X ,)LI9%gɜaLC<(hD% fO0II3&p JJ)C8RP9IJdJICM2Pd&Jə"2rs (P,”9(g !̔$Rr rg dNDICIJ$C%C0BdHD4(Ra2P:33i2!N!BRL%d9JL2$̞Re$3B)SPПA0afs%2t% JJp=% f9I<2y)&y6aNJ"(PaBe!@= (S0Bs%33332%B~PRe%32D%DRC

Re N?Ù) pfsBPBfhPhPФJ B'&PNRP.O<Y>t&D%9L BOLd%>4Ɉ9(sJ3)2hP(s% 'NP!… I(e&&PL0 B<2e&h(g9L̔0LȄ3%fs9Bs9>D JLȇa"L4)JfP&D0P a,4))L PrC% <&2r3@@a%9Ha̖P)(yNsL2 h 22R.̦ND&sS $R NN̦e'2S3%2&S9L(RP2RRNhp J̳,48D8P&PI0zhD S00dS M $Ry%2P̠XPI)>S%də%:C)'(Rpfs'CС)C3 IB KD2e'CrPB(fILœ8P3D,"B!IB&R|I),̤H0 3C'L ,œ8S0 ,"zIB$%39I)Nhr)C%2ФI%dP$Γ4&De)I(s3%2iɔ43!Be"&s9B!HS9BRe$‡ S$!$Pg0 $@D392!PSrS9C9BRg0D%$fO’hP@))9CHD$@,)C$@"(s%fd3)2œ!œg)Re&ffDS&(Rf,9B42S%2PIBdBdBe%2S%2S33">&I4…&f*"39a)C)2 RPL "rp L&Rd@g(s2pfp%)'"9C9!C,e!hg>y(XRRD%32P)D9i"%&!B… JfPs9))% %$C38S(JC@9LafJd B!2Д9LBs?C$I"NOgC8R d%2 s2D9 IȁD<%(K&IL̤'32eJd),(y4(Jr9‡$L2~s2S$C9D)2 L)pg%0NffM0 r|2PhRpSfPC2t3%&HM$Rs'(Nffr<̔D32PNdB3S' IHD93%'L)9C% JC)RfS'ϜO̞eRPfPIC333'Bt'&i"(P)()39.i>hg>I&S (JfrrJPRJ% RD3NBBs&S&J" D%0hPаrr&S3d(r)I s<fdI̡9= CILLCO)-q9C !L3%9IpRg9L @d@`J2 2S0JfPAaC99L)&r@ɅY(Re'C9d(S&Pp pIIL"d"dL,̤a.II(r?S LM L fRJpСP B Rg8S&R~XRP(s Nr=&):N>| BOP&r49C4))(RePBe geg8Sr%X JfdaJI9C'&hRf4e3 J)2hpJ} C&Pe0O&pC2y)RO PaI̖g3%!3%PC2redRRS39'3̤r)2fJJHIB0S%gIII%t(Ne%P$BP2Re&S2):RNe0y"C)% s(g pfe L3 $)%&&yJ2rRO$&PgBy)hr"̦g)2΅2P Re%XPЈ rg?)ȁfdBPJ332r p)"'&zM(gJPP(H@yCC99I(RȐS&gϜOIB!"8D4!<))‡L2S33$Bs29P @)2Pg(e$Bs&S J)3By4)(p @hfrxg?d )a$ rfrg!OsfPP̡(D3% fRg330JdIC392BdRDpCIB!“))(r)S$…2PСrg$JfrhRPСI%PB!:<(fR!a@(g:)ɔ9Ȅ%RPiIBJ ɔ)0JL LLS2z8t% x| h <ə)% BB)NfaB8Re39B%%%P󙓡"%3Сg4(g&prffOe$2e$,)" 9L%e9))dON % Ü$ RRr9BRg)I<I9BXP"JrPLaaBœ Ñ ϔ"L3hRs9"L"d29 RNr933&Rg(g )‡xd% fs(Ra&yC!2sg4(S%0%rRL(RgCS)Bt ̡!ž99BPPœIBdLD2S=)(fa)&R8Js9I99Ȅ"(gI!@0K3̑ BHD%9ffO JJILB')t2xs)!I23| Rs $ LC4'd&h„I%HNs9,)(S%3D&yNzaJe <,IC'$ 9BtП))8həB(d2pNPg J\32Ps aJILgd&rs2S3%%)0$&)(Rae LdIfr3ILdP"C<39C30C39PФRM3B )8g ''I(stɡByP2S& RP%8Y8Rt'L))Y垇>P?4aCɑ )IB<)"hh% I2e!™9&S2D2r}'C9 ̦Ba%&s2D Nd'(s3339L)3Lɤ"g)2=RRS' JJ)?d@H`I)9B!ɜ)2DD9 ̡ϡL9)4 !(Re0P d!Nr9aȄxg>S% (Rd@:I,"Iϔ'BC8| J92y NfffpaC)(Re3̅ dICJy4!3fJs3Be$™)BBM3(P rJ!BYN!& &s9Iy)<)HD9ɳ2S'IB Rs%(rPLCC,PNNhS'2D J i(Y33% "( BaJB!I40ɔC9Άe2yP 2HD932XD9Ù@)Be&&i%2y(pNLB'Ù2ÔyN~P)4)9̑ e2Pd(ffdLB9g32pNNg2D&D&D'Y$I%ffd LL…Yg(fd02S%39S%%3 J,)2(RfP/CBP(&RLIB)hP0(sL(rRL9IC339z%e$̙P)œΆJI3% C@r!Nf)!™)L)(Rs%%2S2Ps)2C3 JJ(s‡3&RJfffJa= Iœ?4 LJRJ93(p'0gs)%% rrLФdfyB LffpJdC&sCP J333̔)@ɜ dLɇ9“)(r% 2DxRpM3IA2PICC4(XP%S'0СLLI3"LdM'd҄ȄHr34,"8S39C“(g%fS%!)fe ̑ )H|I@faaNg(d"I4'C JJr\`A C3NPPФ&s3 &C8g3$@,(hSI9$L'BNfOIB8S3 Ls9̑ I9P̟42)s0: 9 Y%3&&PP%)9,2pJ%9) (rffg)2‡3@ Bd= 4)):J &&s2Lœ"'38S39@LL)2ffPJJ"(PФ"% Bɔ3&t% JOIC2hs(e!󔙙2&''BJafd2fS% C9L(adS&P΀kryPPr%&RJdffH‡ g drR &p(D&S33(4&sC’% IRPr0LP) 9'3%8SB'̤(he3 d̡…8r!2g PCBYBP$9Rf%3 @3 I(hhXS(p% ‡r rBPJHIfiBP$)3C33% Rr,)™IaN2g̡̦g(rrrfdRSSfaL0)rS3)I)339fJdg,(LC…!J>Rafe&D NRg)02ȇ C9BRP"dS&RfȆr0d(POee By% C9)2'%9gI)BPJ%P)'Y9ȆJr23")BRg>N%fs%PSC py"!9''C$@))'9,Xzs>e$!S$@ (fPI)(pRfCRL’%4 rOBdH~XD &ffJ!2S3333 paBC…%  afP(pdpL L)(P fd™>S&r2%&fRLIBœg(rL8S‡2&P)=PS fxYLOaeJ9BD ϟ<3(S3% ϙI„X|L92S%0硞e0Jd(|"%(,(D99IIp ̦JfJHI†J 0 g PIL)9)C8D% NP D9)S'%2S dIC3% )Nhr s:CS% % BJJrD9(d ɤD O(ffaL)(y(rdfdJIICaI3<3̑ ))% 䦀|:J"LY&PC)9?)RB3>S(ry(D8D)9):!BS=% dȁII@)3@0`IPzJH3L9C')CB!B΅8S<(s dgRe'dI"C!$I9dIL4s)&fD, 2d’@L40LIL9CɦJJffJfD&RY!’!9@IL)8P&g3&e LaL<9ICL73IC(Rg)Be ОIB| LRXr!!3$g?39s%2RrRar%2S%2S&)2 9dJJ(II3338S2e32&P99932SRDs dJp 33rBPdJJOdB(S33 Rs3)(RNP338SI )(s% IC2r=!ILg= yB@ œ8YCC 8D% fH)=% DP)(AaLC(RrP"LB!C9BhOC&RJd$g JJINLLIL̤"ddJB)RJI̤39dJ%?gC%9B(SRPIL3I"L"L2fpRaL)3z9fNLRP9ILɡ) B’(PhRs$Bri:Jxy)(sB dg= ɜ&P"S!|!B$^S NH?СCLP̔D,&h“(dRSi)PJJJa JO 2PJg(rfJfH!f9̔Ú) C9(S'(D&RPΒ994IB™"))IPB32S$Be)(r Je"9L38D(s̤&B&Ng Jae CC%%332@LIIIL)?)C dS39Nt(Rdə@ ?)3BPfL&e0NaI)),(rfaaȁaM a䔓9ILB94(J}92S)(Rs%2i(PP& )ffOCs0IrPI>rf|JHD,)L(rJa(PS p pe 9BPȆJ!3>g(J!NIL, C pC9@ 0O(y)")@9LLCIHP LPNB L(fdLg)) fp L3%C4L9)8Pha')=(d>RP4)(IfS3'92D2Rr2gIRO3(dd sL)% ϡS3BPPP”'2P"p"t3@ɡ)8939!D2i0NstfRe O=f  NRgC932PNJd))Bs%330J)3)sM 9(RfPP3()&$&|IILdfLЈp )9%02P))(SaL"L# 8rp0g0…L9@)XP4?)s9It9(d(&KIB(Pp2er@Άs INz)0 ffd)@P`P J)ar9IB3fd!',&DBs42 >L8S3Le"d̡(D3&P)$)hPaNL"9JLfJB,,24)$2ÙP)2Ϥ4(g)2PNP0a<3>g2Y&B 9fe ̙IBRfLrI2(P)",) N,2(S'0'))%$32P% LIȆJP8XD%J|)NH?Rx$a3I"(s3( @he3'C9)9B?@fd@()?ФfÅ 4 (g&e! Ls$(g(se&XXRD0hOȆJRP p sB&gȄ ϡCBP3)̳I9ddJdI(y(r(sCI 0adsJ&fsNP3ϔɔ’ X3)(!CI)”Ô'CS'OfaI2ffrRNPP,C% 'SNryIÄC'&3D hdrg(s LI)C3d2Jd"dRP9̔>g̡̤C)2C9ICIJICIB™9CI LBfIB!3OJdС')3)P9 !HP&r?I9JfL̚aIBpL39D B8D8S&bJNS&dNadP(Y3%,?30Ls)Raaf ))>Pg̡ RPNdB)(e&  T' N̔&RNddH Jp)š32垆P2s39S 2(pJP)))@™8D d,)Bs=fS3dIϙI'% JP?-qLФa?"dI9@28e2I$C%hJ(`t(fNd29@29Li= Cg9IBt'( B$IfJNe0œLI2s2~RPfJaIB9CRs3 dȄ$ᔒPɔ8R| 334 d,dϡ“2 s9PФr>0СB8fP<JfPM B XS%%zIePI)8Re0"% %332dJJ39$S')HP# % d(d @|L)(g% LRCg 2Ф!e4fJ,"2 C@,I@O PB(rft(Jhg=S%3% I3r)9(Iffe&XPO™94''(rIs?8D9̤̔&LJfM &D38PICɈ Na S2P IIg"(e L|I%L&L 4ϙ)&p2&e0 !B))PK0JJR"̤hC))|)&R&C$@)”9C3&Rr d"9"2XP9@$'3唔 )2(J| C 9C'HS&s3PdJa2S%PP%0 3) )g)332S%333(fs )2Y|Ʌ%0 "9@JLs9)!C9ɡI ILϞO B$(g2$$J2yСC)" >D JLrp)S%3%(g&fg2HJ9I0fJ:9Bg 2fLP32RP'ɤ(D̡CIФJ2PP9@ zM39CIp/ sBfLJdLa)$$M))))>IRr!(Re LNP3̡'0g0Jg2~S)% NaaC)Ne%JB)(g?)(2P4(e&RiB,"9RO%d"9LS!T(hLLP9)&fr: 8LP&R 2|)P2œ)3$B|,fPfyIaNz"8~S'):I3I4p"C%II>S'D4 C4='2%Pfg B…3I4aB!L̔932r>t0"B O %3 ̑ ̔NLaL)™ReLßȆNpd39I(pNaȁ̔39C<(X9NpdBJL"BHP,(@2RP,4)"" ) ɑ )Ls9)΁NyCIB9>Y)))(sCdS!D% (r=䤡2™)9P J' ,e JB!4%C2e 9" d(RPrfa)2Be釆RO%2irLɜ9Cɉ!y(r&zY% 9B&P B$8S3IC'L")32L9̡99IIIBI)(Rg40reg)02rffB!(S J9!"%PsPNLd s3)39B24 I|4<9B|fRJddMeLBPJp'&ffg%(ad fs")e!Chd!?)32)%$2JP)C&X(P hRe2XD9(pI“949C2~D8PNLpRiaC)9R ̡†g>p(f`y,"09LXPO)L9C)'IB’!(Re@" &r2fs̤4)28S3% Ns9$C' d s)2S4 hNP&)3g JHaL2!''2S3 &R S% dNkp JfB (JL™)2g30d)C8SLɔB99CBS%)i!@II%%%$C'3$B,B&fPyɤ4)2!S$BS$Be'It'C8D2SCL)C@t(g4ɥ J)")8S)0ze$:9B…& ~3C32S0J JCS' PȒHa  Jt')&PBBpO333 sI(p pde ?)(J99(RL43BJL,"C3% L%9™48D8|L"d RDL32e$BPg0e B)!2 B s&ddIsLIJ"IHNfJ9d 9I(ryL̔)9I@ t RINL9!…38S… ffg PJ(P pxrdae %&S Ld2e IIL(ffg S9IC)™2 sg)2)?ÙJPsCI!̜D(s)aL)(XS2L8S̑ .afhS'D%dIL$C$ 4™6af hPrfdC $:L̜)L3)RO%332S% IB))&b9):OfJBJHS%(s"@4 J̔ JC<2xg3)()r?(XC)'9,(D )Ά(O33332S0NJd NRNfdϡRP N !a)&P))>(e&S HIB))"%%0dA&'"'&RS39…M "%'L$IB2,f)CMg2!f̔9N4"38YI̡IL3(,P !8D2s LСI3,9"% a"ny C@e*YTԩ*jRE*YR*DKRҪ,JZ*iJZ-IU-JRVZYqjK,,R)TJKK*VTeJjR*Jh.-YeeEJ,Zԥ%,I-(R҉+**RT),-*i%UJiieeJʕ+Qk)-JYJ*UYT,J&RYiK-%Q,jI\e%,JZJIZRY*˒Y1rJVXETKQrJYY1Ye*URR*RʋTZ,ťRVRYRʥ,&.*XIJ(QKY*ZRZQ2ʕ%TJ-IKTҖYTQjJU%Z.YTYRRdʒUJRbqKR))YQ2ҩ*)IK,)H,%,))eK*eQJ*K,)Rʉ-*%,*T,JKJԥ%j+Y-d%ԖZT\Z\JRZUK$eb)RVJr,Yi)e*JRYRX䥤%K-,%JZdIJU*R%.&T-)J)EK*YeIJ-Qb-,TZUVITJZJRRJ,K)TJTUV)R)JR)R)JTJRT҉JRҤiJTLJTTLM--RLIIK-JQTIrjJJK*YJT)i-IR)jJZYqe*QRRjRʒZYRҲ%)jKRZ-)jQrTYR)Iie)VT-J&TT(%ITYIiV)I12XQjQjIjJZYR*TEIT8*RT)JT\LVZL,)rE+%&K-,TTYRԩiRҕ-**TT*).IZ-heJe)QKJde)JR%-)R).R\勔TL\ZJZRʔJU%ԪUJ)iZVYR-*RJU-)R-%)IM$RҪZTL奩JJ\*R,5YRR)iKJjJjRJU&*RTbk)dIe-IqeEKKR%,)QjJJU)RZZJY.YqUUV(d2ie)jJK*VZ*)JReKRKJT%+&*Z-J.)j-,J,ZYrR,iDRK-&&R+JTKERZʖTZV\Z*RVTJR\JJYK*&*RԕUKRRieRԔL)JZYie%iK-JRTK*-IjKTiUUeDʒUU$-eDʔqe)Rʥ%VIXbTť*IRʕU,(*vQ&-T)R)IhdKJZ&ZR%%)JR-%JTZb䔘JL&R-QjYieJ*-%R&T*ԖL+-)UZViVTғM(Rʋ,*,M)QiR&&RUU-E-$eBee&-,,)jR,Z,)RJbYRYJRU)%,E-,iV*ZXҪIJZT$-RZ-,)YQ2Q40EJ)-JRʔJ#),%-,Ek*UJ*IRZRԤ%&-,M*RJ*KKK+)TTe-E*R*JRK*JTTZʒYe*,UReJR)RҖ2U%iijQijKTX,JR-Qj)RV,-)LTRIKRUZRJRR**Q4e$KIk$IKIi)i*)K*RԕKYJT2)JYIj,)*QiK)RKRRJ&.JT,ijJ,UeK%*YjQrJT%JU,ŕ+*Y,VRZ*iJ),%ETUE)*Ԓ*ieRTTQ4d)TKVZRJZ*,ZZKRK+-J*T)IjRVRbԩDKQjʉKT%*JRKJ2Y2DҖK(y././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/mb-album-id-form1.mp30000644000175000017500000003370200000000000022316 0ustar00christianchristian00000000000000ID3#TXXX0MusicBrainz Album IdTXXX:MusicBrainz Album IddXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/mb-album-id-form2.mp30000644000175000017500000003370200000000000022317 0ustar00christianchristian00000000000000ID3#TXXX.MUSICBRAINZ_ALBUMIDTXXX:MUSICBRAINZ_ALBUMIDdXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/mb-album-id.flac0000644000175000017500000006566600000000000021520 0ustar00christianchristian00000000000000fLaC" BD-oW K reference libFLAC 1.0.4 20141125MUSICBRAINZ_ALBUMID=MB Album ID@a9'I!$f&D'̦gIJ|9RJL3L>IIB)"%3338D !Jg(s̡C'% B D&e̦s9"'3)=Me2e  ɔ(s% ̙C9B!B$!IIC3&fg2H С32D Js9g?)HOI33 HPp p28g= H JJCBfsIC"L, (PLI9 ɔɔPC)  0JJ)@ФC)2(Re8tDI)2% gReСCINpP)JP)e&%D&RP B3<O!0e g&Pœəϔ̙I3(dJPaa,XD Hf)8S'%2S%2S3)Y%2D3)8s9̡I3)2ϟɔD2e 9ad̔L ɑ)I2P)R|!JM&DH s2?))C)Re HD,=PBPdL̦L"L.e$$ L )YN"s2y%&rS32S DP'C9a4)(i RP"JNN&$fsr\Re2RPdg(rg(D8DJ‡ 2Si2S39)  @"·DIIL') L")r33%3Rt“(g?):)2PNy)'&yI&PNRe JÙ)3BO9̡)(RyPɔ†%3 LP% Nfp …&e9C!O(iD&PIB!?33ß ɡ= 4(sr!C9C̑ r9 >333>S99R93 MC3'@L2JL Iy:aaȁɔɤJa3333")@P4h32iS2s%0t9)2?硆 pC<99&RS%hrB?ɡBRfd L IaB2̤$I9B&f9̦NR|Os`D9BJL>9 SD)%ds9™2gBpX2O2D\<)3C&Re L332e!ffps4 (gh9CL2rD e&XS39BRg3(Lad(s4)3IJ4 L92rP3e“%2egRe <ɔLΐ)ds%8RPePg3) 3L3 L p"!ɔI)re 2P"$C3 J 99g9C(Rs3̡̤dIB?)L)Nd d I)8Pd'IC94)2%2)’dD!Cr(fPJC LIIB$ΒS0B,)?,dJ%=2SPJJL(Xe32r))s32XrD8z9CPfs$I3%RP(faICINI&Lɦ )94Bs(PPzBPJ,>49dLI2P)I2)Xd(rs4)L02yLS Bs%RLL B!C9I@ %9(Re2RPfḑ%P3tM0(JS I3)RO?" A33yBI< rg33̤fppB~S$ JB!$( B1 4’̔8R~S38DhaL†faICg(hRP,I)’38D $(RdL<3") ri= 硜9(r O%2r2)&d:’' r!3D9?z"?NR JJ̔39(JzM3%0 hPɅ&S2Y4™ɔ(g$e$9C'pH!Lr9%2PBP)zdHPd29I2IB!̙™Rz))IPL))4(JPe pP9B49Cg?)ϡ?O8i?)y'(g3%2i""B$M% CК?aB C33%™2!ÅDBs%2D2S9 dCBy:d % 42RP32yCPB<I9ee2PС!PC%(D9(fP )29<),% Cg JaB2' ,)ffP 9)  KS2P̒yy'3PLP(|(s)™Bßfd HȒJOC99IIC3'(R8D8t9CɦJaC 0phS JCɔO8Pg%2rK0y48D92S34"8PrP,)O(Rf1$(iBzy&fdfyB2|"9J)(™(RP !(ga̔)% J2i)"C3339̔“† NNA NyL0J)2P`DfsB haIDD%9(XgB̦dB?)2efr3I%2P dNIa@$2B!(XD JLffs9$$49C™'RXP9 he2P333% L@sL @333(dHPœg2|$I3&X ,)LI9%gɜaLC<(hD% fO0II3&p JJ)C8RP9IJdJICM2Pd&Jə"2rs (P,”9(g !̔$Rr rg dNDICIJ$C%C0BdHD4(Ra2P:33i2!N!BRL%d9JL2$̞Re$3B)SPПA0afs%2t% JJp=% f9I<2y)&y6aNJ"(PaBe!@= (S0Bs%33332%B~PRe%32D%DRC

Re N?Ù) pfsBPBfhPhPФJ B'&PNRP.O<Y>t&D%9L BOLd%>4Ɉ9(sJ3)2hP(s% 'NP!… I(e&&PL0 B<2e&h(g9L̔0LȄ3%fs9Bs9>D JLȇa"L4)JfP&D0P a,4))L PrC% <&2r3@@a%9Ha̖P)(yNsL2 h 22R.̦ND&sS $R NN̦e'2S3%2&S9L(RP2RRNhp J̳,48D8P&PI0zhD S00dS M $Ry%2P̠XPI)>S%də%:C)'(Rpfs'CС)C3 IB KD2e'CrPB(fILœ8P3D,"B!IB&R|I),̤H0 3C'L ,œ8S0 ,"zIB$%39I)Nhr)C%2ФI%dP$Γ4&De)I(s3%2iɔ43!Be"&s9B!HS9BRe$‡ S$!$Pg0 $@D392!PSrS9C9BRg0D%$fO’hP@))9CHD$@,)C$@"(s%fd3)2œ!œg)Re&ffDS&(Rf,9B42S%2PIBdBdBe%2S%2S33">&I4…&f*"39a)C)2 RPL "rp L&Rd@g(s2pfp%)'"9C9!C,e!hg>y(XRRD%32P)D9i"%&!B… JfPs9))% %$C38S(JC@9LafJd B!2Д9LBs?C$I"NOgC8R d%2 s2D9 IȁD<%(K&IL̤'32eJd),(y4(Jr9‡$L2~s2S$C9D)2 L)pg%0NffM0 r|2PhRpSfPC2t3%&HM$Rs'(Nffr<̔D32PNdB3S' IHD93%'L)9C% JC)RfS'ϜO̞eRPfPIC333'Bt'&i"(P)()39.i>hg>I&S (JfrrJPRJ% RD3NBBs&S&J" D%0hPаrr&S3d(r)I s<fdI̡9= CILLCO)-q9C !L3%9IpRg9L @d@`J2 2S0JfPAaC99L)&r@ɅY(Re'C9d(S&Pp pIIL"d"dL,̤a.II(r?S LM L fRJpСP B Rg8S&R~XRP(s Nr=&):N>| BOP&r49C4))(RePBe geg8Sr%X JfdaJI9C'&hRf4e3 J)2hpJ} C&Pe0O&pC2y)RO PaI̖g3%!3%PC2redRRS39'3̤r)2fJJHIB0S%gIII%t(Ne%P$BP2Re&S2):RNe0y"C)% s(g pfe L3 $)%&&yJ2rRO$&PgBy)hr"̦g)2΅2P Re%XPЈ rg?)ȁfdBPJ332r p)"'&zM(gJPP(H@yCC99I(RȐS&gϜOIB!"8D4!<))‡L2S33$Bs29P @)2Pg(e$Bs&S J)3By4)(p @hfrxg?d )a$ rfrg!OsfPP̡(D3% fRg330JdIC392BdRDpCIB!“))(r)S$…2PСrg$JfrhRPСI%PB!:<(fR!a@(g:)ɔ9Ȅ%RPiIBJ ɔ)0JL LLS2z8t% x| h <ə)% BB)NfaB8Re39B%%%P󙓡"%3Сg4(g&prffOe$2e$,)" 9L%e9))dON % Ü$ RRr9BRg)I<I9BXP"JrPLaaBœ Ñ ϔ"L3hRs9"L"d29 RNr933&Rg(g )‡xd% fs(Ra&yC!2sg4(S%0%rRL(RgCS)Bt ̡!ž99BPPœIBdLD2S=)(fa)&R8Js9I99Ȅ"(gI!@0K3̑ BHD%9ffO JJILB')t2xs)!I23| Rs $ LC4'd&h„I%HNs9,)(S%3D&yNzaJe <,IC'$ 9BtП))8həB(d2pNPg J\32Ps aJILgd&rs2S3%%)0$&)(Rae LdIfr3ILdP"C<39C30C39PФRM3B )8g ''I(stɡByP2S& RP%8Y8Rt'L))Y垇>P?4aCɑ )IB<)"hh% I2e!™9&S2D2r}'C9 ̦Ba%&s2D Nd'(s3339L)3Lɤ"g)2=RRS' JJ)?d@H`I)9B!ɜ)2DD9 ̡ϡL9)4 !(Re0P d!Nr9aȄxg>S% (Rd@:I,"Iϔ'BC8| J92y NfffpaC)(Re3̅ dICJy4!3fJs3Be$™)BBM3(P rJ!BYN!& &s9Iy)<)HD9ɳ2S'IB Rs%(rPLCC,PNNhS'2D J i(Y33% "( BaJB!I40ɔC9Άe2yP 2HD932XD9Ù@)Be&&i%2y(pNLB'Ù2ÔyN~P)4)9̑ e2Pd(ffdLB9g32pNNg2D&D&D'Y$I%ffd LL…Yg(fd02S%39S%%3 J,)2(RfP/CBP(&RLIB)hP0(sL(rRL9IC339z%e$̙P)œΆJI3% C@r!Nf)!™)L)(Rs%%2S2Ps)2C3 JJ(s‡3&RJfffJa= Iœ?4 LJRJ93(p'0gs)%% rrLФdfyB LffpJdC&sCP J333̔)@ɜ dLɇ9“)(r% 2DxRpM3IA2PICC4(XP%S'0СLLI3"LdM'd҄ȄHr34,"8S39C“(g%fS%!)fe ̑ )H|I@faaNg(d"I4'C JJr\`A C3NPPФ&s3 &C8g3$@,(hSI9$L'BNfOIB8S3 Ls9̑ I9P̟42)s0: 9 Y%3&&PP%)9,2pJ%9) (rffg)2‡3@ Bd= 4)):J &&s2Lœ"'38S39@LL)2ffPJJ"(PФ"% Bɔ3&t% JOIC2hs(e!󔙙2&''BJafd2fS% C9L(adS&P΀kryPPr%&RJdffH‡ g drR &p(D&S33(4&sC’% IRPr0LP) 9'3%8SB'̤(he3 d̡…8r!2g PCBYBP$9Rf%3 @3 I(hhXS(p% ‡r rBPJHIfiBP$)3C33% Rr,)™IaN2g̡̦g(rrrfdRSSfaL0)rS3)I)339fJdg,(LC…!J>Rafe&D NRg)02ȇ C9BRP"dS&RfȆr0d(POee By% C9)2'%9gI)BPJ%P)'Y9ȆJr23")BRg>N%fs%PSC py"!9''C$@))'9,Xzs>e$!S$@ (fPI)(pRfCRL’%4 rOBdH~XD &ffJ!2S3333 paBC…%  afP(pdpL L)(P fd™>S&r2%&fRLIBœg(rL8S‡2&P)=PS fxYLOaeJ9BD ϟ<3(S3% ϙI„X|L92S%0硞e0Jd(|"%(,(D99IIp ̦JfJHI†J 0 g PIL)9)C8D% NP D9)S'%2S dIC3% )Nhr s:CS% % BJJrD9(d ɤD O(ffaL)(y(rdfdJIICaI3<3̑ ))% 䦀|:J"LY&PC)9?)RB3>S(ry(D8D)9):!BS=% dȁII@)3@0`IPzJH3L9C')CB!B΅8S<(s dgRe'dI"C!$I9dIL4s)&fD, 2d’@L40LIL9CɦJJffJfD&RY!’!9@IL)8P&g3&e LaL<9ICL73IC(Rg)Be ОIB| LRXr!!3$g?39s%2RrRar%2S%2S&)2 9dJJ(II3338S2e32&P99932SRDs dJp 33rBPdJJOdB(S33 Rs3)(RNP338SI )(s% IC2r=!ILg= yB@ œ8YCC 8D% fH)=% DP)(AaLC(RrP"LB!C9BhOC&RJd$g JJINLLIL̤"ddJB)RJI̤39dJ%?gC%9B(SRPIL3I"L"L2fpRaL)3z9fNLRP9ILɡ) B’(PhRs$Bri:Jxy)(sB dg= ɜ&P"S!|!B$^S NH?СCLP̔D,&h“(dRSi)PJJJa JO 2PJg(rfJfH!f9̔Ú) C9(S'(D&RPΒ994IB™"))IPB32S$Be)(r Je"9L38D(s̤&B&Ng Jae CC%%332@LIIIL)?)C dS39Nt(Rdə@ ?)3BPfL&e0NaI)),(rfaaȁaM a䔓9ILB94(J}92S)(Rs%2i(PP& )ffOCs0IrPI>rf|JHD,)L(rJa(PS p pe 9BPȆJ!3>g(J!NIL, C pC9@ 0O(y)")@9LLCIHP LPNB L(fdLg)) fp L3%C4L9)8Pha')=(d>RP4)(IfS3'92D2Rr2gIRO3(dd sL)% ϡS3BPPP”'2P"p"t3@ɡ)8939!D2i0NstfRe O=f  NRgC932PNJd))Bs%330J)3)sM 9(RfPP3()&$&|IILdfLЈp )9%02P))(SaL"L# 8rp0g0…L9@)XP4?)s9It9(d(&KIB(Pp2er@Άs INz)0 ffd)@P`P J)ar9IB3fd!',&DBs42 >L8S3Le"d̡(D3&P)$)hPaNL"9JLfJB,,24)$2ÙP)2Ϥ4(g)2PNP0a<3>g2Y&B 9fe ̙IBRfLrI2(P)",) N,2(S'0'))%$32P% LIȆJP8XD%J|)NH?Rx$a3I"(s3( @he3'C9)9B?@fd@()?ФfÅ 4 (g&e! Ls$(g(se&XXRD0hOȆJRP p sB&gȄ ϡCBP3)̳I9ddJdI(y(r(sCI 0adsJ&fsNP3ϔɔ’ X3)(!CI)”Ô'CS'OfaI2ffrRNPP,C% 'SNryIÄC'&3D hdrg(s LI)C3d2Jd"dRP9̔>g̡̤C)2C9ICIJICIB™9CI LBfIB!3OJdС')3)P9 !HP&r?I9JfL̚aIBpL39D B8D8S&bJNS&dNadP(Y3%,?30Ls)Raaf ))>Pg̡ RPNdB)(e&  T' N̔&RNddH Jp)š32垆P2s39S 2(pJP)))@™8D d,)Bs=fS3dIϙI'% JP?-qLФa?"dI9@28e2I$C%hJ(`t(fNd29@29Li= Cg9IBt'( B$IfJNe0œLI2s2~RPfJaIB9CRs3 dȄ$ᔒPɔ8R| 334 d,dϡ“2 s9PФr>0СB8fP<JfPM B XS%%zIePI)8Re0"% %332dJJ39$S')HP# % d(d @|L)(g% LRCg 2Ф!e4fJ,"2 C@,I@O PB(rft(Jhg=S%3% I3r)9(Iffe&XPO™94''(rIs?8D9̤̔&LJfM &D38PICɈ Na S2P IIg"(e L|I%L&L 4ϙ)&p2&e0 !B))PK0JJR"̤hC))|)&R&C$@)”9C3&Rr d"9"2XP9@$'3唔 )2(J| C 9C'HS&s3PdJa2S%PP%0 3) )g)332S%333(fs )2Y|Ʌ%0 "9@JLs9)!C9ɡI ILϞO B$(g2$$J2yСC)" >D JLrp)S%3%(g&fg2HJ9I0fJ:9Bg 2fLP32RP'ɤ(D̡CIФJ2PP9@ zM39CIp/ sBfLJdLa)$$M))))>IRr!(Re LNP3̡'0g0Jg2~S)% NaaC)Ne%JB)(g?)(2P4(e&RiB,"9RO%d"9LS!T(hLLP9)&fr: 8LP&R 2|)P2œ)3$B|,fPfyIaNz"8~S'):I3I4p"C%II>S'D4 C4='2%Pfg B…3I4aB!L̔932r>t0"B O %3 ̑ ̔NLaL)™ReLßȆNpd39I(pNaȁ̔39C<(X9NpdBJL"BHP,(@2RP,4)"" ) ɑ )Ls9)΁NyCIB9>Y)))(sCdS!D% (r=䤡2™)9P J' ,e JB!4%C2e 9" d(RPrfa)2Be釆RO%2irLɜ9Cɉ!y(r&zY% 9B&P B$8S3IC'L")32L9̡99IIIBI)(Rg40reg)02rffB!(S J9!"%PsPNLd s3)39B24 I|4<9B|fRJddMeLBPJp'&ffg%(ad fs")e!Chd!?)32)%$2JP)C&X(P hRe2XD9(pI“949C2~D8PNLpRiaC)9R ̡†g>p(f`y,"09LXPO)L9C)'IB’!(Re@" &r2fs̤4)28S3% Ns9$C' d s)2S4 hNP&)3g JHaL2!''2S3 &R S% dNkp JfB (JL™)2g30d)C8SLɔB99CBS%)i!@II%%%$C'3$B,B&fPyɤ4)2!S$BS$Be'It'C8D2SCL)C@t(g4ɥ J)")8S)0ze$:9B…& ~3C32S0J JCS' PȒHa  Jt')&PBBpO333 sI(p pde ?)(J99(RL43BJL,"C3% L%9™48D8|L"d RDL32e$BPg0e B)!2 B s&ddIsLIJ"IHNfJ9d 9I(ryL̔)9I@ t RINL9!…38S… ffg PJ(P pxrdae %&S Ld2e IIL(ffg S9IC)™2 sg)2)?ÙJPsCI!̜D(s)aL)(XS2L8S̑ .afhS'D%dIL$C$ 4™6af hPrfdC $:L̜)L3)RO%332S% IB))&b9):OfJBJHS%(s"@4 J̔ JC<2xg3)()r?(XC)'9,(D )Ά(O33332S0NJd NRNfdϡRP N !a)&P))>(e&S HIB))"%%0dA&'"'&RS39…M "%'L$IB2,f)CMg2!f̔9N4"38YI̡IL3(,P !8D2s LСI3,9"% a"ny C@e*YTԩ*jRE*YR*DKRҪ,JZ*iJZ-IU-JRVZYqjK,,R)TJKK*VTeJjR*Jh.-YeeEJ,Zԥ%,I-(R҉+**RT),-*i%UJiieeJʕ+Qk)-JYJ*UYT,J&RYiK-%Q,jI\e%,JZJIZRY*˒Y1rJVXETKQrJYY1Ye*URR*RʋTZ,ťRVRYRʥ,&.*XIJ(QKY*ZRZQ2ʕ%TJ-IKTҖYTQjJU%Z.YTYRRdʒUJRbqKR))YQ2ҩ*)IK,)H,%,))eK*eQJ*K,)Rʉ-*%,*T,JKJԥ%j+Y-d%ԖZT\Z\JRZUK$eb)RVJr,Yi)e*JRYRX䥤%K-,%JZdIJU*R%.&T-)J)EK*YeIJ-Qb-,TZUVITJZJRRJ,K)TJTUV)R)JR)R)JTJRT҉JRҤiJTLJTTLM--RLIIK-JQTIrjJJK*YJT)i-IR)jJZYqe*QRRjRʒZYRҲ%)jKRZ-)jQrTYR)Iie)VT-J&TT(%ITYIiV)I12XQjQjIjJZYR*TEIT8*RT)JT\LVZL,)rE+%&K-,TTYRԩiRҕ-**TT*).IZ-heJe)QKJde)JR%-)R).R\勔TL\ZJZRʔJU%ԪUJ)iZVYR-*RJU-)R-%)IM$RҪZTL奩JJ\*R,5YRR)iKJjJjRJU&*RTbk)dIe-IqeEKKR%,)QjJJU)RZZJY.YqUUV(d2ie)jJK*VZ*)JReKRKJT%+&*Z-J.)j-,J,ZYrR,iDRK-&&R+JTKERZʖTZV\Z*RVTJR\JJYK*&*RԕUKRRieRԔL)JZYie%iK-JRTK*-IjKTiUUeDʒUU$-eDʔqe)Rʥ%VIXbTť*IRʕU,(*vQ&-T)R)IhdKJZ&ZR%%)JR-%JTZb䔘JL&R-QjYieJ*-%R&T*ԖL+-)UZViVTғM(Rʋ,*,M)QiR&&RUU-E-$eBee&-,,)jR,Z,)RJbYRYJRU)%,E-,iV*ZXҪIJZT$-RZ-,)YQ2Q40EJ)-JRʔJ#),%-,Ek*UJ*IRZRԤ%&-,M*RJ*KKK+)TTe-E*R*JRK*JTTZʒYe*,UReJR)RҖ2U%iijQijKTX,JR-Qj)RV,-)LTRIKRUZRJRR**Q4e$KIk$IKIi)i*)K*RԕKYJT2)JYIj,)*QiK)RKRRJ&.JT,ijJ,UeK%*YjQrJT%JU,ŕ+*Y,VRZ*iJ),%ETUE)*Ԓ*ieRTTQ4d)TKVZRJZ*,ZZKRK+-J*T)IjRVRbԩDKQjʉKT%*JRKJ2Y2DҖK(y././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/missing-headers.mp30000644000175000017500000013740400000000000022274 0ustar00christianchristian00000000000000Infot #%'),.2479;=BDFHKMOSVXZ\^cegilnrtwy{};LAME3.99r$FxECqQ"`<K[|cS>6K$ثSv4#c`imE Dx ``xQ"Vs!e:= CcǏ?~{%lU٩; r10GZ DM46цC" <00 Xihz!bǏ~= 0'0 0x3|Y%0Ky3 2(030hl` l`$BR+ UmغżKƕIl:1+}`R<i,%Ἑhm46Cu060V!`) o*̂l]b%J00fBv"lΆ[Ѓ!9 Ç|@G!Xp!`"LkY;V\@0 >B  `j3!; `jbCzhAc5a,`a n``z !DvL NG`"@O @5B81 ah =tW.Z,4>:DI4j pc)S @,z2T2Y35C0:&z51D0h2*XAU T{ɆYu*Z,ܘiic="N4ٙ,eˆ= M(L% DLZ zMv@L@V i*i@H ( >0UXÃ;!pw!"@00%1jT0f551X119 #t(`#_ Ѷ36.ݝc * `IDjsDk JLhtLnnο1ƄFQ595!eـV"ϋqvF$:abL-@NXb+`80bA!C tݟLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1 o @HUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU0gy7@ѪA/LXL M3΂C9O"@Q8Vj |bdž`llh Ȧt̚xpBb2b<̯YzN=& [ʨb%FZ4"odW4dy^;c]{M:PJE<'9hDȯLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU34ă7s#hbM$6P;-1G>]v 6d1H?ҰR%TMG7[4peWzf?fFhIHlv[,cN |l baFJni|ʮgqεDj5"d~|؛| {s%8^)sC@#X֨ZLoOcSnryĠ כ.b@"?~1HLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU >8`w,'AHUUUUUUUUUUU2<2h3MN504Rj47G015`m115NMWZ[|MO4jCd)_\0e '&-&/MYLI߬"h Qj`] URf (1KxvO٤aȒ%[Ğ& HU,j"4ggULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU D3!(w+AaHUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU23ܰ591R6h{S=ʆ1A*91P1370$0X/s!߽OIE)偭ǩQ,ٳCڙT0 Qq ٙA&!{ ^OL|W1Ǎ. a.̮L0wYl~$ZYct!f]]]È,`+ȳ n 8H_@)LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU @X`w%bhMUUUUUUUUUUUUUUUU0@DZ0#6sSgnHCOM [5PsWH ~?`#`ha)Fl4&xf8jjA"~G%C>t08A1S8;01lq111P2>k3N]R\3NC33MC##?T[LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU D<(s0# @bHUUUUgLwOP, +̘ B=L j{zAcc;~ɨL ! Xf o S=wz*>%9ieXNKAɦFT:t.Ytino NfdF`V`&uӒajriN }`>|99LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1l|101E"1 C=!(po'@H0EE1*4uR061b3h@5&9`8`js"Acቅ)y*(UB11p<S% Z4h=L(𖌊Ϲ~ ^`qM L+J(uϬ (0YlNJ@L 3rSO+/0LXx5 ZB׀Q 1p ƀ!I~7HR,cd&M)}F|,5 QÆ%t)IP#f00%:>x1i1 SP0RMB0;Tp] eULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU4`vcM C_Ȱ@aHpk% @H`D\`:pp^cb)Fb&)c^a /B?L@0 ;1C0"0NƝ8l8/11| 1B10@PCq&̀ LL Q 3~7# ^LM @˰кD (C~% LL Q 3~7# ^LM @˰кD (C~%LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU5Ճrg:80t19fzs4 ! īD!Xo+ @bH ;|05g6W;30,0@ ,ҥRˬ_u`ܙΎ8L0zGY!G Y͕Ǝ !9 K4cT/"R{9z (33Ӣ3D < s N=a00j"vmjG՘iAaB'^`#MuId  PvIheLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1TƧ.̧:0's0gǪ1弾1Gf3139e6ʏ ;AXo - :AX13618 B@jm"5Q5=ve9с<>=Q-;1I` ) ah(:Usi5Aa2paҏrz)L2L6] 2ã ,`2x&Iq 0x[80MGq9F=X&Q.~@aщQ00LPu6p ?;*lj`BCHx*ZCa\<7Af*XO*@4 & ։^:1C$x<-!ðJL._LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU! L2ȋE +ذHXo+ @bH e,LT ̒O^NL L #QNL38N((Q_Y `hjac)bfmdztƏa@``araqD@%pDGZ}g!& bgf0F'xf& 0gQO~!|6`p =ruٌ+Y8 <A;yLpa߈~MLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU  BXw$)$!UUUUUUUUUUUUUS n3x|T*!BlHHŷX`PɆF7B<`Ծ}ׂ*cfz`Xr`6$ioNQbۿD@Ɂ㙋1k羙>Y6)˙p`l ݏ"L /^1]MP ?=ϯq <t&LLW -\˃eL5FLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1!AUF8D&F *9F D4!Hs t+daN'nc-m\" Qb+A JQf$#*0t'"^eG({ŴͫCA4 E`(<iX ;wAHʲ҅ȤLJh Tщ4 pIkX.1E1DR1s24a9ǀ2)'>1Hb!bMb{re#ZV$˹LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ?Lt%MFCL菹̏3 ÃFaXps-dLm "_bLV!@\@B! 䩨ar]8;)API1 P6Or#(}`N#L <1@<HA0q@0(HYО\E6IAG!QyFyb>x a ⁑9`P=e>v?EmLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU E9ahw# -CXUUUUUUUUU >qL";=N`~oϽȌ~L%O=N_ Q"LX/:^2ǞsAY"iDQgэ8Y鄶iG$IA KXtQ0%$ޜpŢM d vP$ 4 X4 av-ox&6X䤛ӎIA! Tjğ<&!l4ŹLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU0T8 L(  E9ahw# -d7@jqL#$daE "\ pYC8 <`oD?f )N1 dق (\  (`GQ gwd 0P.0[12 5*0G?u0180c2p0p93:  =AI f f5]EFH'LfN"fgA@b#X?LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÏ Ã AaXpw$,+daUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUm ~aJ2iF`L``gcDz`x`@Ա=0C%4Cc0zU?&i0w031F=0@Q<0 jX~Z \ L wdHMӘ38a(A 8ֈ0!)2Ń]07>h4 !6m C0"FuLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU (0!Xo%+ bUUUUUUUUUUUUUUUUUUUUU$LbRiFsa vqdć>avc`{ؚ"L5C?$LbRiFsa vqdć>avc`{ؚ"L5C?0*f  f ,f0j;1FF/&adRa v. C3I3 a3w5wJ#c`Zd)0pULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1"̲t4T}C l3oo  ;Xs$+db씤S,E1Wx3Ր67&10s5{"\c9NjϨa me`20buazЖf4fp 3'M͞p#矝a?p٦Ue.APjae0$D&&څa8l#l< #2-r S )&0!006(U߫UwLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU0D(0)60q00ʏ D(:ahs% - >A >0@|0,0s0?ē$4@2P#7S!@ G %Is>!Y; a $!QRC"YD'Ɏ0a TArJq:& T q @`io!UwߪǑ,̢PӓdFX}* ǎ@¹%8 DCB@ 04]wLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUɏ E(9hw% - 1є+#hZ K϶Y. 'jt5ͅ < B%-WQC|c)VFе? m ]RAOk41 &AxKA[[LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU4d U@aBd S C Jahpw$ \-+~ccoH``L @Z!$M=4d U@aBd ~ccoH``L @Z!$M=0hQF3(QfwrF Y}PaᜎR3  ,nAQf!pܑvC'VFk_T&'y&{w$ 8g#iC(A +[_;LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU2 E(8hs% H-IdAќ̦Qa,c~h c$`=D`:b`%aREWm# tg3)G7Ko%IaQ' `XTUw6E0S /0T61<e>-1@1胗0:sة<L21 lj0X<Ӥ$cv̐M@u0Hi=ǻ3ψ; d3&Mb3X@"^e ox?  FfHC&h"F'piR%_M@ BÛq;A'‘Ʌ Ɯ`锅EqLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUD VƋɀ L2{IS(I !f> C@!Hps"- dcAhTŵ\иA y0R0S6/}0]|1%0{Ad8C,ӧ0r(0- 8`P1<(sd(DR#@=7ĿB+̦n1q YȊͧv%O&!?Fc&)F&uF>ggV%v P=׎^e3qf DVm;o/LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU$e4Df ӏ D_ Cahk$ - >A)ϴxfK"4r lfCf.-vI`F.,M&hh;s!6>ً% F]A3Hs/#H3r 8{?ksn535$1jf+Ŵ0%Hb`gWceb/&`|~&kHfjHc(V3i- L 4d+@@ٔ3iQ01XD3^2_?Zw1208 43,2c1$, D`J?01XD3^2_?Zw1208 43,2c1$, D`J?LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUŏ E(8ho% - A0UUUUUUUUL 2cMG7#0]n0C38H00N;u4es'00TdGQ1._ęFJEW'`Y2Pi2TmmXɔZKA\ZR/&U8!A5(aRɔZKA\ZR/&U8!A5(aRLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1 C F!hpo$- `UUUUUUUUUUUUUUUUUUUUUUUUUU0$ 9i1?9=Zd MvH㿒|?20#'-5#1߇?4<\Cc CwQO Ze 0CL\1 Lp yj!~%uo1i0 0Päs'1pDŽ>&11.OaHV=]LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU 8aXo0+&@bUUUUUUX3 1R,<40>As041 <20Z@= :H-؛?Wfb&Xxi't`|ahc|yde``{,uf0[%7R<0 4#cH L] 'G.ը$( q3if@A6qܦ`FRf*`8f)88/vfF8~a$A@P[LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU@1lL#DЬ9L 8   C Chpo$-dޅZ Q1N07ѧC+LZ RX4b`A&a`T`bnt f2Larwفf:Xb`JGf"fe'Ƀ(`xcrAb0/ DcVf/`bRctqO~cTvl`6g$p  ,j_H&88fj(f|!9&>P:Ggf8GlFf{BJ ƪLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUɏ E(:ho% - :AUUUUUUUUUUUUUUUUUUUUUUUUUUUU.QdL(c TԴ:L 0H!nL:ݮY q > k<7gc/LfxWTr"aC`aDa ra׌frnKa{Y;xc0АE-ºZp8hC P)l>?c1xtck33#N0Ш;u^j xD8? #L)@qL8}ь |MϠ̍8 BHkyLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUke D_(9hk%- d씰1cL#w ~08 02HAu2y;M0]{7 )O0}A$?`bƙF`qa5tdd$v `nFRa*,ImKU 4$A`W4B-QWE54bof-AyQILD&qJQ "сZqXDSSF&-LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU4xb,l`H _ CXk$p+ $b`6c`tL$`D~C#؍4xb,l`H`6c`tL$`D~C#؍k0!'4{0>j0E240?0Ӂ>3^f2 03."W` d$怘os&-FWF6pp9ӆkVvb&`RJW=LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULs33f*;S0 46EZXΞZ AH`<nLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUIPaGI*O2!J ɓ!@1y J:g4X0ՏJ C IAhpo$ p- .iͣ $l|H'ƥXpdɀ à<% 3L2Hއ8"a<ƅQ fSRfkF8 &H pJfx/@jgE ` \0ևt `qcLqh\d&caa$`^@ 0"Ǣ?" <"O.À `Żw& `&*Lf ۈ`jcc((c|Άdvkf>dHb`N,f LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUKq46xAHК2̏ (?AXo% - 3P 쑘X<7CH2$!Kq46xAHК2P 쑘X<7CH2$!wa&ѱ`pd"a'Pa%L}ooany+-Xl` `"#;0ɓh0D82 00&>0p7<ˊ,60x0LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUP C Jhpo$- UUUUUUUUUUUUUUUUUUUU}I40@m1`.0T0_x>05A;Z s0 ߋnB040iH`(b\``}`jv40`ݪV)j TM 0BLZf JOM-^p$NB2tA@w"_蕹 fZsLRKs 1@ P ȗgLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ?(1Xg%H- UUUU~ ȍ5 sh r#ܣ#83C1\C _2#MBc@4(c ( r@%vW0aD+m- Hq`8_׃F5f@f1'Z&=Ѿa "hZfB`֘;d$o[3Lk2 6 d:[Ot Xcs>ZfB`֘;d$o[3Lk2 6 d:[OLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUE"@4UJ@\ 44EՏ D Aho$ `- LA,Bz(ϥ<&TjzC`Pra dpli% aaNd"d!pgҞdib``@ 5BG`фf05l!&?9JIh V. &H4 T4c)ŗ;G0@hc6GN%$+L$\ `\ e1ÁÝGGLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU E9,. Je0@o(6 9L#ipQ L Xy!I߬ d M'8 CNS H\ct#cHRcw3'0-"4LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU50C60C170-10 D_ >Ahk$- d0V?Y00%G0">cQ]tCnk`mh`0cmn`[b``=la4`K`D}0(iJk HHA &pf(fJ"fF xgҙ!gOS$@x*y-!"`F3@TDJġ^* M<&JdDRr?LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUSdE1= ɑ (iQnʏ C?0Ahpg&- D?QE($`0-dAlAF g!020Ax00 1"} 2M4G21u 0ଈ1"??/ jAp- c8]HgaEG% Ob& *+%BA H4.4,cs 23" (S U61@:EELAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU|<H)}L?3I,i۟aVJ%`PA!j"_яC C Hahpo$ - d!A F4fǭLyfK>vF9XU$F X'dn栈d&374([1"0R:?C0D0Aw0 3Lc:ɇ8pwLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU7 2J C0IAhpo&-HA-сH!bkǺ,J\`(-x0`^`|F `t gůG꘱(arHK??3G  3L e %42NULSFL    LA ߋwwu g&m2Fؙgo*)#&Xy WoŻLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU CAhp{@-(@UUUUUUUUUUUUUUUUUI  U Yfk &C2ʯ3@l(&` peИaI  U Yfk &C2ʯ3@l(&` peИa] F&(wFFf\Af f5ᆆ0,0h@¯] F&(wFFf\Af f5ᆆ0,0h@¯LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUS$m 0)0_B0g01ƈ=޺>6vE1X0@;1ڡ58 fe_o D=hwB -H` u)6@LJߘC/C3_AVD];"O zmP P3]_kf i Az# y8qI>y 1fQ5di $_D!j 1)$F<p4"3s8}*c̀4j AIw}_LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUg+1@ 9ᦑa C0T!h`s& -? 鲪?I)h?Y Y鈈 ׳ܘsHtUp|YѴO Hr,ntD A[k<@cWlSc9Ó%# dl3`0*CS:Szr4D1 3{5x& >Z's&K6Ff*'If `T *u2hb6fwuLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUaR*SŃ3gsNaYǏ D=!hwC <-hA'ӥ%s\UCgMU D A]> 0BA enwoaR*SŃ3gsNaYӥ%s\UCgMU D A]> 0BA enwoCF%g"慐Fs2 8F=ce(E]eJ$E +MeLQ! -2 q{L ; ZP PLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUɏ CPh`wB-h`ㅢ UUU9i0\;22P?1q0F1T40b  #cE.UȻL/YB$!)y15!, 0 ȡ(puxabj>^qĵH(8:\"P^=ռ+ Q8 %G9@wLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU;$0D<  D@hwBt-(@/LE-" @sL@4Ό 6̣ @mzN %?Ac H'#P'8 #M(#i?wY D n3>4/+ э=VY D n3>4/+ э=VLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU_溑FfAgǟƗfFF D>AhwB-hAf:AGKYfw 5Wi2pa Q@aY0Q|&QYႴ yC茰xBLINFhv\p(AG0H$F gN #0xp,0)<)8#0H2c"=M9n=@h{# DffLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU0P|Ac͠ˏ: CGAhpwBl-A (6Hް&X2""CfBkQW&< } ̔6=!(Bh$i!")0Qd&_5eri!ꆟT&FG&&ƞ&B&hFBS3B7\s DD<?_t410*28754=.457R0D:2>20A:&`R$B 0|EazLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU^(F D?hwB -A"kmpdA 0b K$PBmB RdkIZ'>&^!@5K\mS$ 0]dY ҇lh\#\M283f80m38K LH96?xr$jaE 讀XPt2#5l3,C03y#s 0Q]\^`/LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUD![H D>hsBx-A|7 ߍjLP @DcON-AL"p\Pt@4 DWilLk\1@1`P)ULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU5)C'3 8% E2AhoC,-hAAu#B^6ȓGaPD{OggVj QR9c*Ngq[Fp 78!gKh(F-'Nf m&* ¡ EQj[a\B? CFSjV١FZ$<2$lCaTF DjqW&ưFThDO 4LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVTBG CHh`sB-AA(F 50ޑ3f)0Z!N _mNLYj@E   $֫*f!r#moH3fRF-/ `,H5 fL  vz?&ȶoG&q`(d`ˍffq6ib`lIFo?4vd@8g, "پHwi.5i٥@i!i&adّ!LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU d*rfVaF@cōQ CJ!hpsB- ` ŒᄘـmE4DQET/Bdgo-c =ٙY;YM!6nC 0_cfw lgFc)aP Q{??eD+4I$ʥ5 M27LL$—YC N=?XʄBDLX3R)Ct rL)q;ko<@xN5d8(0pt#LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU. CEh`sB-AUUUUUUUUUUUUUUUUUUUUUUUS\ h&tlF'n fh 3&tbˡB!a"ag:fD5Se0=0Ct0on33E0^6]    ?o@r`(4`Q ɤ*0#( s;Dd@>ɚſ?o@r`(4`Q ɤ*0#( s;Dd@>ɚſLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU D=hoB-JA@UUUUUUUUUUUUUU@)8"a0"f DYAb`A :L&02sM~80RX026h?2N1@v>ۦeaPTaIUGDMʕ5#Os|K`† ٢08  n AQ&]$lag "i>`a0d~)cqheb `v?H$0 D|D`S'"(ѱ!Ah $~LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUԚ BxoB/ `ۅ j09 Mt`+`ZTaZu8bkggr`f1f(bc3gOO?Z]F7 Tiw` B ;ޫNZg Bb،zL " L||o{?*Z@)kR  Q8: O&Mf !?4 ]Q" !|ps #d؆a(J"qLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUS BJaPsB/ `ⁿ (`P4ڡ&Mݩ0C>0GY0Ψ9w0843I3133(&!båtH=@j7vm }d:0< ^D'4r ̠ gu ?0X=30$eSI ]pϴˌ|yNV5 -#̮ P/L  _u ?0X=30$eSI ]pϴˌ|yNV5 -#̮ P/L  ULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUF BHPsB/ DUUUUUUUUUUUU(*aU0u0n$aRF?=&hfh/&F3 Ю 0Es* :7c0s# S#hW?X$I(ڢ= @~P^[ 30X@ 0# 3cJ?6C!s3+#Bt0`t 14  pLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ăʘ7!xsS(- AUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU)$hT0!Ci380ۀ>u 91T*NONP4 a#@ IeɊRtQXLD0 lqL*p@@arc醢aB٪%A>=U %O {LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU DҀ3hoP/ j߅A@UUUU̺Pc٘`a*nutaqYO&A2 bAfb:nL *!)цF%fi?F d~b3 R3q>CxS CLzSKGCptW3L!ίo ZD+zNBfҚXB= ;$&?d1u{LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ă4xsP1 H!RD~bdF N0'T账*G, %qc-W$3Mc"0M0t1H>27?E1U>0g0],4jIl= C_ G`kD1 `" !L K,DkjWOݨHEMah6\Ff I%'{U0JHf p*`mXb ^V7PW!>11H11=1j05!0C=0WW3֐0Y501p:EL^DK#Xr3xs=iSc#X%OLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUb,fa ]l`a \bkJmhvj|baGa X8@sDp3b@^`{WFmMF^HWA3ax˱:=!`MqMOpL\(k@RcͩkÃizPP faR &@${if%8iɁѥG_A+AK1 {wEA@KD0qo[ƃԖ:F( 8&F },ā7_LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU[ C_ Ka`kD1jA!HUUUaqfX28l Iժ" `p#):yv{?d`IF2`gt%& Hk'WsV&f P3Lc!yOi, 081H\ 'cL"   $vGG4`ɇ . R 1؎&YQb??LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ҐBxsRD/ @UUUUUUUUUU9LhBC;? LKȎe1_̳ 110L  L6a(1Sƌ4)t3ıS0HCЁfOC@M}"OW'wb\(bhG V_w 1165>^h"^ߣ⌞s#Es@^apaZb4)YLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU _;xkP1 "@m 44a`P&= h&&  ( vd )Ugm 44a`P&= h&&  ( vd )Ug*0t0p po< э2j1r9 RIלᵳCXr$?`U a` A3Bx@;Sdc0s 9Gkg6H~9LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU:`aRceNhhkaRhdv2wUtc)`酬`^9 Eڐ8sR3jAbAHQC+C|c~wh5|S2T]C:ak@aTm8߿vס>NNt y.a|1Y&!`J:x?C|(: L 5X c \b# L C5342u"+LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUYS ƒ-J>SEs] (mևs#lu x-lcY V9 BRAPwR3jAbH#R^ӣwW_8 &Z|:Pf7ςF[f"Ʋ$r%IG`G}0@8ġr!LLpߌ[SO9a pq%$` PQͪ6b0gC !>.PQ$)inyj G,!$ 9YfFs a[>LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU BPPwR 5A!HUUUUUUUUUUUUUUUUUUUUUUUUUUUzCGH|M6<Ė H ,H֢ Ġ( שT4tt@j 0I`Ϫ@t@ "$j _LJ _r# ᜚Iɾ"[cp`v1`i'TL\pM Y$ @JL-HLg0;  L 0 ED AGfLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU>( ڐ8oR5 j`AL1̺QTMx,8P4ǒ(ۂߣwe F &ehgGXF'& .FcagnT~„n*_ȡ]*͚wobԏV ăJsR (5A%AH w@B0|B_x01:U}X: 21Ce0T6155j30-r}Waсv?edm蹂2Y8"IRnxea˂Ad@yFD#i B o9f;` &Jɺo͆. ULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU{³L(G $s0܏R`sR 5A#AH$0]E2m5 0j^0@56*\!by"ʙ=BY#F9@.әB\6d5A/ `.n`QyeLabI)٣#6Y`a iYAI遀R1Io?{ IHFL I 9K \LJJ L0L  ?K|LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU҇32Pȏ=!ؠsS T= A*H8|C#qs  Js #S T;68L Ch Y> 9|QN9*rn?UZ(J1ؓL 0U 鎏L   1:i`;7PUZ(J1ؓL 0U 鎏L   1:i`;7PLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU1DF!ȀoR3 @bHUUUUUUUUUUUUUUUUUUUUUUUUaP\ 1!A#8 ```Ўcd a\6A(5x@c."9+> 9fI pA L$ aqPCC"@;KKhd=n 31?Dᜃ 3H$񂆇0Dv18(ѦzݣgLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU!\  㤌PIL! s6lO D?6gR|9 @"HRLVE LL R{!\  㤌PIL! s6lOՑRLVE LL R{{P1c* M!yz1>`И7=(jTtU |7(o{P1c* M!yz1>`И7=(jTtU |7(oLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU=Ai 6Iz!xɄ"dΏD@oS ; A8aH`oD @@ ;5Z;z! 0-86m=yc (C"SQhD3"MS?ވ 2vk^wA* /)0G01V>f1DŽ0{6}7=6 a1 WlA_3 6 " &8T^R`0acs6|9>c aUl*o3@{lb0 ؃9LAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU>)Ay®cَ~: QOʤi!$NWJ׏7ăFؐoR ;A?bH|" 0R&55\<D (!Cum# h"H/HCH p8ŀs% 1w"La WL L ` @XXhII<{1wN8xb9UDa;P^ ѦPO0Apd cၬ4$ oLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU^И7a;Į%F`&-@wDNoR d= ALH` &N&F){ 8*fFB`pL`݄b{GLc_a``b>``s:9 d8[1X2t34d=?L1xA0c4pst 6UÆ#t;$[dBl`@aa0`ӍG0pVOLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUʠP؀oT=AǛ*G0"01J4w? 00%@W0K0|1Y"?qʑ8 *Lc ,8 P/6 r@+H)1DCC12Lc6R> 108@90m0,0~Ī5Ia @`1K7 , s@O⇈"1CfTB0-@0U80#>f'2A0D3D2'8/M1(Ph ^n/(x2/6eO4#P ,R3is, pC9C)bs& D?Aw`5A?v@F6:˖ <8pCl8SP\Y3@v Pa@'/```ac.|51J`K dጢ`a(gf-aLD_IkRXuK4FBa(` & `L 9 @M4CͼnX,Ժg-rrު]=)8K|V/_s@"@ @q LR8c(#`m:huM*QJ+ "(!u@`&0M9Po V, 5.lAܜf%Jw;{v9.+U? VTDd‡*ZŮc4J1Q1-D;*f@2*ƕ*¤*`Nӽ4jqM̩ҁA_Y.E؀ xlO Gjt$HL+4G \`[H88T ;Nkѫ[Ƶ72˻JLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/no-tags.flac0000644000175000017500000006461700000000000020775 0ustar00christianchristian00000000000000fLaC" BD-oW ( reference libFLAC 1.0.4 20141125@a9'I!$f&D'̦gIJ|9RJL3L>IIB)"%3338D !Jg(s̡C'% B D&e̦s9"'3)=Me2e  ɔ(s% ̙C9B!B$!IIC3&fg2H С32D Js9g?)HOI33 HPp p28g= H JJCBfsIC"L, (PLI9 ɔɔPC)  0JJ)@ФC)2(Re8tDI)2% gReСCINpP)JP)e&%D&RP B3<O!0e g&Pœəϔ̙I3(dJPaa,XD Hf)8S'%2S%2S3)Y%2D3)8s9̡I3)2ϟɔD2e 9ad̔L ɑ)I2P)R|!JM&DH s2?))C)Re HD,=PBPdL̦L"L.e$$ L )YN"s2y%&rS32S DP'C9a4)(i RP"JNN&$fsr\Re2RPdg(rg(D8DJ‡ 2Si2S39)  @"·DIIL') L")r33%3Rt“(g?):)2PNy)'&yI&PNRe JÙ)3BO9̡)(RyPɔ†%3 LP% Nfp …&e9C!O(iD&PIB!?33ß ɡ= 4(sr!C9C̑ r9 >333>S99R93 MC3'@L2JL Iy:aaȁɔɤJa3333")@P4h32iS2s%0t9)2?硆 pC<99&RS%hrB?ɡBRfd L IaB2̤$I9B&f9̦NR|Os`D9BJL>9 SD)%ds9™2gBpX2O2D\<)3C&Re L332e!ffps4 (gh9CL2rD e&XS39BRg3(Lad(s4)3IJ4 L92rP3e“%2egRe <ɔLΐ)ds%8RPePg3) 3L3 L p"!ɔI)re 2P"$C3 J 99g9C(Rs3̡̤dIB?)L)Nd d I)8Pd'IC94)2%2)’dD!Cr(fPJC LIIB$ΒS0B,)?,dJ%=2SPJJL(Xe32r))s32XrD8z9CPfs$I3%RP(faICINI&Lɦ )94Bs(PPzBPJ,>49dLI2P)I2)Xd(rs4)L02yLS Bs%RLL B!C9I@ %9(Re2RPfḑ%P3tM0(JS I3)RO?" A33yBI< rg33̤fppB~S$ JB!$( B1 4’̔8R~S38DhaL†faICg(hRP,I)’38D $(RdL<3") ri= 硜9(r O%2r2)&d:’' r!3D9?z"?NR JJ̔39(JzM3%0 hPɅ&S2Y4™ɔ(g$e$9C'pH!Lr9%2PBP)zdHPd29I2IB!̙™Rz))IPL))4(JPe pP9B49Cg?)ϡ?O8i?)y'(g3%2i""B$M% CК?aB C33%™2!ÅDBs%2D2S9 dCBy:d % 42RP32yCPB<I9ee2PС!PC%(D9(fP )29<),% Cg JaB2' ,)ffP 9)  KS2P̒yy'3PLP(|(s)™Bßfd HȒJOC99IIC3'(R8D8t9CɦJaC 0phS JCɔO8Pg%2rK0y48D92S34"8PrP,)O(Rf1$(iBzy&fdfyB2|"9J)(™(RP !(ga̔)% J2i)"C3339̔“† NNA NyL0J)2P`DfsB haIDD%9(XgB̦dB?)2efr3I%2P dNIa@$2B!(XD JLffs9$$49C™'RXP9 he2P333% L@sL @333(dHPœg2|$I3&X ,)LI9%gɜaLC<(hD% fO0II3&p JJ)C8RP9IJdJICM2Pd&Jə"2rs (P,”9(g !̔$Rr rg dNDICIJ$C%C0BdHD4(Ra2P:33i2!N!BRL%d9JL2$̞Re$3B)SPПA0afs%2t% JJp=% f9I<2y)&y6aNJ"(PaBe!@= (S0Bs%33332%B~PRe%32D%DRC

Re N?Ù) pfsBPBfhPhPФJ B'&PNRP.O<Y>t&D%9L BOLd%>4Ɉ9(sJ3)2hP(s% 'NP!… I(e&&PL0 B<2e&h(g9L̔0LȄ3%fs9Bs9>D JLȇa"L4)JfP&D0P a,4))L PrC% <&2r3@@a%9Ha̖P)(yNsL2 h 22R.̦ND&sS $R NN̦e'2S3%2&S9L(RP2RRNhp J̳,48D8P&PI0zhD S00dS M $Ry%2P̠XPI)>S%də%:C)'(Rpfs'CС)C3 IB KD2e'CrPB(fILœ8P3D,"B!IB&R|I),̤H0 3C'L ,œ8S0 ,"zIB$%39I)Nhr)C%2ФI%dP$Γ4&De)I(s3%2iɔ43!Be"&s9B!HS9BRe$‡ S$!$Pg0 $@D392!PSrS9C9BRg0D%$fO’hP@))9CHD$@,)C$@"(s%fd3)2œ!œg)Re&ffDS&(Rf,9B42S%2PIBdBdBe%2S%2S33">&I4…&f*"39a)C)2 RPL "rp L&Rd@g(s2pfp%)'"9C9!C,e!hg>y(XRRD%32P)D9i"%&!B… JfPs9))% %$C38S(JC@9LafJd B!2Д9LBs?C$I"NOgC8R d%2 s2D9 IȁD<%(K&IL̤'32eJd),(y4(Jr9‡$L2~s2S$C9D)2 L)pg%0NffM0 r|2PhRpSfPC2t3%&HM$Rs'(Nffr<̔D32PNdB3S' IHD93%'L)9C% JC)RfS'ϜO̞eRPfPIC333'Bt'&i"(P)()39.i>hg>I&S (JfrrJPRJ% RD3NBBs&S&J" D%0hPаrr&S3d(r)I s<fdI̡9= CILLCO)-q9C !L3%9IpRg9L @d@`J2 2S0JfPAaC99L)&r@ɅY(Re'C9d(S&Pp pIIL"d"dL,̤a.II(r?S LM L fRJpСP B Rg8S&R~XRP(s Nr=&):N>| BOP&r49C4))(RePBe geg8Sr%X JfdaJI9C'&hRf4e3 J)2hpJ} C&Pe0O&pC2y)RO PaI̖g3%!3%PC2redRRS39'3̤r)2fJJHIB0S%gIII%t(Ne%P$BP2Re&S2):RNe0y"C)% s(g pfe L3 $)%&&yJ2rRO$&PgBy)hr"̦g)2΅2P Re%XPЈ rg?)ȁfdBPJ332r p)"'&zM(gJPP(H@yCC99I(RȐS&gϜOIB!"8D4!<))‡L2S33$Bs29P @)2Pg(e$Bs&S J)3By4)(p @hfrxg?d )a$ rfrg!OsfPP̡(D3% fRg330JdIC392BdRDpCIB!“))(r)S$…2PСrg$JfrhRPСI%PB!:<(fR!a@(g:)ɔ9Ȅ%RPiIBJ ɔ)0JL LLS2z8t% x| h <ə)% BB)NfaB8Re39B%%%P󙓡"%3Сg4(g&prffOe$2e$,)" 9L%e9))dON % Ü$ RRr9BRg)I<I9BXP"JrPLaaBœ Ñ ϔ"L3hRs9"L"d29 RNr933&Rg(g )‡xd% fs(Ra&yC!2sg4(S%0%rRL(RgCS)Bt ̡!ž99BPPœIBdLD2S=)(fa)&R8Js9I99Ȅ"(gI!@0K3̑ BHD%9ffO JJILB')t2xs)!I23| Rs $ LC4'd&h„I%HNs9,)(S%3D&yNzaJe <,IC'$ 9BtП))8həB(d2pNPg J\32Ps aJILgd&rs2S3%%)0$&)(Rae LdIfr3ILdP"C<39C30C39PФRM3B )8g ''I(stɡByP2S& RP%8Y8Rt'L))Y垇>P?4aCɑ )IB<)"hh% I2e!™9&S2D2r}'C9 ̦Ba%&s2D Nd'(s3339L)3Lɤ"g)2=RRS' JJ)?d@H`I)9B!ɜ)2DD9 ̡ϡL9)4 !(Re0P d!Nr9aȄxg>S% (Rd@:I,"Iϔ'BC8| J92y NfffpaC)(Re3̅ dICJy4!3fJs3Be$™)BBM3(P rJ!BYN!& &s9Iy)<)HD9ɳ2S'IB Rs%(rPLCC,PNNhS'2D J i(Y33% "( BaJB!I40ɔC9Άe2yP 2HD932XD9Ù@)Be&&i%2y(pNLB'Ù2ÔyN~P)4)9̑ e2Pd(ffdLB9g32pNNg2D&D&D'Y$I%ffd LL…Yg(fd02S%39S%%3 J,)2(RfP/CBP(&RLIB)hP0(sL(rRL9IC339z%e$̙P)œΆJI3% C@r!Nf)!™)L)(Rs%%2S2Ps)2C3 JJ(s‡3&RJfffJa= Iœ?4 LJRJ93(p'0gs)%% rrLФdfyB LffpJdC&sCP J333̔)@ɜ dLɇ9“)(r% 2DxRpM3IA2PICC4(XP%S'0СLLI3"LdM'd҄ȄHr34,"8S39C“(g%fS%!)fe ̑ )H|I@faaNg(d"I4'C JJr\`A C3NPPФ&s3 &C8g3$@,(hSI9$L'BNfOIB8S3 Ls9̑ I9P̟42)s0: 9 Y%3&&PP%)9,2pJ%9) (rffg)2‡3@ Bd= 4)):J &&s2Lœ"'38S39@LL)2ffPJJ"(PФ"% Bɔ3&t% JOIC2hs(e!󔙙2&''BJafd2fS% C9L(adS&P΀kryPPr%&RJdffH‡ g drR &p(D&S33(4&sC’% IRPr0LP) 9'3%8SB'̤(he3 d̡…8r!2g PCBYBP$9Rf%3 @3 I(hhXS(p% ‡r rBPJHIfiBP$)3C33% Rr,)™IaN2g̡̦g(rrrfdRSSfaL0)rS3)I)339fJdg,(LC…!J>Rafe&D NRg)02ȇ C9BRP"dS&RfȆr0d(POee By% C9)2'%9gI)BPJ%P)'Y9ȆJr23")BRg>N%fs%PSC py"!9''C$@))'9,Xzs>e$!S$@ (fPI)(pRfCRL’%4 rOBdH~XD &ffJ!2S3333 paBC…%  afP(pdpL L)(P fd™>S&r2%&fRLIBœg(rL8S‡2&P)=PS fxYLOaeJ9BD ϟ<3(S3% ϙI„X|L92S%0硞e0Jd(|"%(,(D99IIp ̦JfJHI†J 0 g PIL)9)C8D% NP D9)S'%2S dIC3% )Nhr s:CS% % BJJrD9(d ɤD O(ffaL)(y(rdfdJIICaI3<3̑ ))% 䦀|:J"LY&PC)9?)RB3>S(ry(D8D)9):!BS=% dȁII@)3@0`IPzJH3L9C')CB!B΅8S<(s dgRe'dI"C!$I9dIL4s)&fD, 2d’@L40LIL9CɦJJffJfD&RY!’!9@IL)8P&g3&e LaL<9ICL73IC(Rg)Be ОIB| LRXr!!3$g?39s%2RrRar%2S%2S&)2 9dJJ(II3338S2e32&P99932SRDs dJp 33rBPdJJOdB(S33 Rs3)(RNP338SI )(s% IC2r=!ILg= yB@ œ8YCC 8D% fH)=% DP)(AaLC(RrP"LB!C9BhOC&RJd$g JJINLLIL̤"ddJB)RJI̤39dJ%?gC%9B(SRPIL3I"L"L2fpRaL)3z9fNLRP9ILɡ) B’(PhRs$Bri:Jxy)(sB dg= ɜ&P"S!|!B$^S NH?СCLP̔D,&h“(dRSi)PJJJa JO 2PJg(rfJfH!f9̔Ú) C9(S'(D&RPΒ994IB™"))IPB32S$Be)(r Je"9L38D(s̤&B&Ng Jae CC%%332@LIIIL)?)C dS39Nt(Rdə@ ?)3BPfL&e0NaI)),(rfaaȁaM a䔓9ILB94(J}92S)(Rs%2i(PP& )ffOCs0IrPI>rf|JHD,)L(rJa(PS p pe 9BPȆJ!3>g(J!NIL, C pC9@ 0O(y)")@9LLCIHP LPNB L(fdLg)) fp L3%C4L9)8Pha')=(d>RP4)(IfS3'92D2Rr2gIRO3(dd sL)% ϡS3BPPP”'2P"p"t3@ɡ)8939!D2i0NstfRe O=f  NRgC932PNJd))Bs%330J)3)sM 9(RfPP3()&$&|IILdfLЈp )9%02P))(SaL"L# 8rp0g0…L9@)XP4?)s9It9(d(&KIB(Pp2er@Άs INz)0 ffd)@P`P J)ar9IB3fd!',&DBs42 >L8S3Le"d̡(D3&P)$)hPaNL"9JLfJB,,24)$2ÙP)2Ϥ4(g)2PNP0a<3>g2Y&B 9fe ̙IBRfLrI2(P)",) N,2(S'0'))%$32P% LIȆJP8XD%J|)NH?Rx$a3I"(s3( @he3'C9)9B?@fd@()?ФfÅ 4 (g&e! Ls$(g(se&XXRD0hOȆJRP p sB&gȄ ϡCBP3)̳I9ddJdI(y(r(sCI 0adsJ&fsNP3ϔɔ’ X3)(!CI)”Ô'CS'OfaI2ffrRNPP,C% 'SNryIÄC'&3D hdrg(s LI)C3d2Jd"dRP9̔>g̡̤C)2C9ICIJICIB™9CI LBfIB!3OJdС')3)P9 !HP&r?I9JfL̚aIBpL39D B8D8S&bJNS&dNadP(Y3%,?30Ls)Raaf ))>Pg̡ RPNdB)(e&  T' N̔&RNddH Jp)š32垆P2s39S 2(pJP)))@™8D d,)Bs=fS3dIϙI'% JP?-qLФa?"dI9@28e2I$C%hJ(`t(fNd29@29Li= Cg9IBt'( B$IfJNe0œLI2s2~RPfJaIB9CRs3 dȄ$ᔒPɔ8R| 334 d,dϡ“2 s9PФr>0СB8fP<JfPM B XS%%zIePI)8Re0"% %332dJJ39$S')HP# % d(d @|L)(g% LRCg 2Ф!e4fJ,"2 C@,I@O PB(rft(Jhg=S%3% I3r)9(Iffe&XPO™94''(rIs?8D9̤̔&LJfM &D38PICɈ Na S2P IIg"(e L|I%L&L 4ϙ)&p2&e0 !B))PK0JJR"̤hC))|)&R&C$@)”9C3&Rr d"9"2XP9@$'3唔 )2(J| C 9C'HS&s3PdJa2S%PP%0 3) )g)332S%333(fs )2Y|Ʌ%0 "9@JLs9)!C9ɡI ILϞO B$(g2$$J2yСC)" >D JLrp)S%3%(g&fg2HJ9I0fJ:9Bg 2fLP32RP'ɤ(D̡CIФJ2PP9@ zM39CIp/ sBfLJdLa)$$M))))>IRr!(Re LNP3̡'0g0Jg2~S)% NaaC)Ne%JB)(g?)(2P4(e&RiB,"9RO%d"9LS!T(hLLP9)&fr: 8LP&R 2|)P2œ)3$B|,fPfyIaNz"8~S'):I3I4p"C%II>S'D4 C4='2%Pfg B…3I4aB!L̔932r>t0"B O %3 ̑ ̔NLaL)™ReLßȆNpd39I(pNaȁ̔39C<(X9NpdBJL"BHP,(@2RP,4)"" ) ɑ )Ls9)΁NyCIB9>Y)))(sCdS!D% (r=䤡2™)9P J' ,e JB!4%C2e 9" d(RPrfa)2Be釆RO%2irLɜ9Cɉ!y(r&zY% 9B&P B$8S3IC'L")32L9̡99IIIBI)(Rg40reg)02rffB!(S J9!"%PsPNLd s3)39B24 I|4<9B|fRJddMeLBPJp'&ffg%(ad fs")e!Chd!?)32)%$2JP)C&X(P hRe2XD9(pI“949C2~D8PNLpRiaC)9R ̡†g>p(f`y,"09LXPO)L9C)'IB’!(Re@" &r2fs̤4)28S3% Ns9$C' d s)2S4 hNP&)3g JHaL2!''2S3 &R S% dNkp JfB (JL™)2g30d)C8SLɔB99CBS%)i!@II%%%$C'3$B,B&fPyɤ4)2!S$BS$Be'It'C8D2SCL)C@t(g4ɥ J)")8S)0ze$:9B…& ~3C32S0J JCS' PȒHa  Jt')&PBBpO333 sI(p pde ?)(J99(RL43BJL,"C3% L%9™48D8|L"d RDL32e$BPg0e B)!2 B s&ddIsLIJ"IHNfJ9d 9I(ryL̔)9I@ t RINL9!…38S… ffg PJ(P pxrdae %&S Ld2e IIL(ffg S9IC)™2 sg)2)?ÙJPsCI!̜D(s)aL)(XS2L8S̑ .afhS'D%dIL$C$ 4™6af hPrfdC $:L̜)L3)RO%332S% IB))&b9):OfJBJHS%(s"@4 J̔ JC<2xg3)()r?(XC)'9,(D )Ά(O33332S0NJd NRNfdϡRP N !a)&P))>(e&S HIB))"%%0dA&'"'&RS39…M "%'L$IB2,f)CMg2!f̔9N4"38YI̡IL3(,P !8D2s LСI3,9"% a"ny C@e*YTԩ*jRE*YR*DKRҪ,JZ*iJZ-IU-JRVZYqjK,,R)TJKK*VTeJjR*Jh.-YeeEJ,Zԥ%,I-(R҉+**RT),-*i%UJiieeJʕ+Qk)-JYJ*UYT,J&RYiK-%Q,jI\e%,JZJIZRY*˒Y1rJVXETKQrJYY1Ye*URR*RʋTZ,ťRVRYRʥ,&.*XIJ(QKY*ZRZQ2ʕ%TJ-IKTҖYTQjJU%Z.YTYRRdʒUJRbqKR))YQ2ҩ*)IK,)H,%,))eK*eQJ*K,)Rʉ-*%,*T,JKJԥ%j+Y-d%ԖZT\Z\JRZUK$eb)RVJr,Yi)e*JRYRX䥤%K-,%JZdIJU*R%.&T-)J)EK*YeIJ-Qb-,TZUVITJZJRRJ,K)TJTUV)R)JR)R)JTJRT҉JRҤiJTLJTTLM--RLIIK-JQTIrjJJK*YJT)i-IR)jJZYqe*QRRjRʒZYRҲ%)jKRZ-)jQrTYR)Iie)VT-J&TT(%ITYIiV)I12XQjQjIjJZYR*TEIT8*RT)JT\LVZL,)rE+%&K-,TTYRԩiRҕ-**TT*).IZ-heJe)QKJde)JR%-)R).R\勔TL\ZJZRʔJU%ԪUJ)iZVYR-*RJU-)R-%)IM$RҪZTL奩JJ\*R,5YRR)iKJjJjRJU&*RTbk)dIe-IqeEKKR%,)QjJJU)RZZJY.YqUUV(d2ie)jJK*VZ*)JReKRKJT%+&*Z-J.)j-,J,ZYrR,iDRK-&&R+JTKERZʖTZV\Z*RVTJR\JJYK*&*RԕUKRRieRԔL)JZYie%iK-JRTK*-IjKTiUUeDʒUU$-eDʔqe)Rʥ%VIXbTť*IRʕU,(*vQ&-T)R)IhdKJZ&ZR%%)JR-%JTZb䔘JL&R-QjYieJ*-%R&T*ԖL+-)UZViVTғM(Rʋ,*,M)QiR&&RUU-E-$eBee&-,,)jR,Z,)RJbYRYJRU)%,E-,iV*ZXҪIJZT$-RZ-,)YQ2Q40EJ)-JRʔJ#),%-,Ek*UJ*IRZRԤ%&-,M*RJ*KKK+)TTe-E*R*JRK*JTTZʒYe*,UReJR)RҖ2U%iijQijKTX,JR-Qj)RV,-)LTRIKRUZRJRR**Q4e$KIk$IKIi)i*)K*RԕKYJT2)JYIj,)*QiK)RKRRJ&.JT,ijJ,UeK%*YjQrJT%JU,ŕ+*Y,VRZ*iJ),%ETUE)*Ԓ*ieRTTQ4d)TKVZRJZ*,ZZKRK+-J*T)IjRVRbԩDKQjʉKT%*JRKJ2Y2DҖK(y././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test/data/no-tags.mp30000644000175000017500000003370200000000000020556 0ustar00christianchristian00000000000000ID3#dXing(/ !!!''///55;;;BBHHNNNSSSYY__eeejjjppvv}}}ZLAME3.99r5 $|M/Dx `$HځGPqRE^q!db?8Å~$ `\ÖgY$?:~Ae3yiTהZYMYw7X޿.^T`"VW&̷$Xf{?sU_B21Gʵ/җW̽4")r} 2jwv]DTړYXҥַv+Xf>Vu)q =M1RF^'g 9QYNһ؏3+V̻m2JvE) B-6}&cP#E2-nO[YhףZipD'~7DؒF@""H!tfk2BمDZUI(8҈&->IUQTG\җ۪>GKrs>ۮg1߇i&(n0l`{*lBՑF"׏bXF6Lf{[^W08H{"179*fS .ZiSc9ޫW{ualAIebO9I:%=!Ji |bX`H2l[%{KpD}7C/FH@ U5U#Nc]3[MP7lȡLy0!? JR#볹>vM5c SQK̕-EEub"-8U`CTZ9ȉ򱘎VTILgC$/X7~rXɥHZ=1I!g 2C4˻}Gs1Y(3%&DCY@4i!{K@3zRct )CЈCUDFrNj?!縗`DK~E79ȳ&@ H^d!ўd<ɚw:K2kybYMj* QɄTa>{D"1NrhYގ|kZiᆪ&Y J=2$@&4{>|TA8P"[=3SjIVZP}h)\r+C1ur,7LOplB1 .O2f=QsFїZDT~D7G︣FI@ ? "Jd;M9e.vzT0R̗3XS]<|RJdp!IgJ2L#j}Uv;-jAhdDbLOp>:P]4ќ$NgBE ̄蹊}SwBòɗ fr*iP.U2@my5K]T%K_jTzN[+NξsE 8sӠ/GN~ܻjPf # r$pDui X>c#pDe~D7QȂIH ?6?"'{MMb c3蓫:޿UT+)\tH):ݞv=ȶF䭪%Sޥ+4ϚΨʬ=TΉg֣1e"#D6HÂH"[6V%Q+mc3jV3\J6e?I4%L=*VҠG-;޶Vo΢)+׮%RԄc63hEHUĈ$B6^XwZf`D2|7CoFE*` ^`4eL[-3"/R*6$F(rLgޚHFs:}=xe5o'2lfbP yN2:QEgB3QmolWbtq@))1%sR5wDfS!̶LvJ*]űO9RR k=AXA R0̓*[!S$DwdB[ܦpDY~D7F/ȒFE]*` ^`>bK:PPl( d >JB#-\1e+kڈ2;c!F4j4lL> E8UN~eWt%J~K;ӂT-YݞlBP+G;#G+"?~5&U7wF*F2B*/J]i-qFD3ZO 5qا1mrF#ΥB]N:~L·U@Ob89zᮄڙ`DiI;3C E@ܴdhG˫dj$? t}lNJ$Ȏap\gl^i.D+.F,Wл^Pj`Dj3R+"nr*梽 B@u{ߑmYQ*(/:)M BeHchgÉ$c_tG)X_˺kjE d"-F"`Di~7;)3b&`~3r;VlwYks#EL0ʢv{F0Txsg!HJ^dn*.ҟ EB;3:b:l2F="f1BH_^fzUÙ^N+Fֆ_+eԊq d"QXm,p'lAI)e!__oxq݋˒Gfx P`De< #b,`^ 4$=M.lWf_?f+5摐`n!?C,@jD+D$dH*cވ-|]K EbwRıuF4F.f;sAMg%UgwEb+ )_׾C`+,@jfHj@J),"PXig驹EloSX-GPGb~`DeȘ(6Cb&` ^4Jz]>0, 6o[ `U-S jO+GS^lzV}-]SۥWVʧt8"Hf*)Ol|OXҔ[§$hKe:Li BxK'8(EfP 6MeY`'jCneRm>QV)(fSE$d>:Ic+`Dgɘ=)"Q& ^ RnWTd{ VDzz?2'nmkYv:9Y9aeVҦ0G)G%Dri`h|1d 9 i6x &:϶ϔutPhJ>vկe kȜ1ba-ȳs M +s!ˁ:bvPi#g鐹6go[:!uk1]*}7W`DeI9-#b)&` ^% O\.W8ib(}:4(L; u2H@#*-O`gTz(⳵[IќLbJӌmߥwOӳ X:E*̌/uV`yCZ,KYČgINw%5&V b<`9ء yd-OFZ"ܧY+ 0?{GB[kuaz= 70U8ѷ`DgI; b"`~`3S 6Rw,P(/E?o? ޢa([AΥ5;A;s^3:ɛ'#nFKđZV7<mkdg(hi&tg3dm2 MS[YM:D_~Y#.@Je"؏S#wUTVX60(;a2q^de\ǯJئ2H`Dgɘ?- #e$ ^޴dLĘe@hi1a!d_"tDᏺt/SepykJ1y =N2oUJf=Ͽb52!FÅ8%lN >NJ+TtrFt9QD抋´BiaǓ;G>E5K,:/K :ʕ+5klGI0aݔi(6<{z9S 7"DP} 1{#~<bԁb^ȹ=֩pDgȘ>m)#b"`o!d !TD<9C]JM.VRl%l5--.PT[ έkkO=NJHP̿U,߾]B9.ϒMٟ|[;YʇCbpD!sȘ@)b-$` ^4$Ե%|Έ$A2vlԢm}|TC`'s:IU)Q)15s$D9vCh u[y#RZ"$[n+䪛1![߼ h!&u1\mj\TPSIH' *leA[>~veooerWWT"cfP%Oc#X3j.}&72ֱ5DC1w|IhG*S{x@^`D`D##$` ^46l9y5A`HY׷K9sRk /Qd0tlR%D9Ԗ,4%?zǒfRU gAS_oM:*aq1od4ⴐ=G2@ E@MA lpe!(r#izP+o*=V<Hj؃3"1jE (pDGgH:#bM&` ^"$Qfl̘Sm[縗ʪ(yzTK+`מ_zﱮ_ꝩI  0c}x;C6 0SBg $i֝χ#N ;Q@rHU2J̼)M0mvE3䴿?s+hۿ__H\'lYw]E $cpz <#Tc rQ@xMj=?tOuy*lҿ`Dhɘ:et"`o0ҫ:,d`=kX6p>H}080b1{L$bn !by q0DN@eRS괪)RN]Zej3Mc%/@ 2GD*#_5ZDz lQ VPTb.grd„2P$U~/ڋzBBvN CspDcHB# `~) $L ܭ7l*>9OF GjRD4UąΔsF%޴ 1N[?7ҥeC;'duf*+L໖ ƅRK 4 Nܓ#N^^=QW[5MIPe zOqYTQ@իaŽPP%lwz$载ʚU-ñ Pcoڑta%2I% \nĺV, "B`b唵U-d <@`D Ș=- b͙(`o JIC>*,) m<;(Ӽfm@SyNy+.>iƹyC.NTh| YZD7ҷ )*N(ŏddgT9-™jm4T XM$m"kZ] JȌsЄW9LpT 2cXFj_Jr̬b+:15 WP.C[\^^$ppDhI:bџ$` ^L śtĘUGm"MrgM?;S}6wtSU+`5Ra eZ]H̎24U#CzdFfz'uNwfDed)_;cysf!#u#P2ZO5j "71LpآuZ,<8X<y\a'< Ia)i:Z18QW AYS%?P/~,VI>sܸI5kczr@A0jYpDFH7C5"` a?$Ԛ{A@׾S~ɝ*w`υP(O)4f֦ VGe* ? :d|T%.;Q\@tXz3(WcJʇ\zJ4= !ukoad?ĴKP_-,x u=ee␁A8* 8܅&̴0p!>?"+Kg; 3 n#xĪG$ a _\ bpGi]۶[atEu-N GEƐK`B2qLœ-UH)^<~П{\Ip0-ӖfW)zءBypDhHA#]$` !4d  1!bEW KIERZd_ELi~ii bK6wUtc6ȾsR*h 1)UO;0Gei +;oS7ؚHa'x#3A{K -8O !Dbs0D⣑]aay 򵌛דO C9 350v gm$,IX,II%4ql˦А̷~WOn+GM-gs:\8HiG;s$% uL|XE4;_~ƈiSC`DhIG# $`o3$Z(U $M*mmi{n682pNjm}MzQǡBc (AdCpQJ0VnkY՝X*xG/sV4\vHн!eUQR2mCUpO*PAm@ft:h, ~"R:rY#P(rV6ԽRpDIA3b&` ^$L /RR7YHcrYjD8m3eJPP[&m!rāLAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.99.5UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUpDhH@ # `~!3$ UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUdݏ 4UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/test/test_albumid.py0000644000175000017500000001220000000000000020670 0ustar00christianchristian00000000000000import os.path import unittest import mutagen from mutagen.id3 import ID3FileType import rgain3.albumid DATA_PATH = os.path.join(os.path.dirname(__file__), "data") # Of the basic functions, we only test one because they're all very similar. class TestGetAlbum(unittest.TestCase): def test_no_tags_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "no-tags.flac")) self.assertEqual(rgain3.albumid.get_album(tags), None) def test_no_tags_mp3(self): tags = ID3FileType(os.path.join(DATA_PATH, "no-tags.mp3")) self.assertEqual(rgain3.albumid.get_album(tags), None) def test_album_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "album-tag.flac")) self.assertEqual(rgain3.albumid.get_album(tags), "Test Album") def test_album_mp3(self): tags = ID3FileType(os.path.join(DATA_PATH, "album-tag.mp3")) self.assertEqual(rgain3.albumid.get_album(tags), "Test Album") class TestGetMBAlbumID_MP3(unittest.TestCase): def test_no_tags(self): tags = ID3FileType(os.path.join(DATA_PATH, "no-tags.mp3")) self.assertEqual(rgain3.albumid.get_musicbrainz_album_id(tags), None) def test_album_id_form1(self): tags = ID3FileType(os.path.join(DATA_PATH, "mb-album-id-form1.mp3")) self.assertEqual(rgain3.albumid.get_musicbrainz_album_id(tags), "TXXX:MusicBrainz Album Id") def test_album_id_form2(self): tags = ID3FileType(os.path.join(DATA_PATH, "mb-album-id-form2.mp3")) self.assertEqual(rgain3.albumid.get_musicbrainz_album_id(tags), "TXXX:MUSICBRAINZ_ALBUMID") class TestGetAlbumArtist(unittest.TestCase): def test_no_tags_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "no-tags.flac")) self.assertEqual(rgain3.albumid.get_albumartist(tags), None) def test_no_tags_mp3(self): tags = ID3FileType(os.path.join(DATA_PATH, "no-tags.mp3")) self.assertEqual(rgain3.albumid.get_albumartist(tags), None) def test_albumartist_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "albumartist.flac")) self.assertEqual(rgain3.albumid.get_albumartist(tags), "Test Album Artist") def _mp3_test(self, suffix): tags = ID3FileType( os.path.join(DATA_PATH, "albumartist-%s.mp3" % suffix)) self.assertEqual(rgain3.albumid.get_albumartist(tags), "Test Album Artist - %s" % suffix) def test_albumartist_mp3_TPE2(self): self._mp3_test("TPE2") def test_albumartist_mp3_TXXX_albumartist(self): self._mp3_test("TXXX_albumartist") def test_albumartist_mp3_TXXX_QL_albumartist(self): self._mp3_test("TXXX_QL_albumartist") def test_albumartist_mp3_TXXX_ALBUM_ARTIST(self): self._mp3_test("TXXX_ALBUM_ARTIST") class TestGetAlbumId(unittest.TestCase): def test_no_tags_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "no-tags.flac")) self.assertEqual(rgain3.albumid.get_album_id(tags), None) def test_no_tags_mp3(self): tags = ID3FileType(os.path.join(DATA_PATH, "no-tags.mp3")) self.assertEqual(rgain3.albumid.get_album_id(tags), None) def test_album_flac(self): tags = mutagen.File(os.path.join(DATA_PATH, "album-tag.flac")) self.assertEqual(rgain3.albumid.get_album_id(tags), "Test Album") def test_only_album_mp3(self): tags = ID3FileType(os.path.join(DATA_PATH, "album-tag.mp3")) self.assertEqual(rgain3.albumid.get_album_id(tags), "Test Album") def test_only_albumartist(self): tags = mutagen.File(os.path.join(DATA_PATH, "albumartist.flac")) self.assertEqual(rgain3.albumid.get_album_id(tags), None) def test_mb_album_id_only(self): tags = mutagen.File(os.path.join(DATA_PATH, "mb-album-id.flac")) self.assertEqual(rgain3.albumid.get_album_id(tags), "MB Album ID") def test_mb_album_id_and_more(self): tags = mutagen.File(os.path.join(DATA_PATH, "mb-album-id-and-more.flac")) self.assertEqual(rgain3.albumid.get_album_id(tags), "MB Album ID") def test_album_and_mb_albumartist(self): tags = ID3FileType( os.path.join(DATA_PATH, "album-and-mb-albumartist.mp3")) self.assertEqual(rgain3.albumid.get_album_id(tags), "MB Album Artist ID - Album Title") def test_album_and_albumartist(self): tags = ID3FileType( os.path.join(DATA_PATH, "album-and-albumartist.mp3")) self.assertEqual(rgain3.albumid.get_album_id(tags), "Album Artist - Album Title") def test_album_and_artist(self): tags = ID3FileType(os.path.join(DATA_PATH, "album-artist.mp3")) self.assertEqual(rgain3.albumid.get_album_id(tags), "Test Artist - Test Album") ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/test/test_rgain_init.py0000644000175000017500000000171500000000000021407 0ustar00christianchristian00000000000000import unittest from rgain3 import GainData, GainType class TestGainData(unittest.TestCase): def test_eq(self): gd1 = GainData(-5, 0.5, 80) gd2 = GainData(-5, 0.5, 80) self.assertTrue(gd1 == gd2) self.assertFalse(gd1 != gd2) def test_not_eq(self): gd1 = GainData(-5, 0.5, 80) gd2 = GainData(-5, 0.6, 80) self.assertTrue(gd1 != gd2) self.assertFalse(gd1 == gd2) def test_bad_type(self): gd1 = GainData(-5, 0.6, 89) gd2 = "not GainData" self.assertTrue(gd1 != gd2) self.assertFalse(gd1 == gd2) def test_eq_gain_type(self): gd1 = GainData(0, 0, 0, GainType.TP_TRACK) gd2 = GainData(0, 0, 0, GainType.TP_TRACK) gd3 = GainData(0, 0, 0, GainType.TP_ALBUM) gd4 = GainData(0, 0, 0) self.assertEqual(gd1, gd2) self.assertNotEqual(gd1, gd3) self.assertNotEqual(gd1, gd4) self.assertNotEqual(gd3, gd4) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/test/test_rgcalc.py0000644000175000017500000000575600000000000020530 0ustar00christianchristian00000000000000import os.path import unittest import gi gi.require_version("Gst", "1.0") from gi.repository import GLib, GObject, Gst # noqa isort:skip from rgain3 import GainType, rgcalc, util # noqa isort:skip Gst.init([]) DATA_PATH = os.path.join(os.path.dirname(__file__), "data") class TestReplayGain(unittest.TestCase): def test_no_files(self): with self.assertRaises(ValueError): rgcalc.calculate([]) def test_silence(self): f = os.path.join(DATA_PATH, "no-tags.flac") t, a = rgcalc.calculate([f]) # Gain and peak determined experimentally for this file. self.assertAlmostEqual(a.gain, 64.82, 5) self.assertAlmostEqual(a.peak, 0.000244, 5) self.assertEqual(a.ref_level, 89) self.assertEqual(a.gain_type, GainType.TP_ALBUM) self.assertEqual(len(t), 1) for k in t: self.assertEqual(k, f) gain = t[k] self.assertAlmostEqual(gain.gain, 64.82, 5) self.assertAlmostEqual(gain.peak, 0.000244, 5) self.assertEqual(gain.ref_level, 89) self.assertEqual(gain.gain_type, GainType.TP_TRACK) def test_custom_ref_level(self): f = os.path.join(DATA_PATH, "no-tags.flac") t, a = rgcalc.calculate([f], ref_lvl=105) self.assertAlmostEqual(a.gain, 80.82, 5) self.assertAlmostEqual(a.peak, 0.000244, 5) self.assertEqual(a.ref_level, 105) self.assertEqual(a.gain_type, GainType.TP_ALBUM) self.assertEqual(len(t), 1) for k in t: self.assertEqual(k, f) gain = t[k] self.assertAlmostEqual(gain.gain, 80.82, 5) self.assertAlmostEqual(gain.peak, 0.000244, 5) self.assertEqual(gain.ref_level, 105) self.assertEqual(gain.gain_type, GainType.TP_TRACK) def test_track_started_finished_signals(self): tracks = [os.path.join(DATA_PATH, "no-tags.flac"), os.path.join(DATA_PATH, "no-tags.mp3")] rg = rgcalc.ReplayGain(tracks) events = [] loop = GLib.MainLoop() def event(*args): """ Collect signals received from analysis. """ events.append(list(args)) def assert_not_called(*args): """ The test must not receive any error signals! """ loop.quit() print(args) assert False with util.gobject_signals( rg, ("error", assert_not_called), ("track-started", event), ("track-finished", event), ("all-finished", lambda *args: loop.quit())): rg.start() loop.run() self.assertEqual(len(events), 4) self.assertEqual(events[0], [rg, tracks[0]]) self.assertEqual(events[1], [rg, tracks[0], rg.track_data[tracks[0]]]) self.assertEqual(events[2], [rg, tracks[1]]) self.assertEqual(events[3], [rg, tracks[1], rg.track_data[tracks[1]]]) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/test/test_rgio.py0000644000175000017500000000200400000000000020214 0ustar00christianchristian00000000000000import os.path import unittest from pathlib import Path from rgain3.rgio import MP3TagReaderWriter DATA_PATH = Path(os.path.dirname(__file__)) / "data" class TestGetTagsObject(unittest.TestCase): def setUp(self): self.reader_writer = MP3TagReaderWriter() def test_no_headers_mp3(self): tags = self.reader_writer._get_tags_object( str(DATA_PATH / "missing-headers.mp3") ) self.assertEqual(tags.keys(), []) self.assertTrue(tags.filename.endswith("missing-headers.mp3")) def test_no_tags_mp3(self): tags = self.reader_writer._get_tags_object( str(DATA_PATH / "no-tags.mp3") ) self.assertEqual(tags.keys(), []) self.assertTrue(tags.filename.endswith("no-tags.mp3")) def test_album_mp3(self): tags = self.reader_writer._get_tags_object( str(DATA_PATH / "album-tag.mp3") ) self.assertEqual(tags.keys(), ["album"]) self.assertTrue(tags.filename.endswith("album-tag.mp3")) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070719.0 rgain3-1.1.1/test/test_util.py0000644000175000017500000000152000000000000020233 0ustar00christianchristian00000000000000import pytest from rgain3.util import parse_db, parse_peak @pytest.mark.parametrize("in_value,expected", [ ("invalid", None), ("", None), ("1", 1.0), ("1.0", 1.0), ("1 db", 1.0), ("1.0 DB", 1.0), ("1.0 dB", 1.0), ("1.0dB", 1.0), (" 1.0dB ", 1.0), # The value may also be of type bytes # https://github.com/chaudum/rgain3/issues/38 (b" 1.0dB ", 1.0), ]) def test_parse_db(in_value, expected): assert parse_db(in_value) == expected @pytest.mark.parametrize("in_value,expected", [ ("invalid", None), ("", None), ("1dB", None), ("1", 1.0), ("1.0", 1.0), (" 1.0 ", 1.0), # The value may also be of type bytes # https://github.com/chaudum/rgain3/issues/38 (b" 1.0 ", 1.0), ]) def test_parse_peak(in_value, expected): assert parse_peak(in_value) == expected ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605216162.0 rgain3-1.1.1/test-requirements.txt0000644000175000017500000000010600000000000021126 0ustar00christianchristian00000000000000pytest>=5.3,<6.0 pytest-cov>=2.8 pytest-flake8>=1.0 pytest-isort>=0.3 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1605217912.0 rgain3-1.1.1/tests.sh0000755000175000017500000000024200000000000016367 0ustar00christianchristian00000000000000#!/bin/bash -xe pip install -e . pytest -vvv -s --cache-clear find . -name __pycache__ -type d | xargs rm -rf rm -rf .pytest_cache/ .mypy_cache/ rgain.egg-info/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1627070679.0 rgain3-1.1.1/tox.ini0000644000175000017500000000071700000000000016210 0ustar00christianchristian00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. To use it, "pip install tox" # and then run "tox" from this directory. [tox] envlist = py35,py36,py37,py38,py39 [testenv] usedevelop = true setenv = LANG=C.UTF-8 commands = pytest --cache-clear {posargs} deps = -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt