├── Seeds ├── Monster-Music-Transformer-MI-Seed-1.mid ├── Monster-Music-Transformer-MI-Seed-2.mid ├── Monster-Music-Transformer-MI-Seed-3.mid ├── Monster-Music-Transformer-MI-Seed-4.mid ├── Monster-Music-Transformer-MI-Seed-5.mid ├── Monster-Music-Transformer-MI-Seed-6.mid ├── Monster-Music-Transformer-Piano-Seed-1.mid ├── Monster-Music-Transformer-Piano-Seed-2.mid ├── Monster-Music-Transformer-Piano-Seed-3.mid ├── Monster-Music-Transformer-Piano-Seed-4.mid ├── Monster-Music-Transformer-Piano-Seed-5.mid ├── Monster-Music-Transformer-Piano-Seed-6.mid └── README.md ├── Artwork ├── Logo │ ├── Monster-MIDI-Dataset-Logo (1).jpg │ ├── Monster-MIDI-Dataset-Logo (2).jpg │ ├── Monster-MIDI-Dataset-Logo (3).jpg │ ├── Monster-MIDI-Dataset-Logo (4).jpg │ ├── Monster-MIDI-Dataset-Logo (5).jpg │ ├── Monster-MIDI-Dataset-Logo (6).jpg │ ├── Monster-MIDI-Dataset-Logo (7).jpg │ ├── Monster-MIDI-Dataset-Logo (8).jpg │ └── README.md ├── MMT │ ├── Monster-Music-Transformer-Artwork (1).jpg │ ├── Monster-Music-Transformer-Artwork (2).jpg │ ├── Monster-Music-Transformer-Artwork (3).jpg │ ├── Monster-Music-Transformer-Artwork (4).jpg │ ├── Monster-Music-Transformer-Artwork (5).jpg │ ├── Monster-Music-Transformer-Artwork (6).jpg │ ├── Monster-Music-Transformer-Artwork (7).jpg │ ├── Monster-Music-Transformer-Artwork (8).jpg │ ├── Monster-Music-Transformer-Artwork (9).jpg │ ├── Monster-Music-Transformer-Artwork (10).jpg │ ├── Monster-Music-Transformer-Artwork (11).jpg │ └── README.md ├── Monster-MIDI-Dataset-Concept-Artwork (1).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (10).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (11).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (12).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (2).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (3).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (4).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (5).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (6).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (7).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (8).jpg ├── Monster-MIDI-Dataset-Concept-Artwork (9).jpg └── README.md ├── README.md ├── LICENSE ├── monster_music_transformer.py ├── monster_midi_dataset_gpu_search_and_filter.py ├── Monster_Music_Transformer.ipynb └── Monster_MIDI_Dataset_GPU_Search_and_Filter.ipynb /Seeds/Monster-Music-Transformer-MI-Seed-1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-1.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-MI-Seed-2.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-2.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-MI-Seed-3.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-3.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-MI-Seed-4.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-4.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-MI-Seed-5.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-5.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-MI-Seed-6.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-MI-Seed-6.mid -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (1).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (2).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (2).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (3).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (3).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (4).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (4).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (5).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (5).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (6).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (6).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (7).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (7).jpg -------------------------------------------------------------------------------- /Artwork/Logo/Monster-MIDI-Dataset-Logo (8).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Logo/Monster-MIDI-Dataset-Logo (8).jpg -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-1.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-2.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-2.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-3.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-3.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-4.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-4.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-5.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-5.mid -------------------------------------------------------------------------------- /Seeds/Monster-Music-Transformer-Piano-Seed-6.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Seeds/Monster-Music-Transformer-Piano-Seed-6.mid -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (1).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (2).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (2).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (3).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (3).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (4).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (4).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (5).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (5).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (6).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (6).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (7).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (7).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (8).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (8).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (9).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (9).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (1).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (10).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (10).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (11).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (11).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (12).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (12).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (2).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (2).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (3).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (3).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (4).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (4).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (5).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (5).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (6).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (6).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (7).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (7).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (8).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (8).jpg -------------------------------------------------------------------------------- /Artwork/Monster-MIDI-Dataset-Concept-Artwork (9).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/Monster-MIDI-Dataset-Concept-Artwork (9).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (10).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (10).jpg -------------------------------------------------------------------------------- /Artwork/MMT/Monster-Music-Transformer-Artwork (11).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/Monster-MIDI-Dataset/main/Artwork/MMT/Monster-Music-Transformer-Artwork (11).jpg -------------------------------------------------------------------------------- /Artwork/Logo/README.md: -------------------------------------------------------------------------------- 1 | # Monster MIDI Dataset Logo Artwork 2 | 3 | ## Artwork was created with Stable Diffusion XL 4 | 5 | *** 6 | 7 | ### Project Los Angeles 8 | ### Tegridy Code 2024 9 | -------------------------------------------------------------------------------- /Artwork/README.md: -------------------------------------------------------------------------------- 1 | # Monster MIDI Dataset Concept Artwork 2 | 3 | ## Artwork was created with Stable Diffusion XL 4 | 5 | *** 6 | 7 | ### Project Los Angeles 8 | ### Tegridy Code 2024 9 | -------------------------------------------------------------------------------- /Artwork/MMT/README.md: -------------------------------------------------------------------------------- 1 | # Monster Music Transformer Concept Artwwork 2 | 3 | ## Images were created with SDXL-Lightning 4 | 5 | *** 6 | 7 | ### Project Los Angeles 8 | ### Tegridy Code 2024 9 | -------------------------------------------------------------------------------- /Seeds/README.md: -------------------------------------------------------------------------------- 1 | # Monster MIDI Dataset Sample MIDIs 2 | 3 | *** 4 | 5 | ## These can be used with Monster MIDI Dataset GPU Search or with Monster Music Transformer Code/Colab 6 | 7 | *** 8 | 9 | ### Project Los Angeles 10 | ### Tegridy Code 2024 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monster MIDI Dataset 2 | ## Giant searchable raw MIDI dataset for MIR and Music AI purposes 3 | 4 | ![Monster-MIDI-Dataset-Logo (8)](https://github.com/asigalov61/Monster-MIDI-Dataset/assets/56325539/d5648673-97c1-40e3-ad57-c03c639592a3) 5 | 6 | *** 7 | 8 | ## Monster MIDI Dataset GPU Search and Filter 9 | 10 | ### [NEW] Monster GPU/CPU Search and Filter stand-alone Python module with improved matching 11 | 12 | #### Installation 13 | 14 | ##### Install requirements 15 | 16 | ```sh 17 | !git clone --depth 1 https://github.com/asigalov61/Monster-MIDI-Dataset 18 | 19 | !pip install cupy-cuda12x 20 | !pip install numpy==1.26.4 21 | !pip install huggingface_hub 22 | !pip install hf-transfer 23 | !pip install ipywidgets 24 | !pip install tqdm 25 | ``` 26 | 27 | ##### Import modules 28 | 29 | ```python 30 | import os 31 | os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1" 32 | 33 | from huggingface_hub import hf_hub_download 34 | 35 | %cd ./Monster-MIDI-Dataset 36 | import monster_search_and_filter 37 | %cd .. 38 | ``` 39 | 40 | ##### Download and unzip Monster MIDI dataset 41 | 42 | ```python 43 | hf_hub_download(repo_id='projectlosangeles/Monster-MIDI-Dataset', 44 | repo_type='dataset', 45 | filename='Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip', 46 | local_dir='./Monster-MIDI-Dataset/' 47 | ) 48 | ``` 49 | 50 | ```sh 51 | %cd ./Monster-MIDI-Dataset 52 | !unzip -o Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip > /dev/null 53 | %cd .. 54 | ``` 55 | 56 | ##### Run the search 57 | 58 | ```python 59 | sigs_data_path = './Monster-MIDI-Dataset/SIGNATURES_DATA/MONSTER_SIGNATURES_DATA.pickle' 60 | 61 | sigs_data = monster_search_and_filter.load_pickle(sigs_data_path) 62 | sigs_dicts = monster_search_and_filter.load_signatures(sigs_data) 63 | 64 | # Please note that you will need at least 80GB RAM or VRAM to run the search 65 | X, global_union = monster_search_and_filter.precompute_signatures(sigs_dicts) 66 | 67 | # IO dirs will be created on the first function run 68 | # Make sure to put your master MIDIs into created Master-MIDI-Dataset dir 69 | monster_search_and_filter.search_and_filter(sigs_dicts, X, global_union) 70 | ``` 71 | 72 | ### [LEGACY] 73 | 74 | [![Open In Colab][colab-badge]][colab-notebook1] 75 | 76 | [colab-notebook1]: 77 | [colab-badge]: 78 | 79 | ### Search, filter and explore Monster MIDI Dataset :) 80 | 81 | #### PLEASE NOTE: Google Colab Pro or Pro+ subscription/A100 GPU is required to use the provided colab/code because of the size of the dataset and its data files 82 | 83 | *** 84 | 85 | ## Monster MIDI Dataset Sample Search Results 86 | 87 | ### Here are the [Monster MIDI Dataset Sample Search Results](https://huggingface.co/datasets/projectlosangeles/Monster-MIDI-Dataset/blob/main/Monster_MIDI_Dataset_Search_Results_Ver_1_0_CC_BY_NC_SA.zip) 88 | 89 | ### It takes about one hour on A100 GPU to do a full search on 285 source MIDIs 90 | 91 | ### Please also check out [Quad Music Transformer](https://github.com/asigalov61/Quad-Music-Transformer) which was trained using these sample search results 92 | 93 | *** 94 | 95 | ## Monster Music Transformer 96 | 97 | ### Here is the large model trained on the full Monster MIDI Dataset to demo the dataset in action :) 98 | 99 | [![Open In Colab][colab-badge]][colab-notebook2] 100 | 101 | [colab-notebook2]: 102 | [colab-badge]: 103 | 104 | ### Model was trained on full Monster MIDI Dataset for 65 hours (1 epoch) @ 4 batches on a single H100 GPU 105 | ### This model can be used for music generation/composition or for (dataset) embeddings exploration 106 | 107 | *** 108 | 109 | ### Enjoy and please CC BY-NC-SA :) 110 | 111 | *** 112 | 113 | ### Project Los Angeles 114 | ### Tegridy Code 2025 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /monster_music_transformer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Monster_Music_Transformer.ipynb 3 | 4 | Automatically generated by Colaboratory. 5 | 6 | Original file is located at 7 | https://colab.research.google.com/drive/1_fs1W2cuXxiMKznQIP3wtUxSIbxt71Nk 8 | 9 | # Monster Music Transformer (ver. 1.0) 10 | 11 | *** 12 | 13 | Powered by tegridy-tools: https://github.com/asigalov61/tegridy-tools 14 | 15 | *** 16 | 17 | WARNING: This complete implementation is a functioning model of the Artificial Intelligence. Please excercise great humility, care, and respect. https://www.nscai.gov/ 18 | 19 | *** 20 | 21 | #### Project Los Angeles 22 | 23 | #### Tegridy Code 2024 24 | 25 | *** 26 | 27 | # (GPU CHECK) 28 | """ 29 | 30 | #@title NVIDIA GPU check 31 | !nvidia-smi 32 | 33 | """# (SETUP ENVIRONMENT)""" 34 | 35 | #@title Install dependencies 36 | !git clone --depth 1 https://github.com/asigalov61/Monster-MIDI-Dataset 37 | !pip install huggingface_hub 38 | !pip install einops 39 | !pip install torch-summary 40 | !apt install fluidsynth #Pip does not work for some reason. Only apt works 41 | 42 | # Commented out IPython magic to ensure Python compatibility. 43 | #@title Import modules 44 | 45 | print('=' * 70) 46 | print('Loading core Monster Music Transformer modules...') 47 | 48 | import os 49 | import copy 50 | import pickle 51 | import secrets 52 | import statistics 53 | from time import time 54 | import tqdm 55 | 56 | print('=' * 70) 57 | print('Loading main Monster Music Transformer modules...') 58 | import torch 59 | 60 | # %cd /content/Monster-MIDI-Dataset 61 | 62 | import TMIDIX 63 | 64 | from midi_to_colab_audio import midi_to_colab_audio 65 | 66 | from x_transformer_1_27_16 import * 67 | 68 | import random 69 | 70 | # %cd /content/ 71 | print('=' * 70) 72 | print('Loading aux Monster Music Transformer modules...') 73 | 74 | import matplotlib.pyplot as plt 75 | 76 | from torchsummary import summary 77 | from sklearn import metrics 78 | 79 | from IPython.display import Audio, display 80 | 81 | from huggingface_hub import hf_hub_download 82 | 83 | from google.colab import files 84 | 85 | print('=' * 70) 86 | print('Done!') 87 | print('Enjoy! :)') 88 | print('=' * 70) 89 | 90 | """# (LOAD MODEL)""" 91 | 92 | #@title Load Monster Music Transformer Pre-Trained Model 93 | 94 | #@markdown Choose model 95 | 96 | select_model_to_load = "651M-32L-Fast-Large" # @param ["651M-32L-Fast-Large"] 97 | 98 | #@markdown Model precision option 99 | 100 | model_precision = "bfloat16" # @param ["bfloat16", "float16"] 101 | 102 | #@markdown bfloat16 == Half precision/faster speed (if supported, otherwise the model will default to float16) 103 | 104 | #@markdown float16 == Full precision/fast speed 105 | 106 | plot_tokens_embeddings = "None" # @param ["None", "Start Times", "Durations Velocities", "Piano Pitches", "Drums Pitches", "Aux"] 107 | 108 | print('=' * 70) 109 | print('Loading Monster Music Transformer', select_model_to_load,'Pre-Trained Model...') 110 | print('Please wait...') 111 | print('=' * 70) 112 | 113 | full_path_to_models_dir = "/content/Monster-MIDI-Dataset/" 114 | 115 | if select_model_to_load == '651M-32L-Fast-Large': 116 | 117 | model_checkpoint_file_name = 'Monster_Music_Transformer_Large_Trained_Model_22501_steps_0.3419_loss_0.9121_acc.pth' 118 | model_path = full_path_to_models_dir+'/'+model_checkpoint_file_name 119 | num_layers = 36 120 | if os.path.isfile(model_path): 121 | print('Model already exists...') 122 | 123 | else: 124 | hf_hub_download(repo_id='asigalov61/Monster-Music-Transformer', 125 | filename=model_checkpoint_file_name, 126 | local_dir='/content/Monster-MIDI-Dataset', 127 | local_dir_use_symlinks=False) 128 | 129 | print('=' * 70) 130 | print('Instantiating model...') 131 | 132 | device_type = 'cuda' 133 | 134 | if model_precision == 'bfloat16' and torch.cuda.is_bf16_supported(): 135 | dtype = 'bfloat16' 136 | else: 137 | dtype = 'float16' 138 | 139 | if model_precision == 'float16': 140 | dtype = 'float16' 141 | 142 | ptdtype = {'float32': torch.float32, 'bfloat16': torch.bfloat16, 'float16': torch.float16}[dtype] 143 | ctx = torch.amp.autocast(device_type=device_type, dtype=ptdtype) 144 | 145 | SEQ_LEN = 8192 146 | 147 | # instantiate the model 148 | 149 | model = TransformerWrapper( 150 | num_tokens = 19080, 151 | max_seq_len = SEQ_LEN, 152 | attn_layers = Decoder(dim = 1024, depth = num_layers, heads = 32, attn_flash=True) 153 | ) 154 | 155 | model = AutoregressiveWrapper(model, ignore_index=19079) 156 | 157 | model.cuda() 158 | print('=' * 70) 159 | 160 | print('Loading model checkpoint...') 161 | 162 | model.load_state_dict(torch.load(model_path)) 163 | print('=' * 70) 164 | 165 | model.eval() 166 | 167 | print('Done!') 168 | print('=' * 70) 169 | 170 | print('Model will use', dtype, 'precision...') 171 | print('=' * 70) 172 | 173 | # Model stats 174 | print('Model summary...') 175 | summary(model) 176 | 177 | # Plot Token Embeddings 178 | if plot_tokens_embeddings != 'None': 179 | tok_emb = model.net.token_emb.emb.weight.detach().cpu().tolist() 180 | 181 | if plot_tokens_embeddings == 'Start Times': 182 | tok_range = [0, 256] 183 | 184 | elif plot_tokens_embeddings == 'Durations Velocities': 185 | tok_range = [256, 2304] 186 | 187 | elif plot_tokens_embeddings == 'Piano Pitches': 188 | tok_range = [2304, 2304+128] 189 | 190 | elif plot_tokens_embeddings == 'Drums Pitches': 191 | tok_range = [18945-128, 18945] 192 | 193 | elif plot_tokens_embeddings == 'Aux': 194 | tok_range = [18945, 19079] 195 | 196 | if plot_tokens_embeddings != 'None': 197 | 198 | tok_emb1 = [] 199 | 200 | for t in tok_emb[tok_range[0]:tok_range[1]]: 201 | tok_emb1.append(t) 202 | 203 | cos_sim = metrics.pairwise_distances( 204 | tok_emb1, metric='cosine' 205 | ) 206 | plt.figure(figsize=(7, 7)) 207 | plt.imshow(cos_sim, cmap="inferno", interpolation="nearest") 208 | im_ratio = cos_sim.shape[0] / cos_sim.shape[1] 209 | plt.colorbar(fraction=0.046 * im_ratio, pad=0.04) 210 | plt.xlabel("Position") 211 | plt.ylabel("Position") 212 | plt.tight_layout() 213 | plt.plot() 214 | plt.savefig("/content/Monster-Music-Transformer-Tokens-Embeddings-Plot.png", bbox_inches="tight") 215 | 216 | """# (GENERATE) 217 | 218 | # (IMPROV) 219 | """ 220 | 221 | #@title Standard Improv Generator 222 | 223 | #@markdown Improv type 224 | 225 | improv_type = "Random Freestyle" # @param ["Random Freestyle", "Freestyle without Drums", "Freestyle with Drums", "Custom"] 226 | 227 | #@markdown Custom Improv settings 228 | 229 | first_note_MIDI_patch_number = 0 # @param {type:"slider", min:0, max:128, step:1} 230 | add_drums = False #@param {type:"boolean"} 231 | 232 | #@markdown Generation settings 233 | 234 | number_of_tokens_tp_generate = 546 # @param {type:"slider", min:30, max:8190, step:3} 235 | number_of_batches_to_generate = 4 #@param {type:"slider", min:1, max:16, step:1} 236 | temperature = 0.9 # @param {type:"slider", min:0.1, max:1, step:0.05} 237 | 238 | #@markdown Other settings 239 | 240 | render_MIDI_to_audio = True # @param {type:"boolean"} 241 | 242 | print('=' * 70) 243 | print('Monster Music Transformer Standard Improv Model Generator') 244 | print('=' * 70) 245 | 246 | if improv_type == 'Random Freestyle': 247 | 248 | outy = [19077] 249 | 250 | if improv_type == 'Freestyle without Drums': 251 | 252 | outy = [19077, 18946] 253 | 254 | if improv_type == 'Freestyle with Drums': 255 | 256 | outy = [19077, 18947] 257 | 258 | if improv_type == 'Custom': 259 | 260 | if add_drums: 261 | drumsp = 18947 # Yes 262 | else: 263 | drumsp = 18946 # No 264 | 265 | outy = [19077, drumsp, 18948+first_note_MIDI_patch_number] 266 | 267 | print('Selected Improv sequence:') 268 | print(outy) 269 | print('=' * 70) 270 | 271 | torch.cuda.empty_cache() 272 | 273 | inp = [outy] * number_of_batches_to_generate 274 | 275 | inp = torch.LongTensor(inp).cuda() 276 | 277 | with ctx: 278 | out = model.generate(inp, 279 | number_of_tokens_tp_generate, 280 | temperature=temperature, 281 | return_prime=True, 282 | verbose=True) 283 | 284 | out0 = out.tolist() 285 | 286 | print('=' * 70) 287 | print('Done!') 288 | print('=' * 70) 289 | 290 | torch.cuda.empty_cache() 291 | 292 | #====================================================================== 293 | 294 | print('Rendering results...') 295 | 296 | for i in range(number_of_batches_to_generate): 297 | 298 | print('=' * 70) 299 | print('Batch #', i) 300 | print('=' * 70) 301 | 302 | out1 = out0[i] 303 | 304 | print('Sample INTs', out1[:12]) 305 | print('=' * 70) 306 | 307 | if len(out1) != 0: 308 | 309 | song = out1 310 | song_f = [] 311 | 312 | time = 0 313 | dur = 0 314 | vel = 90 315 | pitch = 0 316 | channel = 0 317 | 318 | patches = [-1] * 16 319 | 320 | channels = [0] * 16 321 | channels[9] = 1 322 | 323 | for ss in song: 324 | 325 | if 0 <= ss < 256: 326 | 327 | time += ss * 16 328 | 329 | if 256 <= ss < 2304: 330 | 331 | dur = ((ss-256) // 8) * 16 332 | vel = (((ss-256) % 8)+1) * 15 333 | 334 | if 2304 <= ss < 18945: 335 | 336 | patch = (ss-2304) // 129 337 | 338 | if patch < 128: 339 | 340 | if patch not in patches: 341 | if 0 in channels: 342 | cha = channels.index(0) 343 | channels[cha] = 1 344 | else: 345 | cha = 15 346 | 347 | patches[cha] = patch 348 | channel = patches.index(patch) 349 | else: 350 | channel = patches.index(patch) 351 | 352 | if patch == 128: 353 | channel = 9 354 | 355 | pitch = (ss-2304) % 129 356 | 357 | song_f.append(['note', time, dur, channel, pitch, vel, patch ]) 358 | 359 | patches = [0 if x==-1 else x for x in patches] 360 | 361 | data = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f, 362 | output_signature = 'Monster Music Transformer', 363 | output_file_name = '/content/Monster-Music-Transformer-Music-Composition_'+str(i), 364 | track_name='Project Los Angeles', 365 | list_of_MIDI_patches=patches 366 | ) 367 | 368 | 369 | print('=' * 70) 370 | print('Displaying resulting composition...') 371 | print('=' * 70) 372 | 373 | fname = '/content/Monster-Music-Transformer-Music-Composition_'+str(i) 374 | 375 | if render_MIDI_to_audio: 376 | midi_audio = midi_to_colab_audio(fname + '.mid') 377 | display(Audio(midi_audio, rate=16000, normalize=False)) 378 | 379 | TMIDIX.plot_ms_SONG(song_f, plot_title=fname) 380 | 381 | """# (CUSTOM MIDI)""" 382 | 383 | #@title Load Seed MIDI 384 | 385 | #@markdown Press play button to to upload your own seed MIDI or to load one of the provided sample seed MIDIs from the dropdown list below 386 | 387 | select_seed_MIDI = "Upload your own custom MIDI" # @param ["Upload your own custom MIDI", "Monster-Music-Transformer-Piano-Seed-1", "Monster-Music-Transformer-Piano-Seed-2", "Monster-Music-Transformer-Piano-Seed-3", "Monster-Music-Transformer-Piano-Seed-4", "Monster-Music-Transformer-Piano-Seed-5", "Monster-Music-Transformer-Piano-Seed-6", "Monster-Music-Transformer-MI-Seed-1", "Monster-Music-Transformer-MI-Seed-2", "Monster-Music-Transformer-MI-Seed-3", "Monster-Music-Transformer-MI-Seed-4", "Monster-Music-Transformer-MI-Seed-5", "Monster-Music-Transformer-MI-Seed-6"] 388 | render_MIDI_to_audio = False # @param {type:"boolean"} 389 | 390 | print('=' * 70) 391 | print('Monster Music Transformer Seed MIDI Loader') 392 | print('=' * 70) 393 | 394 | f = '' 395 | 396 | if select_seed_MIDI != "Upload your own custom MIDI": 397 | print('Loading seed MIDI...') 398 | f = '/content/Monster-MIDI-Dataset/Seeds/'+select_seed_MIDI+'.mid' 399 | 400 | else: 401 | print('Upload your own custom MIDI...') 402 | print('=' * 70) 403 | uploaded_MIDI = files.upload() 404 | if list(uploaded_MIDI.keys()): 405 | f = list(uploaded_MIDI.keys())[0] 406 | 407 | if f != '': 408 | 409 | print('=' * 70) 410 | print('File:', f) 411 | print('=' * 70) 412 | 413 | #======================================================= 414 | # START PROCESSING 415 | 416 | # Convering MIDI to ms score with MIDI.py module 417 | score = TMIDIX.midi2single_track_ms_score(open(f, 'rb').read(), recalculate_channels=False) 418 | 419 | # INSTRUMENTS CONVERSION CYCLE 420 | events_matrix = [] 421 | itrack = 1 422 | patches = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 423 | 424 | while itrack < len(score): 425 | for event in score[itrack]: 426 | if event[0] == 'note' or event[0] == 'patch_change': 427 | events_matrix.append(event) 428 | itrack += 1 429 | 430 | events_matrix.sort(key=lambda x: x[1]) 431 | 432 | events_matrix1 = [] 433 | 434 | for event in events_matrix: 435 | if event[0] == 'patch_change': 436 | patches[event[2]] = event[3] 437 | 438 | if event[0] == 'note': 439 | event.extend([patches[event[3]]]) 440 | 441 | if events_matrix1: 442 | if (event[1] == events_matrix1[-1][1]): 443 | if ([event[3], event[4]] != events_matrix1[-1][3:5]): 444 | events_matrix1.append(event) 445 | else: 446 | events_matrix1.append(event) 447 | 448 | else: 449 | events_matrix1.append(event) 450 | 451 | if len(events_matrix1) > 0: 452 | if min([e[1] for e in events_matrix1]) >= 0 and min([e[2] for e in events_matrix1]) >= 0: 453 | 454 | #======================================================= 455 | # PRE-PROCESSING 456 | 457 | # checking number of instruments in a composition 458 | instruments_list_without_drums = list(set([y[3] for y in events_matrix1 if y[3] != 9])) 459 | instruments_list = list(set([y[3] for y in events_matrix1])) 460 | 461 | if len(events_matrix1) > 0 and len(instruments_list_without_drums) > 0: 462 | 463 | #====================================== 464 | 465 | events_matrix2 = [] 466 | 467 | # Recalculating timings 468 | for e in events_matrix1: 469 | 470 | # Original timings 471 | e[1] = int(e[1] / 16) 472 | e[2] = int(e[2] / 16) 473 | 474 | #=================================== 475 | # ORIGINAL COMPOSITION 476 | #=================================== 477 | 478 | # Sorting by patch, pitch, then by start-time 479 | 480 | events_matrix1.sort(key=lambda x: x[6]) 481 | events_matrix1.sort(key=lambda x: x[4], reverse=True) 482 | events_matrix1.sort(key=lambda x: x[1]) 483 | 484 | #======================================================= 485 | # FINAL PROCESSING 486 | 487 | melody_chords = [] 488 | melody_chords2 = [] 489 | 490 | # Break between compositions / Intro seq 491 | 492 | if 9 in instruments_list: 493 | drums_present = 18947 # Yes 494 | else: 495 | drums_present = 18946 # No 496 | 497 | if events_matrix1[0][3] != 9: 498 | pat = events_matrix1[0][6] 499 | else: 500 | pat = 128 501 | 502 | melody_chords.extend([19077, drums_present, 18948+pat, 0]) # Intro seq 503 | 504 | #======================================================= 505 | # MAIN PROCESSING CYCLE 506 | #======================================================= 507 | 508 | abs_time = 0 509 | 510 | pbar_time = 0 511 | 512 | pe = events_matrix1[0] 513 | 514 | chords_counter = 1 515 | 516 | comp_chords_len = len(list(set([y[1] for y in events_matrix1]))) 517 | 518 | for e in events_matrix1: 519 | 520 | #======================================================= 521 | # Timings... 522 | 523 | # Cliping all values... 524 | delta_time = max(0, min(255, e[1]-pe[1])) 525 | 526 | # Durations and channels 527 | 528 | dur = max(0, min(255, e[2])) 529 | cha = max(0, min(15, e[3])) 530 | 531 | # Patches 532 | if cha == 9: # Drums patch will be == 128 533 | pat = 128 534 | 535 | else: 536 | pat = e[6] 537 | 538 | # Pitches 539 | 540 | ptc = max(1, min(127, e[4])) 541 | 542 | # Velocities 543 | 544 | # Calculating octo-velocity 545 | vel = max(8, min(127, e[5])) 546 | velocity = round(vel / 15)-1 547 | 548 | #======================================================= 549 | # Outro seq 550 | 551 | # if ((comp_chords_len - chords_counter) == 50) and (delta_time != 0): 552 | # out_t = 18946+delta_time 553 | # out_p = 19202+ptc 554 | # melody_chords.extend([18945, out_t, out_p]) # outro seq 555 | 556 | 557 | # if delta_time != 0: 558 | # chords_counter += 1 559 | 560 | #======================================================= 561 | # FINAL NOTE SEQ 562 | 563 | # Writing final note asynchronously 564 | 565 | dur_vel = (8 * dur) + velocity 566 | pat_ptc = (129 * pat) + ptc 567 | 568 | if delta_time != 0: 569 | melody_chords.extend([delta_time, dur_vel+256, pat_ptc+2304]) 570 | else: 571 | melody_chords.extend([dur_vel+256, pat_ptc+2304]) 572 | melody_chords2.append([delta_time, dur_vel+256, pat_ptc+2304]) 573 | 574 | pe = e 575 | 576 | #======================================================= 577 | 578 | # melody_chords.extend([19462, 19462, 19462]) # EOS 579 | 580 | #======================================================= 581 | 582 | # TOTAL DICTIONARY SIZE 19462+1=19463 583 | #======================================================= 584 | 585 | #======================================================= 586 | 587 | song = melody_chords 588 | 589 | song_f = [] 590 | 591 | time = 0 592 | dur = 0 593 | vel = 90 594 | pitch = 0 595 | channel = 0 596 | 597 | patches = [-1] * 16 598 | 599 | channels = [0] * 16 600 | channels[9] = 1 601 | 602 | for ss in song: 603 | 604 | if 0 <= ss < 256: 605 | 606 | time += ss * 16 607 | 608 | if 256 <= ss < 2304: 609 | 610 | dur = ((ss-256) // 8) * 16 611 | vel = (((ss-256) % 8)+1) * 15 612 | 613 | if 2304 <= ss < 18945: 614 | 615 | patch = (ss-2304) // 129 616 | 617 | if patch < 128: 618 | 619 | if patch not in patches: 620 | if 0 in channels: 621 | cha = channels.index(0) 622 | channels[cha] = 1 623 | else: 624 | cha = 15 625 | 626 | patches[cha] = patch 627 | channel = patches.index(patch) 628 | else: 629 | channel = patches.index(patch) 630 | 631 | if patch == 128: 632 | channel = 9 633 | 634 | pitch = (ss-2304) % 129 635 | 636 | song_f.append(['note', time, dur, channel, pitch, vel, patch ]) 637 | 638 | patches = [0 if x==-1 else x for x in patches] 639 | 640 | detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f, 641 | output_signature = 'Monster Music Transformer', 642 | output_file_name = '/content/Monster-Music-Transformer-Seed-Composition', 643 | track_name='Project Los Angeles', 644 | list_of_MIDI_patches=patches 645 | ) 646 | 647 | #======================================================= 648 | 649 | print('=' * 70) 650 | print('Composition stats:') 651 | print('Composition has', len(melody_chords2), 'notes') 652 | print('Composition has', len(melody_chords), 'tokens') 653 | print('Composition MIDI patches:', sorted(list(set([((y-2304) // 129) for y in melody_chords if 2304 <= y < 18945])))) 654 | print('=' * 70) 655 | 656 | print('Displaying resulting composition...') 657 | print('=' * 70) 658 | 659 | fname = '/content/Monster-Music-Transformer-Seed-Composition' 660 | 661 | if render_MIDI_to_audio: 662 | midi_audio = midi_to_colab_audio(fname + '.mid') 663 | display(Audio(midi_audio, rate=16000, normalize=False)) 664 | 665 | TMIDIX.plot_ms_SONG(song_f, plot_title=fname) 666 | 667 | else: 668 | print('=' * 70) 669 | 670 | """# (CONTINUATION)""" 671 | 672 | #@title Standard Continuation 673 | 674 | #@markdown Generation settings 675 | 676 | try_to_generate_outro = False #@param {type:"boolean"} 677 | number_of_prime_tokens = 7191 # @param {type:"slider", min:3, max:8190, step:3} 678 | number_of_tokens_to_generate = 504 # @param {type:"slider", min:30, max:8190, step:3} 679 | number_of_batches_to_generate = 4 #@param {type:"slider", min:1, max:16, step:1} 680 | temperature = 0.9 # @param {type:"slider", min:0.1, max:1, step:0.05} 681 | 682 | #@markdown Other settings 683 | include_prime_tokens_in_generated_output = False #@param {type:"boolean"} 684 | allow_model_to_stop_generation_if_needed = False #@param {type:"boolean"} 685 | render_MIDI_to_audio = True # @param {type:"boolean"} 686 | 687 | print('=' * 70) 688 | print('Monster Music Transformer Standard Continuation Model Generator') 689 | print('=' * 70) 690 | 691 | if allow_model_to_stop_generation_if_needed: 692 | min_stop_token = 19078 693 | else: 694 | min_stop_token = None 695 | 696 | outy = melody_chords[:number_of_prime_tokens] 697 | 698 | if try_to_generate_outro: 699 | outy.extend([18945]) 700 | 701 | torch.cuda.empty_cache() 702 | 703 | inp = [outy] * number_of_batches_to_generate 704 | 705 | inp = torch.LongTensor(inp).cuda() 706 | 707 | with ctx: 708 | out = model.generate(inp, 709 | number_of_tokens_to_generate, 710 | temperature=temperature, 711 | return_prime=include_prime_tokens_in_generated_output, 712 | eos_token=min_stop_token, 713 | verbose=True) 714 | 715 | out0 = out.tolist() 716 | 717 | torch.cuda.empty_cache() 718 | 719 | print('=' * 70) 720 | print('Done!') 721 | print('=' * 70) 722 | 723 | #====================================================================== 724 | print('Rendering results...') 725 | 726 | for i in range(number_of_batches_to_generate): 727 | 728 | print('=' * 70) 729 | print('Batch #', i) 730 | print('=' * 70) 731 | 732 | out1 = out0[i] 733 | 734 | print('Sample INTs', out1[:12]) 735 | print('=' * 70) 736 | 737 | if len(out) != 0: 738 | 739 | song = out1 740 | song_f = [] 741 | 742 | time = 0 743 | dur = 0 744 | vel = 90 745 | pitch = 0 746 | channel = 0 747 | 748 | patches = [-1] * 16 749 | 750 | channels = [0] * 16 751 | channels[9] = 1 752 | 753 | for ss in song: 754 | 755 | if 0 <= ss < 256: 756 | 757 | time += ss * 16 758 | 759 | if 256 <= ss < 2304: 760 | 761 | dur = ((ss-256) // 8) * 16 762 | vel = (((ss-256) % 8)+1) * 15 763 | 764 | if 2304 <= ss < 18945: 765 | 766 | patch = (ss-2304) // 129 767 | 768 | if patch < 128: 769 | 770 | if patch not in patches: 771 | if 0 in channels: 772 | cha = channels.index(0) 773 | channels[cha] = 1 774 | else: 775 | cha = 15 776 | 777 | patches[cha] = patch 778 | channel = patches.index(patch) 779 | else: 780 | channel = patches.index(patch) 781 | 782 | if patch == 128: 783 | channel = 9 784 | 785 | pitch = (ss-2304) % 129 786 | 787 | song_f.append(['note', time, dur, channel, pitch, vel, patch ]) 788 | 789 | patches = [0 if x==-1 else x for x in patches] 790 | 791 | detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f, 792 | output_signature = 'Monster Music Transformer', 793 | output_file_name = '/content/Monster-Music-Transformer-Music-Composition_'+str(i), 794 | track_name='Project Los Angeles', 795 | list_of_MIDI_patches=patches 796 | ) 797 | print('=' * 70) 798 | print('Displaying resulting composition...') 799 | print('=' * 70) 800 | 801 | fname = '/content/Monster-Music-Transformer-Music-Composition_'+str(i) 802 | 803 | if render_MIDI_to_audio: 804 | midi_audio = midi_to_colab_audio(fname + '.mid') 805 | display(Audio(midi_audio, rate=16000, normalize=False)) 806 | 807 | TMIDIX.plot_ms_SONG(song_f, plot_title=fname) 808 | 809 | """# Congrats! You did it! :)""" -------------------------------------------------------------------------------- /monster_midi_dataset_gpu_search_and_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Monster_MIDI_Dataset_GPU_Search_and_Filter.ipynb 3 | 4 | Automatically generated by Colab. 5 | 6 | Original file is located at 7 | https://colab.research.google.com/github/asigalov61/Monster-MIDI-Dataset/blob/main/Monster_MIDI_Dataset_GPU_Search_and_Filter.ipynb 8 | 9 | # Monster MIDI Dataset GPU Search and Filter (ver. 4.0) 10 | 11 | *** 12 | 13 | Powered by tegridy-tools: https://github.com/asigalov61/tegridy-tools 14 | 15 | *** 16 | 17 | #### Project Los Angeles 18 | 19 | #### Tegridy Code 2024 20 | 21 | *** 22 | 23 | # (GPU CHECK) 24 | """ 25 | 26 | # @title NVIDIA GPU Check 27 | !nvidia-smi 28 | 29 | """# (SETUP ENVIRONMENT)""" 30 | 31 | #@title Install all dependencies (run only once per session) 32 | 33 | !git clone --depth 1 https://github.com/asigalov61/Monster-MIDI-Dataset 34 | !pip install huggingface_hub 35 | !pip install hf_transfer 36 | 37 | #@title Import all needed modules 38 | 39 | print('Loading core modules... Please wait...') 40 | 41 | import os 42 | import copy 43 | from collections import Counter 44 | import random 45 | import pickle 46 | from tqdm import tqdm 47 | import pprint 48 | import statistics 49 | import shutil 50 | 51 | os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1" 52 | 53 | try: 54 | import locale 55 | locale.getpreferredencoding = lambda: "UTF-8" 56 | 57 | except: 58 | pass 59 | 60 | try: 61 | import cupy as cp 62 | 63 | except: 64 | import numpy as cp 65 | 66 | from huggingface_hub import hf_hub_download 67 | 68 | try: 69 | from google.colab import files 70 | 71 | except: 72 | pass 73 | 74 | print('Loading TMIDIX module...') 75 | os.chdir('/content/Monster-MIDI-Dataset') 76 | 77 | import TMIDIX 78 | 79 | os.chdir('/content/') 80 | 81 | print('Creating IO dirs... Please wait...') 82 | 83 | if not os.path.exists('/content/Master-MIDI-Dataset'): 84 | os.makedirs('/content/Master-MIDI-Dataset') 85 | 86 | if not os.path.exists('/content/Output-MIDI-Dataset'): 87 | os.makedirs('/content/Output-MIDI-Dataset') 88 | 89 | print('Done!') 90 | print('Enjoy! :)') 91 | 92 | """# (DOWNLOAD AND UNZIP MAIN MIDI DATASET)""" 93 | 94 | #@title Download Monster MIDI Dataset 95 | print('=' * 70) 96 | print('Downloading Monster MIDI Dataset...Please wait...') 97 | print('=' * 70) 98 | 99 | hf_hub_download(repo_id='projectlosangeles/Monster-MIDI-Dataset', 100 | filename='Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip', 101 | repo_type="dataset", 102 | local_dir='/content/Main-MIDI-Dataset' 103 | ) 104 | print('=' * 70) 105 | print('Done! Enjoy! :)') 106 | print('=' * 70) 107 | 108 | # Commented out IPython magic to ensure Python compatibility. 109 | #@title Unzip Monster MIDI Dataset 110 | # %cd /content/Main-MIDI-Dataset/ 111 | 112 | print('=' * 70) 113 | print('Unzipping Monster MIDI Dataset...Please wait...') 114 | !unzip 'Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip' > /dev/null 115 | print('=' * 70) 116 | 117 | print('Done! Enjoy! :)') 118 | print('=' * 70) 119 | # %cd /content/ 120 | 121 | """# (CREATE MAIN MIDI DATASET FILES LIST)""" 122 | 123 | #@title Create Monster MIDI Dataset files list 124 | print('=' * 70) 125 | print('Creating dataset files list...') 126 | dataset_addr = "/content/Main-MIDI-Dataset/MIDIs" 127 | 128 | # os.chdir(dataset_addr) 129 | filez = list() 130 | for (dirpath, dirnames, filenames) in os.walk(dataset_addr): 131 | filez += [os.path.join(dirpath, file) for file in filenames] 132 | 133 | if filez == []: 134 | print('Could not find any MIDI files. Please check Dataset dir...') 135 | print('=' * 70) 136 | 137 | print('=' * 70) 138 | print('Randomizing file list...') 139 | random.shuffle(filez) 140 | print('=' * 70) 141 | 142 | LAMD_files_list = [] 143 | 144 | for f in tqdm(filez): 145 | LAMD_files_list.append([f.split('/')[-1].split('.mid')[0], f]) 146 | print('Done!') 147 | print('=' * 70) 148 | 149 | """# (SIGNATURES SEARCH)""" 150 | 151 | # @title Load Monster MIDI Dataset Signatures Data 152 | 153 | print('=' * 70) 154 | print('Loading Monster MIDI Dataset Signatures Data...') 155 | sigs_data = pickle.load(open('/content/Main-MIDI-Dataset/SIGNATURES_DATA/MONSTER_SIGNATURES_DATA.pickle', 'rb')) 156 | print('=' * 70) 157 | 158 | print('Prepping signatures...') 159 | print('=' * 70) 160 | 161 | random.shuffle(sigs_data) 162 | 163 | signatures_file_names = [] 164 | sigs_matrixes = [ [0]*(len(TMIDIX.ALL_CHORDS_SORTED)+256) for i in range(len(sigs_data))] 165 | 166 | idx = 0 167 | for s in tqdm(sigs_data): 168 | 169 | signatures_file_names.append(s[0]) 170 | 171 | for ss in s[1]: 172 | sigs_matrixes[idx][ss[0]] = ss[1] 173 | 174 | idx += 1 175 | 176 | print('=' * 70) 177 | print('Loading signatures...') 178 | print('=' * 70) 179 | 180 | signatures_data_full = cp.array(sigs_matrixes) 181 | 182 | print('Done!') 183 | print('=' * 70) 184 | 185 | #@title Monster MIDI Dataset Search and Filter 186 | 187 | #@markdown DO NOT FORGET TO UPLOAD YOUR MASTER DATASET TO "Master-MIDI-Dataset" FOLDER 188 | 189 | #@markdown NOTE: You can stop the search at any time to render partial results 190 | 191 | number_of_top_matches_MIDIs_to_collect = 30 #@param {type:"slider", min:5, max:50, step:1} 192 | search_matching_type = "Ratios" # @param ["Ratios", "Distances", "Correlations"] 193 | maximum_match_ratio_to_search_for = 1 #@param {type:"slider", min:0, max:1, step:0.001} 194 | match_results_weight = 2 # @param {type:"slider", min:0.1, max:3, step:0.1} 195 | match_lengths_weight = 1 # @param {type:"slider", min:0.1, max:3, step:0.1} 196 | match_counts_weight = 1 # @param {type:"slider", min:0.1, max:3, step:0.1} 197 | distances_norm_order = 3 # @param {type:"slider", min:1, max:10, step:1} 198 | epsilon = 0.5 # @param {type:"slider", min:0.001, max:1, step:0.001} 199 | match_drums = False # @param {type:"boolean"} 200 | 201 | print('=' * 70) 202 | print('Monster MIDI Dataset GPU Search and Filter') 203 | print('=' * 70) 204 | 205 | ########### 206 | 207 | search_settings_string = '' 208 | 209 | if match_drums: 210 | search_settings_string += 'Chords_Drums' 211 | else: 212 | search_settings_string += 'Chords' 213 | 214 | if search_matching_type == 'Distances': 215 | search_settings_string += '_O_' + str(distances_norm_order) 216 | 217 | search_settings_string += '_W_' 218 | search_settings_string += str(match_results_weight) + '_' 219 | search_settings_string += str(match_lengths_weight) + '_' 220 | search_settings_string += str(match_counts_weight) 221 | 222 | search_settings_string += '_E_' + str(epsilon) 223 | 224 | ########### 225 | 226 | print('Loading MIDI files...') 227 | print('This may take a while on a large dataset in particular.') 228 | 229 | dataset_addr = "/content/Master-MIDI-Dataset" 230 | 231 | filez = list() 232 | 233 | for (dirpath, dirnames, filenames) in os.walk(dataset_addr): 234 | for file in filenames: 235 | if file.endswith(('.mid', '.midi', '.kar')): 236 | filez.append(os.path.join(dirpath, file)) 237 | 238 | print('=' * 70) 239 | 240 | if filez: 241 | 242 | print('Randomizing file list...') 243 | random.shuffle(filez) 244 | print('=' * 70) 245 | 246 | ################### 247 | 248 | if not os.path.exists('/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string): 249 | os.makedirs('/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string) 250 | 251 | ################### 252 | 253 | input_files_count = 0 254 | files_count = 0 255 | 256 | for f in filez: 257 | try: 258 | 259 | input_files_count += 1 260 | 261 | fn = os.path.basename(f) 262 | fn1 = os.path.splitext(fn)[0] 263 | ext = os.path.splitext(f)[1] 264 | 265 | print('Processing MIDI File #', files_count+1, 'out of', len(filez)) 266 | print('MIDI file name', fn) 267 | print('-' * 70) 268 | 269 | #======================================================= 270 | 271 | raw_score = TMIDIX.midi2single_track_ms_score(f) 272 | escore = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0] 273 | 274 | escore = TMIDIX.augment_enhanced_score_notes(escore) 275 | 276 | drums_offset = len(TMIDIX.ALL_CHORDS_SORTED) + 128 277 | 278 | src_sigs = [] 279 | 280 | for i in range(-6, 6): 281 | 282 | escore_copy = copy.deepcopy(escore) 283 | 284 | for e in escore_copy: 285 | e[4] += i 286 | 287 | cscore = TMIDIX.chordify_score([1000, escore_copy]) 288 | 289 | sig = [] 290 | dsig = [] 291 | 292 | for c in cscore: 293 | all_pitches = [e[4] if e[3] != 9 else e[4]+128 for e in c] 294 | chord = sorted(set(all_pitches)) 295 | 296 | pitches = sorted([p for p in chord if p < 128], reverse=True) 297 | drums = [(d+drums_offset)-128 for d in chord if d > 127] 298 | 299 | if pitches: 300 | if len(pitches) > 1: 301 | tones_chord = sorted(set([p % 12 for p in pitches])) 302 | 303 | try: 304 | sig_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord) + 128 305 | except: 306 | checked_tones_chord = TMIDIX.check_and_fix_tones_chord(tones_chord) 307 | sig_token = TMIDIX.ALL_CHORDS_SORTED.index(checked_tones_chord) + 128 308 | 309 | elif len(pitches) == 1: 310 | sig_token = pitches[0] 311 | 312 | sig.append(sig_token) 313 | 314 | if drums: 315 | dsig.extend(drums) 316 | 317 | sig_p = dict.fromkeys(sig+dsig, 0) 318 | for item in sig+dsig: 319 | sig_p[item] += 1 320 | 321 | fsig = [list(v) for v in sig_p.items()] 322 | 323 | src_sig_mat = [0] * (len(TMIDIX.ALL_CHORDS_SORTED)+256) 324 | 325 | for s in fsig: 326 | 327 | src_sig_mat[s[0]] = s[1] 328 | 329 | src_sigs.append(src_sig_mat) 330 | 331 | src_signatures = cp.stack(cp.array(src_sigs)) 332 | 333 | if not match_drums: 334 | src_signatures = src_signatures[:,:drums_offset] 335 | signatures_data = signatures_data_full[:,:drums_offset] 336 | else: 337 | signatures_data = signatures_data_full 338 | 339 | #======================================================= 340 | 341 | print('Searching for matches...Please wait...') 342 | print('-' * 70) 343 | 344 | lower_threshold = 0.0 345 | upper_threshold = maximum_match_ratio_to_search_for 346 | filter_size = number_of_top_matches_MIDIs_to_collect 347 | 348 | final_ratios = [] 349 | 350 | avg_idxs = [] 351 | 352 | all_filtered_means = [] 353 | all_filtered_idxs = [] 354 | all_filtered_tvs = [] 355 | 356 | tv_idx = -6 357 | 358 | for target_sig in tqdm(src_signatures): 359 | 360 | comps_lengths = cp.vstack((cp.repeat(cp.sum(target_sig != 0), signatures_data.shape[0]), cp.sum(signatures_data != 0, axis=1))) 361 | comps_lengths_ratios = cp.divide(cp.min(comps_lengths, axis=0), cp.max(comps_lengths, axis=0)) 362 | 363 | comps_counts_sums = cp.vstack((cp.repeat(cp.sum(target_sig), signatures_data.shape[0]), cp.sum(signatures_data, axis=1))) 364 | comps_counts_sums_ratios = cp.divide(cp.min(comps_counts_sums, axis=0), cp.max(comps_counts_sums, axis=0)) 365 | 366 | if search_matching_type == 'Ratios': 367 | 368 | ratios = cp.where(target_sig != 0, cp.divide(cp.minimum(signatures_data, target_sig), cp.maximum(signatures_data, target_sig)), epsilon) 369 | results = cp.mean(ratios, axis=1) 370 | 371 | elif search_matching_type == 'Distances': 372 | 373 | distances = cp.power(cp.sum(cp.power(cp.abs(signatures_data - target_sig), distances_norm_order), axis=1), 1 / distances_norm_order) 374 | 375 | distances_mean = cp.mean(distances) 376 | distances_std = cp.std(distances) 377 | 378 | results = 1 - cp.divide((distances - distances_mean), distances_std) 379 | 380 | elif search_matching_type == 'Correlations': 381 | 382 | main_array_mean = cp.mean(signatures_data, axis=1, keepdims=True) 383 | main_array_std = cp.std(signatures_data, axis=1, keepdims=True) 384 | target_array_mean = cp.mean(target_sig) 385 | target_array_std = cp.std(target_sig) 386 | 387 | signatures_data_normalized = cp.where(main_array_std != 0, (signatures_data - main_array_mean) / main_array_std, epsilon) 388 | target_sig_normalized = cp.where(target_array_std != 0, (target_sig - target_array_mean) / target_array_std, epsilon) 389 | 390 | correlations = cp.divide(cp.einsum('ij,j->i', signatures_data_normalized, target_sig_normalized), (signatures_data.shape[1] - 1)) 391 | scaled_correlations = cp.divide(correlations, cp.sqrt(cp.sum(correlations**2))) 392 | exp = cp.exp(scaled_correlations - cp.max(scaled_correlations)) 393 | results = cp.multiply(cp.divide(exp, cp.sum(exp)), 1e5) 394 | 395 | results_weight = match_results_weight 396 | comp_lengths_weight = match_lengths_weight 397 | comp_counts_sums_weight = match_counts_weight 398 | 399 | results = cp.divide(cp.add(cp.add(results_weight, comp_lengths_weight), comp_counts_sums_weight), cp.add(cp.add(cp.divide(results_weight, cp.where(results !=0, results, epsilon)), cp.divide(comp_lengths_weight, cp.where(comps_lengths_ratios !=0, comps_lengths_ratios, epsilon))), cp.divide(comp_counts_sums_weight, cp.where(comps_counts_sums_ratios !=0, comps_counts_sums_ratios, epsilon)))) 400 | 401 | unique_means = cp.unique(results) 402 | sorted_means = cp.sort(unique_means)[::-1] 403 | 404 | filtered_means = sorted_means[(sorted_means >= lower_threshold) & (sorted_means <= upper_threshold)][:filter_size] 405 | 406 | filtered_idxs = cp.nonzero(cp.in1d(results, filtered_means))[0] 407 | 408 | all_filtered_means.extend(results[filtered_idxs].tolist()) 409 | 410 | all_filtered_idxs.extend(filtered_idxs.tolist()) 411 | 412 | filtered_tvs = [tv_idx] * filtered_idxs.shape[0] 413 | 414 | all_filtered_tvs.extend(filtered_tvs) 415 | 416 | tv_idx += 1 417 | 418 | f_results = sorted(zip(all_filtered_means, all_filtered_idxs, all_filtered_tvs), key=lambda x: x[0], reverse=True) 419 | 420 | triplet_dict = {} 421 | 422 | for triplet in f_results: 423 | 424 | if triplet[0] not in triplet_dict: 425 | triplet_dict[triplet[0]] = triplet 426 | else: 427 | if triplet[2] == 0: 428 | triplet_dict[triplet[0]] = triplet 429 | 430 | filtered_results = list(triplet_dict.values())[:filter_size] 431 | 432 | #======================================================= 433 | 434 | print('Done!') 435 | print('-' * 70) 436 | print('Max match ratio:', filtered_results[0][0]) 437 | print('Max match transpose value:', filtered_results[0][2]) 438 | print('Max match signature index:', filtered_results[0][1]) 439 | print('Max match file name:', signatures_file_names[filtered_results[0][1]]) 440 | print('-' * 70) 441 | print('Copying max ratios MIDIs...') 442 | 443 | for fr in filtered_results: 444 | 445 | max_ratio_index = fr[1] 446 | 447 | ffn = signatures_file_names[fr[1]] 448 | ffn_idx = [y[0] for y in LAMD_files_list].index(ffn) 449 | 450 | ff = LAMD_files_list[ffn_idx][1] 451 | 452 | #======================================================= 453 | 454 | dir_str = str(fn1) 455 | copy_path = '/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string+'/'+dir_str 456 | if not os.path.exists(copy_path): 457 | os.mkdir(copy_path) 458 | 459 | fff = str(fr[0] * 100) + '_' + str(fr[2]) + '_' + ffn + '.mid' 460 | 461 | shutil.copy2(ff, copy_path+'/'+fff) 462 | 463 | shutil.copy2(f, copy_path+'/'+fn) 464 | 465 | #=======================================================''' 466 | print('Done!') 467 | print('=' * 70) 468 | 469 | #======================================================= 470 | 471 | # Processed files counter 472 | files_count += 1 473 | 474 | except KeyboardInterrupt: 475 | print('Quitting...') 476 | print('Total number of processed MIDI files', files_count) 477 | print('=' * 70) 478 | break 479 | 480 | except Exception as ex: 481 | print('WARNING !!!') 482 | print('=' * 70) 483 | print('Bad file:', f) 484 | print('Error detected:', ex) 485 | print('=' * 70) 486 | continue 487 | 488 | print('Total number of processed MIDI files', files_count) 489 | print('=' * 70) 490 | 491 | else: 492 | print('Could not find any MIDI files. Please check Dataset dir...') 493 | print('=' * 70) 494 | 495 | """# (KILO-CHORDS SEARCH)""" 496 | 497 | #@title Load Monster MIDI Dataset Kilo-Chords Data 498 | search_matching_type = "Full-Kilo-Chords" # @param ["Full-Kilo-Chords", "Unique-Kilo-Chords"] 499 | 500 | print('=' * 70) 501 | print('Loading Monster MIDI Dataset Kilo-Chords Data...') 502 | kilo_chords = pickle.load(open('/content/Main-MIDI-Dataset/KILO_CHORDS_DATA/MONSTER_KILO_CHORDS_DATA.pickle', 'rb')) 503 | print('=' * 70) 504 | 505 | print('Prepping Kilo-Chords...') 506 | print('=' * 70) 507 | 508 | random.shuffle(kilo_chords) 509 | 510 | if search_matching_type == 'Full-Kilo-Chords': 511 | 512 | kilo_chords_file_names = [] 513 | 514 | for kc in tqdm(kilo_chords): 515 | 516 | kilo_chords_file_names.append(kc[0]) 517 | 518 | kcho = kc[1] 519 | 520 | kcho += [0] * (1000 - len(kcho)) 521 | 522 | print('=' * 70) 523 | print('Loading Kilo-Chords...') 524 | print('=' * 70) 525 | 526 | kilo_chords_data = cp.array([kc[1] for kc in kilo_chords]) 527 | 528 | else: 529 | 530 | kilo_chords_file_names = [] 531 | 532 | kilo_chords_matrixes = [ [0]*(len(TMIDIX.ALL_CHORDS_SORTED)+128) for i in range(len(kilo_chords))] 533 | 534 | idx = 0 535 | for kc in tqdm(kilo_chords): 536 | 537 | kilo_chords_file_names.append(kc[0]) 538 | 539 | for c in kc[1]: 540 | kilo_chords_matrixes[idx][c] += 1 541 | 542 | idx += 1 543 | 544 | print('=' * 70) 545 | print('Loading Kilo-Chords...') 546 | print('=' * 70) 547 | 548 | kilo_chords_data = cp.array(kilo_chords_matrixes) 549 | 550 | print('Done!') 551 | print('=' * 70) 552 | 553 | #@title Monster MIDI Dataset Search and Filter 554 | 555 | #@markdown DO NOT FORGET TO UPLOAD YOUR MASTER DATASET TO "Master-MIDI-Dataset" FOLDER 556 | 557 | #@markdown NOTE: You can stop the search at any time to render partial results 558 | 559 | number_of_top_matches_MIDIs_to_collect = 30 #@param {type:"slider", min:5, max:50, step:1} 560 | maximum_match_ratio_to_search_for = 1 #@param {type:"slider", min:0, max:1, step:0.001} 561 | match_results_weight = 2 # @param {type:"slider", min:0.1, max:3, step:0.1} 562 | match_lengths_weight = 1 # @param {type:"slider", min:0.1, max:3, step:0.1} 563 | match_counts_weight = 1 # @param {type:"slider", min:0.1, max:3, step:0.1} 564 | epsilon = 0.5 # @param {type:"slider", min:0.001, max:1, step:0.001} 565 | 566 | print('=' * 70) 567 | print('Monster MIDI Dataset GPU Search and Filter') 568 | print('=' * 70) 569 | 570 | ########### 571 | 572 | search_settings_string = '' 573 | 574 | search_settings_string += str(search_matching_type).replace('-', '_') 575 | 576 | search_settings_string += '_W_' 577 | search_settings_string += str(match_results_weight) + '_' 578 | search_settings_string += str(match_lengths_weight) + '_' 579 | search_settings_string += str(match_counts_weight) 580 | 581 | search_settings_string += '_E_' + str(epsilon) 582 | 583 | ########### 584 | 585 | print('Loading MIDI files...') 586 | print('This may take a while on a large dataset in particular.') 587 | 588 | dataset_addr = "/content/Master-MIDI-Dataset" 589 | 590 | filez = list() 591 | 592 | for (dirpath, dirnames, filenames) in os.walk(dataset_addr): 593 | for file in filenames: 594 | if file.endswith(('.mid', '.midi', '.kar')): 595 | filez.append(os.path.join(dirpath, file)) 596 | 597 | print('=' * 70) 598 | 599 | if filez: 600 | 601 | print('Randomizing file list...') 602 | random.shuffle(filez) 603 | print('=' * 70) 604 | 605 | ################### 606 | 607 | if not os.path.exists('/content/Output-MIDI-Dataset/'+search_settings_string): 608 | os.makedirs('/content/Output-MIDI-Dataset/'+search_settings_string) 609 | 610 | ################### 611 | 612 | input_files_count = 0 613 | files_count = 0 614 | 615 | for f in filez: 616 | 617 | try: 618 | 619 | input_files_count += 1 620 | 621 | fn = os.path.basename(f) 622 | fn1 = os.path.splitext(fn)[0] 623 | ext = os.path.splitext(f)[1] 624 | 625 | print('Processing MIDI File #', files_count+1, 'out of', len(filez)) 626 | print('MIDI file name', fn) 627 | print('-' * 70) 628 | 629 | #======================================================= 630 | 631 | raw_score = TMIDIX.midi2single_track_ms_score(f) 632 | escore = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0] 633 | 634 | escore = TMIDIX.augment_enhanced_score_notes(escore) 635 | 636 | src_kilo_chords = [] 637 | 638 | for i in range(-6, 6): 639 | 640 | escore_copy = copy.deepcopy(escore) 641 | 642 | for e in escore_copy: 643 | e[4] += i 644 | 645 | cscore = TMIDIX.chordify_score([1000, escore_copy]) 646 | 647 | kilo_chord = [] 648 | 649 | for c in cscore: 650 | 651 | pitches = sorted(set([p[4] for p in c if p[3] != 9]), reverse=True) 652 | 653 | if pitches: 654 | if len(pitches) > 1: 655 | tones_chord = sorted(set([p % 12 for p in pitches])) 656 | 657 | try: 658 | chord_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord) + 128 659 | except: 660 | checked_tones_chord = TMIDIX.check_and_fix_tones_chord(tones_chord) 661 | chord_token = TMIDIX.ALL_CHORDS_SORTED.index(checked_tones_chord) + 128 662 | 663 | elif len(pitches) == 1: 664 | chord_token = pitches[0] 665 | 666 | kilo_chord.append(chord_token) 667 | 668 | if search_matching_type == 'Full-Kilo-Chords': 669 | 670 | kilo_chord = kilo_chord[:1000] 671 | kilo_chord_matrix = kilo_chord + [0] * (1000 - len(kilo_chord)) 672 | 673 | else: 674 | 675 | kilo_chord_matrix = [0] * (len(TMIDIX.ALL_CHORDS_SORTED)+128) 676 | 677 | for c in kilo_chord: 678 | kilo_chord_matrix[c] += 1 679 | 680 | src_kilo_chords.append(kilo_chord_matrix) 681 | 682 | src_kilo_chords = cp.stack(cp.array(src_kilo_chords)) 683 | 684 | #======================================================= 685 | 686 | print('Searching for matches...Please wait...') 687 | print('-' * 70) 688 | 689 | lower_threshold = 0.0 690 | upper_threshold = maximum_match_ratio_to_search_for 691 | filter_size = number_of_top_matches_MIDIs_to_collect 692 | 693 | final_ratios = [] 694 | 695 | avg_idxs = [] 696 | 697 | all_filtered_means = [] 698 | all_filtered_idxs = [] 699 | all_filtered_tvs = [] 700 | 701 | tv_idx = -6 702 | 703 | for target_kc in tqdm(src_kilo_chords): 704 | 705 | comps_lengths = cp.vstack((cp.repeat(cp.sum(target_kc != 0), kilo_chords_data.shape[0]), cp.sum(kilo_chords_data != 0, axis=1))) 706 | comps_lengths_ratios = cp.divide(cp.min(comps_lengths, axis=0), cp.max(comps_lengths, axis=0)) 707 | 708 | comps_counts_sums = cp.vstack((cp.repeat(cp.sum(target_kc), kilo_chords_data.shape[0]), cp.sum(kilo_chords_data, axis=1))) 709 | comps_counts_sums_ratios = cp.divide(cp.min(comps_counts_sums, axis=0), cp.max(comps_counts_sums, axis=0)) 710 | 711 | intersections = cp.where((kilo_chords_data == target_kc), kilo_chords_data, 0) 712 | results = cp.mean(intersections != 0, axis=1) 713 | 714 | results_weight = match_results_weight 715 | comp_lengths_weight = match_lengths_weight 716 | comp_counts_sums_weight = match_counts_weight 717 | 718 | results = cp.divide(cp.add(cp.add(results_weight, comp_lengths_weight), comp_counts_sums_weight), cp.add(cp.add(cp.divide(results_weight, cp.where(results !=0, results, epsilon)), cp.divide(comp_lengths_weight, cp.where(comps_lengths_ratios !=0, comps_lengths_ratios, epsilon))), cp.divide(comp_counts_sums_weight, cp.where(comps_counts_sums_ratios !=0, comps_counts_sums_ratios, epsilon)))) 719 | 720 | unique_means = cp.unique(results) 721 | sorted_means = cp.sort(unique_means)[::-1] 722 | 723 | filtered_means = sorted_means[(sorted_means >= lower_threshold) & (sorted_means <= upper_threshold)][:filter_size] 724 | 725 | filtered_idxs = cp.nonzero(cp.in1d(results, filtered_means))[0] 726 | 727 | all_filtered_means.extend(results[filtered_idxs].tolist()) 728 | 729 | all_filtered_idxs.extend(filtered_idxs.tolist()) 730 | 731 | filtered_tvs = [tv_idx] * filtered_idxs.shape[0] 732 | 733 | all_filtered_tvs.extend(filtered_tvs) 734 | 735 | tv_idx += 1 736 | 737 | f_results = sorted(zip(all_filtered_means, all_filtered_idxs, all_filtered_tvs), key=lambda x: x[0], reverse=True) 738 | 739 | triplet_dict = {} 740 | 741 | for triplet in f_results: 742 | 743 | if triplet[0] not in triplet_dict: 744 | triplet_dict[triplet[0]] = triplet 745 | else: 746 | if triplet[2] == 0: 747 | triplet_dict[triplet[0]] = triplet 748 | 749 | filtered_results = list(triplet_dict.values())[:filter_size] 750 | 751 | #======================================================= 752 | 753 | print('Done!') 754 | print('-' * 70) 755 | print('Max match ratio:', filtered_results[0][0]) 756 | print('Max match transpose value:', filtered_results[0][2]) 757 | print('Max match signature index:', filtered_results[0][1]) 758 | print('Max match file name:', kilo_chords_file_names[filtered_results[0][1]]) 759 | print('-' * 70) 760 | print('Copying max ratios MIDIs...') 761 | 762 | for fr in filtered_results: 763 | 764 | max_ratio_index = fr[1] 765 | 766 | ffn = kilo_chords_file_names[fr[1]] 767 | ffn_idx = [y[0] for y in LAMD_files_list].index(ffn) 768 | 769 | ff = LAMD_files_list[ffn_idx][1] 770 | 771 | #======================================================= 772 | 773 | dir_str = str(fn1) 774 | copy_path = '/content/Output-MIDI-Dataset/'+search_settings_string+'/'+dir_str 775 | if not os.path.exists(copy_path): 776 | os.mkdir(copy_path) 777 | 778 | fff = str(fr[0] * 100) + '_' + str(fr[2]) + '_' + ffn + '.mid' 779 | 780 | shutil.copy2(ff, copy_path+'/'+fff) 781 | 782 | shutil.copy2(f, copy_path+'/'+fn) 783 | 784 | #=======================================================''' 785 | print('Done!') 786 | print('=' * 70) 787 | 788 | #======================================================= 789 | 790 | # Processed files counter 791 | files_count += 1 792 | 793 | except KeyboardInterrupt: 794 | print('Quitting...') 795 | print('Total number of processed MIDI files', files_count) 796 | print('=' * 70) 797 | break 798 | 799 | except Exception as ex: 800 | print('WARNING !!!') 801 | print('=' * 70) 802 | print('Bad file:', f) 803 | print('Error detected:', ex) 804 | print('=' * 70) 805 | continue 806 | 807 | print('Total number of processed MIDI files', files_count) 808 | print('=' * 70) 809 | 810 | else: 811 | print('Could not find any MIDI files. Please check Dataset dir...') 812 | print('=' * 70) 813 | 814 | """# (DOWNLOAD SEARCH RESULTS)""" 815 | 816 | # Commented out IPython magic to ensure Python compatibility. 817 | #@title Zip and download all search results 818 | 819 | print('=' * 70) 820 | 821 | try: 822 | os.remove('Monster_MIDI_Dataset_Search_Results.zip') 823 | except OSError: 824 | pass 825 | 826 | print('Zipping... Please wait...') 827 | print('=' * 70) 828 | 829 | # %cd /content/Output-MIDI-Dataset/ 830 | !zip -r Monster_MIDI_Dataset_Search_Results.zip * 831 | # %cd /content/ 832 | 833 | print('=' * 70) 834 | print('Done!') 835 | print('=' * 70) 836 | 837 | print('Downloading final zip file...') 838 | print('=' * 70) 839 | 840 | files.download('/content/Output-MIDI-Dataset/Monster_MIDI_Dataset_Search_Results.zip') 841 | 842 | print('Done!') 843 | print('=' * 70) 844 | 845 | # @title Delete search results directory and files 846 | 847 | #@markdown WARNING: This can't be undone so make sure you downloaded the search results first 848 | 849 | print('=' * 70) 850 | print('Deleting... Please wait...') 851 | print('=' * 70) 852 | 853 | !rm -rf /content/Output-MIDI-Dataset 854 | print('Done!') 855 | print('=' * 70) 856 | 857 | """# (META DATA SEARCH)""" 858 | 859 | #@title Load Monster MIDI Dataset Metadata 860 | print('=' * 70) 861 | print('Loading Monster MIDI Dataset Metadata...') 862 | meta_data = pickle.load(open('/content/Main-MIDI-Dataset/META_DATA/MONSTER_META_DATA.pickle', 'rb')) 863 | print('Done!') 864 | print('=' * 70) 865 | print('Enjoy!') 866 | print('=' * 70) 867 | 868 | #@title Monster MIDI Dataset Metadata Search 869 | 870 | #@markdown You can search the metadata by search query or by MIDI md5 hash file name 871 | 872 | search_query = "Come To My Window" #@param {type:"string"} 873 | md5_hash_MIDI_file_name = "68dfb00f24f5ebd9bb52823fa9a04c3e" #@param {type:"string"} 874 | case_sensitive_search = False #@param {type:"boolean"} 875 | 876 | fields_to_search = ['track_name', 877 | 'text_event', 878 | 'lyric', 879 | 'copyright_text_event', 880 | 'marker', 881 | 'text_event_08', 882 | 'text_event_09', 883 | 'text_event_0a', 884 | 'text_event_0b', 885 | 'text_event_0c', 886 | 'text_event_0d', 887 | 'text_event_0e', 888 | 'text_event_0f', 889 | ] 890 | 891 | print('=' * 70) 892 | print('Los Angeles MIDI Dataset Metadata Search') 893 | print('=' * 70) 894 | print('Searching...') 895 | print('=' * 70) 896 | 897 | if md5_hash_MIDI_file_name != '': 898 | for d in tqdm(meta_data): 899 | try: 900 | if d[0] == md5_hash_MIDI_file_name: 901 | print('Found!') 902 | print('=' * 70) 903 | print('Metadata index:', meta_data.index(d)) 904 | print('MIDI file name:', meta_data[meta_data.index(d)][0]) 905 | print('-' * 70) 906 | pprint.pprint(['Result:', d[1][:16]], compact = True) 907 | print('=' * 70) 908 | break 909 | 910 | except KeyboardInterrupt: 911 | print('Ending search...') 912 | print('=' * 70) 913 | break 914 | 915 | except Exception as e: 916 | print('WARNING !!!') 917 | print('=' * 70) 918 | print('Error detected:', e) 919 | print('=' * 70) 920 | continue 921 | 922 | if d[0] != md5_hash_MIDI_file_name: 923 | print('Not found!') 924 | print('=' * 70) 925 | print('md5 hash was not found!') 926 | print('Ending search...') 927 | print('=' * 70) 928 | 929 | else: 930 | for d in tqdm(meta_data): 931 | try: 932 | for dd in d[1]: 933 | if dd[0] in fields_to_search: 934 | if case_sensitive_search: 935 | if str(search_query) in str(dd[2]): 936 | print('Found!') 937 | print('=' * 70) 938 | print('Metadata index:', meta_data.index(d)) 939 | print('MIDI file name:', meta_data[meta_data.index(d)][0]) 940 | print('-' * 70) 941 | pprint.pprint(['Result:', dd[2][:16]], compact = True) 942 | print('=' * 70) 943 | 944 | else: 945 | if str(search_query).lower() in str(dd[2]).lower(): 946 | print('Found!') 947 | print('=' * 70) 948 | print('Metadata index:', meta_data.index(d)) 949 | print('MIDI file name:', meta_data[meta_data.index(d)][0]) 950 | print('-' * 70) 951 | pprint.pprint(['Result:', dd[2][:16]], compact = True) 952 | print('=' * 70) 953 | 954 | except KeyboardInterrupt: 955 | print('Ending search...') 956 | print('=' * 70) 957 | break 958 | 959 | except: 960 | print('Ending search...') 961 | print('=' * 70) 962 | break 963 | 964 | """# Congrats! You did it! :)""" -------------------------------------------------------------------------------- /Monster_Music_Transformer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Monster Music Transformer (ver. 1.0)\n", 7 | "\n", 8 | "***\n", 9 | "\n", 10 | "Powered by tegridy-tools: https://github.com/asigalov61/tegridy-tools\n", 11 | "\n", 12 | "***\n", 13 | "\n", 14 | "WARNING: This complete implementation is a functioning model of the Artificial Intelligence. Please excercise great humility, care, and respect. https://www.nscai.gov/\n", 15 | "\n", 16 | "***\n", 17 | "\n", 18 | "#### Project Los Angeles\n", 19 | "\n", 20 | "#### Tegridy Code 2024\n", 21 | "\n", 22 | "***" 23 | ], 24 | "metadata": { 25 | "id": "gpy3qsulqHa5" 26 | } 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "source": [ 31 | "# (GPU CHECK)" 32 | ], 33 | "metadata": { 34 | "id": "W_So4w8fqPGL" 35 | } 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": { 41 | "id": "X3rABEpKCO02", 42 | "cellView": "form" 43 | }, 44 | "outputs": [], 45 | "source": [ 46 | "#@title NVIDIA GPU check\n", 47 | "!nvidia-smi" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "source": [ 53 | "# (SETUP ENVIRONMENT)" 54 | ], 55 | "metadata": { 56 | "id": "C0XxnXGFqVyh" 57 | } 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "id": "vK40g6V_BTNj", 64 | "cellView": "form" 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "#@title Install dependencies\n", 69 | "!git clone --depth 1 https://github.com/asigalov61/Monster-MIDI-Dataset\n", 70 | "!pip install huggingface_hub\n", 71 | "!pip install einops\n", 72 | "!pip install torch-summary\n", 73 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": { 80 | "id": "DzCOZU_gBiQV", 81 | "cellView": "form" 82 | }, 83 | "outputs": [], 84 | "source": [ 85 | "#@title Import modules\n", 86 | "\n", 87 | "print('=' * 70)\n", 88 | "print('Loading core Monster Music Transformer modules...')\n", 89 | "\n", 90 | "import os\n", 91 | "import copy\n", 92 | "import pickle\n", 93 | "import secrets\n", 94 | "import statistics\n", 95 | "from time import time\n", 96 | "import tqdm\n", 97 | "\n", 98 | "print('=' * 70)\n", 99 | "print('Loading main Monster Music Transformer modules...')\n", 100 | "import torch\n", 101 | "\n", 102 | "%cd /content/Monster-MIDI-Dataset\n", 103 | "\n", 104 | "import TMIDIX\n", 105 | "\n", 106 | "from midi_to_colab_audio import midi_to_colab_audio\n", 107 | "\n", 108 | "from x_transformer_1_27_16 import *\n", 109 | "\n", 110 | "import random\n", 111 | "\n", 112 | "%cd /content/\n", 113 | "print('=' * 70)\n", 114 | "print('Loading aux Monster Music Transformer modules...')\n", 115 | "\n", 116 | "import matplotlib.pyplot as plt\n", 117 | "\n", 118 | "from torchsummary import summary\n", 119 | "from sklearn import metrics\n", 120 | "\n", 121 | "from IPython.display import Audio, display\n", 122 | "\n", 123 | "from huggingface_hub import hf_hub_download\n", 124 | "\n", 125 | "from google.colab import files\n", 126 | "\n", 127 | "print('=' * 70)\n", 128 | "print('Done!')\n", 129 | "print('Enjoy! :)')\n", 130 | "print('=' * 70)" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": { 136 | "id": "eI3aQtHzqSnp" 137 | }, 138 | "source": [ 139 | "# (LOAD MODEL)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "source": [ 145 | "#@title Load Monster Music Transformer Pre-Trained Model\n", 146 | "\n", 147 | "#@markdown Choose model\n", 148 | "\n", 149 | "select_model_to_load = \"651M-32L-Fast-Large\" # @param [\"651M-32L-Fast-Large\"]\n", 150 | "\n", 151 | "#@markdown Model precision option\n", 152 | "\n", 153 | "model_precision = \"bfloat16\" # @param [\"bfloat16\", \"float16\"]\n", 154 | "\n", 155 | "#@markdown bfloat16 == Half precision/faster speed (if supported, otherwise the model will default to float16)\n", 156 | "\n", 157 | "#@markdown float16 == Full precision/fast speed\n", 158 | "\n", 159 | "plot_tokens_embeddings = \"None\" # @param [\"None\", \"Start Times\", \"Durations Velocities\", \"Piano Pitches\", \"Drums Pitches\", \"Aux\"]\n", 160 | "\n", 161 | "print('=' * 70)\n", 162 | "print('Loading Monster Music Transformer', select_model_to_load,'Pre-Trained Model...')\n", 163 | "print('Please wait...')\n", 164 | "print('=' * 70)\n", 165 | "\n", 166 | "full_path_to_models_dir = \"/content/Monster-MIDI-Dataset/\"\n", 167 | "\n", 168 | "if select_model_to_load == '651M-32L-Fast-Large':\n", 169 | "\n", 170 | " model_checkpoint_file_name = 'Monster_Music_Transformer_Large_Trained_Model_22501_steps_0.3419_loss_0.9121_acc.pth'\n", 171 | " model_path = full_path_to_models_dir+'/'+model_checkpoint_file_name\n", 172 | " num_layers = 36\n", 173 | " if os.path.isfile(model_path):\n", 174 | " print('Model already exists...')\n", 175 | "\n", 176 | " else:\n", 177 | " hf_hub_download(repo_id='asigalov61/Monster-Music-Transformer',\n", 178 | " filename=model_checkpoint_file_name,\n", 179 | " local_dir='/content/Monster-MIDI-Dataset',\n", 180 | " local_dir_use_symlinks=False)\n", 181 | "\n", 182 | "print('=' * 70)\n", 183 | "print('Instantiating model...')\n", 184 | "\n", 185 | "device_type = 'cuda'\n", 186 | "\n", 187 | "if model_precision == 'bfloat16' and torch.cuda.is_bf16_supported():\n", 188 | " dtype = 'bfloat16'\n", 189 | "else:\n", 190 | " dtype = 'float16'\n", 191 | "\n", 192 | "if model_precision == 'float16':\n", 193 | " dtype = 'float16'\n", 194 | "\n", 195 | "ptdtype = {'float32': torch.float32, 'bfloat16': torch.bfloat16, 'float16': torch.float16}[dtype]\n", 196 | "ctx = torch.amp.autocast(device_type=device_type, dtype=ptdtype)\n", 197 | "\n", 198 | "SEQ_LEN = 8192\n", 199 | "\n", 200 | "# instantiate the model\n", 201 | "\n", 202 | "model = TransformerWrapper(\n", 203 | " num_tokens = 19080,\n", 204 | " max_seq_len = SEQ_LEN,\n", 205 | " attn_layers = Decoder(dim = 1024, depth = num_layers, heads = 32, attn_flash=True)\n", 206 | ")\n", 207 | "\n", 208 | "model = AutoregressiveWrapper(model, ignore_index=19079)\n", 209 | "\n", 210 | "model.cuda()\n", 211 | "print('=' * 70)\n", 212 | "\n", 213 | "print('Loading model checkpoint...')\n", 214 | "\n", 215 | "model.load_state_dict(torch.load(model_path))\n", 216 | "print('=' * 70)\n", 217 | "\n", 218 | "model.eval()\n", 219 | "\n", 220 | "print('Done!')\n", 221 | "print('=' * 70)\n", 222 | "\n", 223 | "print('Model will use', dtype, 'precision...')\n", 224 | "print('=' * 70)\n", 225 | "\n", 226 | "# Model stats\n", 227 | "print('Model summary...')\n", 228 | "summary(model)\n", 229 | "\n", 230 | "# Plot Token Embeddings\n", 231 | "if plot_tokens_embeddings != 'None':\n", 232 | " tok_emb = model.net.token_emb.emb.weight.detach().cpu().tolist()\n", 233 | "\n", 234 | "if plot_tokens_embeddings == 'Start Times':\n", 235 | " tok_range = [0, 256]\n", 236 | "\n", 237 | "elif plot_tokens_embeddings == 'Durations Velocities':\n", 238 | " tok_range = [256, 2304]\n", 239 | "\n", 240 | "elif plot_tokens_embeddings == 'Piano Pitches':\n", 241 | " tok_range = [2304, 2304+128]\n", 242 | "\n", 243 | "elif plot_tokens_embeddings == 'Drums Pitches':\n", 244 | " tok_range = [18945-128, 18945]\n", 245 | "\n", 246 | "elif plot_tokens_embeddings == 'Aux':\n", 247 | " tok_range = [18945, 19079]\n", 248 | "\n", 249 | "if plot_tokens_embeddings != 'None':\n", 250 | "\n", 251 | " tok_emb1 = []\n", 252 | "\n", 253 | " for t in tok_emb[tok_range[0]:tok_range[1]]:\n", 254 | " tok_emb1.append(t)\n", 255 | "\n", 256 | " cos_sim = metrics.pairwise_distances(\n", 257 | " tok_emb1, metric='cosine'\n", 258 | " )\n", 259 | " plt.figure(figsize=(7, 7))\n", 260 | " plt.imshow(cos_sim, cmap=\"inferno\", interpolation=\"nearest\")\n", 261 | " im_ratio = cos_sim.shape[0] / cos_sim.shape[1]\n", 262 | " plt.colorbar(fraction=0.046 * im_ratio, pad=0.04)\n", 263 | " plt.xlabel(\"Position\")\n", 264 | " plt.ylabel(\"Position\")\n", 265 | " plt.tight_layout()\n", 266 | " plt.plot()\n", 267 | " plt.savefig(\"/content/Monster-Music-Transformer-Tokens-Embeddings-Plot.png\", bbox_inches=\"tight\")" 268 | ], 269 | "metadata": { 270 | "id": "V4s_G8yUL0cH", 271 | "cellView": "form" 272 | }, 273 | "execution_count": null, 274 | "outputs": [] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "source": [ 279 | "# (GENERATE)" 280 | ], 281 | "metadata": { 282 | "id": "7xNyANjZsCOi" 283 | } 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "source": [ 288 | "# (IMPROV)" 289 | ], 290 | "metadata": { 291 | "id": "BxepTeHVmmKO" 292 | } 293 | }, 294 | { 295 | "cell_type": "code", 296 | "source": [ 297 | "#@title Standard Improv Generator\n", 298 | "\n", 299 | "#@markdown Improv type\n", 300 | "\n", 301 | "improv_type = \"Random Freestyle\" # @param [\"Random Freestyle\", \"Freestyle without Drums\", \"Freestyle with Drums\", \"Custom\"]\n", 302 | "\n", 303 | "#@markdown Custom Improv settings\n", 304 | "\n", 305 | "first_note_MIDI_patch_number = 0 # @param {type:\"slider\", min:0, max:128, step:1}\n", 306 | "add_drums = False #@param {type:\"boolean\"}\n", 307 | "\n", 308 | "#@markdown Generation settings\n", 309 | "\n", 310 | "number_of_tokens_tp_generate = 546 # @param {type:\"slider\", min:30, max:8190, step:3}\n", 311 | "number_of_batches_to_generate = 4 #@param {type:\"slider\", min:1, max:16, step:1}\n", 312 | "temperature = 0.9 # @param {type:\"slider\", min:0.1, max:1, step:0.05}\n", 313 | "\n", 314 | "#@markdown Other settings\n", 315 | "\n", 316 | "render_MIDI_to_audio = True # @param {type:\"boolean\"}\n", 317 | "\n", 318 | "print('=' * 70)\n", 319 | "print('Monster Music Transformer Standard Improv Model Generator')\n", 320 | "print('=' * 70)\n", 321 | "\n", 322 | "if improv_type == 'Random Freestyle':\n", 323 | "\n", 324 | " outy = [19077]\n", 325 | "\n", 326 | "if improv_type == 'Freestyle without Drums':\n", 327 | "\n", 328 | " outy = [19077, 18946]\n", 329 | "\n", 330 | "if improv_type == 'Freestyle with Drums':\n", 331 | "\n", 332 | " outy = [19077, 18947]\n", 333 | "\n", 334 | "if improv_type == 'Custom':\n", 335 | "\n", 336 | " if add_drums:\n", 337 | " drumsp = 18947 # Yes\n", 338 | " else:\n", 339 | " drumsp = 18946 # No\n", 340 | "\n", 341 | " outy = [19077, drumsp, 18948+first_note_MIDI_patch_number]\n", 342 | "\n", 343 | "print('Selected Improv sequence:')\n", 344 | "print(outy)\n", 345 | "print('=' * 70)\n", 346 | "\n", 347 | "torch.cuda.empty_cache()\n", 348 | "\n", 349 | "inp = [outy] * number_of_batches_to_generate\n", 350 | "\n", 351 | "inp = torch.LongTensor(inp).cuda()\n", 352 | "\n", 353 | "with ctx:\n", 354 | " out = model.generate(inp,\n", 355 | " number_of_tokens_tp_generate,\n", 356 | " temperature=temperature,\n", 357 | " return_prime=True,\n", 358 | " verbose=True)\n", 359 | "\n", 360 | "out0 = out.tolist()\n", 361 | "\n", 362 | "print('=' * 70)\n", 363 | "print('Done!')\n", 364 | "print('=' * 70)\n", 365 | "\n", 366 | "torch.cuda.empty_cache()\n", 367 | "\n", 368 | "#======================================================================\n", 369 | "\n", 370 | "print('Rendering results...')\n", 371 | "\n", 372 | "for i in range(number_of_batches_to_generate):\n", 373 | "\n", 374 | " print('=' * 70)\n", 375 | " print('Batch #', i)\n", 376 | " print('=' * 70)\n", 377 | "\n", 378 | " out1 = out0[i]\n", 379 | "\n", 380 | " print('Sample INTs', out1[:12])\n", 381 | " print('=' * 70)\n", 382 | "\n", 383 | " if len(out1) != 0:\n", 384 | "\n", 385 | " song = out1\n", 386 | " song_f = []\n", 387 | "\n", 388 | " time = 0\n", 389 | " dur = 0\n", 390 | " vel = 90\n", 391 | " pitch = 0\n", 392 | " channel = 0\n", 393 | "\n", 394 | " patches = [-1] * 16\n", 395 | "\n", 396 | " channels = [0] * 16\n", 397 | " channels[9] = 1\n", 398 | "\n", 399 | " for ss in song:\n", 400 | "\n", 401 | " if 0 <= ss < 256:\n", 402 | "\n", 403 | " time += ss * 16\n", 404 | "\n", 405 | " if 256 <= ss < 2304:\n", 406 | "\n", 407 | " dur = ((ss-256) // 8) * 16\n", 408 | " vel = (((ss-256) % 8)+1) * 15\n", 409 | "\n", 410 | " if 2304 <= ss < 18945:\n", 411 | "\n", 412 | " patch = (ss-2304) // 129\n", 413 | "\n", 414 | " if patch < 128:\n", 415 | "\n", 416 | " if patch not in patches:\n", 417 | " if 0 in channels:\n", 418 | " cha = channels.index(0)\n", 419 | " channels[cha] = 1\n", 420 | " else:\n", 421 | " cha = 15\n", 422 | "\n", 423 | " patches[cha] = patch\n", 424 | " channel = patches.index(patch)\n", 425 | " else:\n", 426 | " channel = patches.index(patch)\n", 427 | "\n", 428 | " if patch == 128:\n", 429 | " channel = 9\n", 430 | "\n", 431 | " pitch = (ss-2304) % 129\n", 432 | "\n", 433 | " song_f.append(['note', time, dur, channel, pitch, vel, patch ])\n", 434 | "\n", 435 | " patches = [0 if x==-1 else x for x in patches]\n", 436 | "\n", 437 | " data = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f,\n", 438 | " output_signature = 'Monster Music Transformer',\n", 439 | " output_file_name = '/content/Monster-Music-Transformer-Music-Composition_'+str(i),\n", 440 | " track_name='Project Los Angeles',\n", 441 | " list_of_MIDI_patches=patches\n", 442 | " )\n", 443 | "\n", 444 | "\n", 445 | " print('=' * 70)\n", 446 | " print('Displaying resulting composition...')\n", 447 | " print('=' * 70)\n", 448 | "\n", 449 | " fname = '/content/Monster-Music-Transformer-Music-Composition_'+str(i)\n", 450 | "\n", 451 | " if render_MIDI_to_audio:\n", 452 | " midi_audio = midi_to_colab_audio(fname + '.mid')\n", 453 | " display(Audio(midi_audio, rate=16000, normalize=False))\n", 454 | "\n", 455 | " TMIDIX.plot_ms_SONG(song_f, plot_title=fname)" 456 | ], 457 | "metadata": { 458 | "cellView": "form", 459 | "id": "Jwxz-eaF0K1y" 460 | }, 461 | "execution_count": null, 462 | "outputs": [] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "source": [ 467 | "# (CUSTOM MIDI)" 468 | ], 469 | "metadata": { 470 | "id": "Gt03VtO6uKkb" 471 | } 472 | }, 473 | { 474 | "cell_type": "code", 475 | "execution_count": null, 476 | "metadata": { 477 | "id": "4QXbFLsKqSnt", 478 | "cellView": "form" 479 | }, 480 | "outputs": [], 481 | "source": [ 482 | "#@title Load Seed MIDI\n", 483 | "\n", 484 | "#@markdown Press play button to to upload your own seed MIDI or to load one of the provided sample seed MIDIs from the dropdown list below\n", 485 | "\n", 486 | "select_seed_MIDI = \"Upload your own custom MIDI\" # @param [\"Upload your own custom MIDI\", \"Monster-Music-Transformer-Piano-Seed-1\", \"Monster-Music-Transformer-Piano-Seed-2\", \"Monster-Music-Transformer-Piano-Seed-3\", \"Monster-Music-Transformer-Piano-Seed-4\", \"Monster-Music-Transformer-Piano-Seed-5\", \"Monster-Music-Transformer-Piano-Seed-6\", \"Monster-Music-Transformer-MI-Seed-1\", \"Monster-Music-Transformer-MI-Seed-2\", \"Monster-Music-Transformer-MI-Seed-3\", \"Monster-Music-Transformer-MI-Seed-4\", \"Monster-Music-Transformer-MI-Seed-5\", \"Monster-Music-Transformer-MI-Seed-6\"]\n", 487 | "render_MIDI_to_audio = False # @param {type:\"boolean\"}\n", 488 | "\n", 489 | "print('=' * 70)\n", 490 | "print('Monster Music Transformer Seed MIDI Loader')\n", 491 | "print('=' * 70)\n", 492 | "\n", 493 | "f = ''\n", 494 | "\n", 495 | "if select_seed_MIDI != \"Upload your own custom MIDI\":\n", 496 | " print('Loading seed MIDI...')\n", 497 | " f = '/content/Monster-MIDI-Dataset/Seeds/'+select_seed_MIDI+'.mid'\n", 498 | "\n", 499 | "else:\n", 500 | " print('Upload your own custom MIDI...')\n", 501 | " print('=' * 70)\n", 502 | " uploaded_MIDI = files.upload()\n", 503 | " if list(uploaded_MIDI.keys()):\n", 504 | " f = list(uploaded_MIDI.keys())[0]\n", 505 | "\n", 506 | "if f != '':\n", 507 | "\n", 508 | " print('=' * 70)\n", 509 | " print('File:', f)\n", 510 | " print('=' * 70)\n", 511 | "\n", 512 | " #=======================================================\n", 513 | " # START PROCESSING\n", 514 | "\n", 515 | " # Convering MIDI to ms score with MIDI.py module\n", 516 | " score = TMIDIX.midi2single_track_ms_score(open(f, 'rb').read(), recalculate_channels=False)\n", 517 | "\n", 518 | " # INSTRUMENTS CONVERSION CYCLE\n", 519 | " events_matrix = []\n", 520 | " itrack = 1\n", 521 | " patches = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n", 522 | "\n", 523 | " while itrack < len(score):\n", 524 | " for event in score[itrack]:\n", 525 | " if event[0] == 'note' or event[0] == 'patch_change':\n", 526 | " events_matrix.append(event)\n", 527 | " itrack += 1\n", 528 | "\n", 529 | " events_matrix.sort(key=lambda x: x[1])\n", 530 | "\n", 531 | " events_matrix1 = []\n", 532 | "\n", 533 | " for event in events_matrix:\n", 534 | " if event[0] == 'patch_change':\n", 535 | " patches[event[2]] = event[3]\n", 536 | "\n", 537 | " if event[0] == 'note':\n", 538 | " event.extend([patches[event[3]]])\n", 539 | "\n", 540 | " if events_matrix1:\n", 541 | " if (event[1] == events_matrix1[-1][1]):\n", 542 | " if ([event[3], event[4]] != events_matrix1[-1][3:5]):\n", 543 | " events_matrix1.append(event)\n", 544 | " else:\n", 545 | " events_matrix1.append(event)\n", 546 | "\n", 547 | " else:\n", 548 | " events_matrix1.append(event)\n", 549 | "\n", 550 | " if len(events_matrix1) > 0:\n", 551 | " if min([e[1] for e in events_matrix1]) >= 0 and min([e[2] for e in events_matrix1]) >= 0:\n", 552 | "\n", 553 | " #=======================================================\n", 554 | " # PRE-PROCESSING\n", 555 | "\n", 556 | " # checking number of instruments in a composition\n", 557 | " instruments_list_without_drums = list(set([y[3] for y in events_matrix1 if y[3] != 9]))\n", 558 | " instruments_list = list(set([y[3] for y in events_matrix1]))\n", 559 | "\n", 560 | " if len(events_matrix1) > 0 and len(instruments_list_without_drums) > 0:\n", 561 | "\n", 562 | " #======================================\n", 563 | "\n", 564 | " events_matrix2 = []\n", 565 | "\n", 566 | " # Recalculating timings\n", 567 | " for e in events_matrix1:\n", 568 | "\n", 569 | " # Original timings\n", 570 | " e[1] = int(e[1] / 16)\n", 571 | " e[2] = int(e[2] / 16)\n", 572 | "\n", 573 | " #===================================\n", 574 | " # ORIGINAL COMPOSITION\n", 575 | " #===================================\n", 576 | "\n", 577 | " # Sorting by patch, pitch, then by start-time\n", 578 | "\n", 579 | " events_matrix1.sort(key=lambda x: x[6])\n", 580 | " events_matrix1.sort(key=lambda x: x[4], reverse=True)\n", 581 | " events_matrix1.sort(key=lambda x: x[1])\n", 582 | "\n", 583 | " #=======================================================\n", 584 | " # FINAL PROCESSING\n", 585 | "\n", 586 | " melody_chords = []\n", 587 | " melody_chords2 = []\n", 588 | "\n", 589 | " # Break between compositions / Intro seq\n", 590 | "\n", 591 | " if 9 in instruments_list:\n", 592 | " drums_present = 18947 # Yes\n", 593 | " else:\n", 594 | " drums_present = 18946 # No\n", 595 | "\n", 596 | " if events_matrix1[0][3] != 9:\n", 597 | " pat = events_matrix1[0][6]\n", 598 | " else:\n", 599 | " pat = 128\n", 600 | "\n", 601 | " melody_chords.extend([19077, drums_present, 18948+pat, 0]) # Intro seq\n", 602 | "\n", 603 | " #=======================================================\n", 604 | " # MAIN PROCESSING CYCLE\n", 605 | " #=======================================================\n", 606 | "\n", 607 | " abs_time = 0\n", 608 | "\n", 609 | " pbar_time = 0\n", 610 | "\n", 611 | " pe = events_matrix1[0]\n", 612 | "\n", 613 | " chords_counter = 1\n", 614 | "\n", 615 | " comp_chords_len = len(list(set([y[1] for y in events_matrix1])))\n", 616 | "\n", 617 | " for e in events_matrix1:\n", 618 | "\n", 619 | " #=======================================================\n", 620 | " # Timings...\n", 621 | "\n", 622 | " # Cliping all values...\n", 623 | " delta_time = max(0, min(255, e[1]-pe[1]))\n", 624 | "\n", 625 | " # Durations and channels\n", 626 | "\n", 627 | " dur = max(0, min(255, e[2]))\n", 628 | " cha = max(0, min(15, e[3]))\n", 629 | "\n", 630 | " # Patches\n", 631 | " if cha == 9: # Drums patch will be == 128\n", 632 | " pat = 128\n", 633 | "\n", 634 | " else:\n", 635 | " pat = e[6]\n", 636 | "\n", 637 | " # Pitches\n", 638 | "\n", 639 | " ptc = max(1, min(127, e[4]))\n", 640 | "\n", 641 | " # Velocities\n", 642 | "\n", 643 | " # Calculating octo-velocity\n", 644 | " vel = max(8, min(127, e[5]))\n", 645 | " velocity = round(vel / 15)-1\n", 646 | "\n", 647 | " #=======================================================\n", 648 | " # Outro seq\n", 649 | "\n", 650 | " # if ((comp_chords_len - chords_counter) == 50) and (delta_time != 0):\n", 651 | " # out_t = 18946+delta_time\n", 652 | " # out_p = 19202+ptc\n", 653 | " # melody_chords.extend([18945, out_t, out_p]) # outro seq\n", 654 | "\n", 655 | "\n", 656 | " # if delta_time != 0:\n", 657 | " # chords_counter += 1\n", 658 | "\n", 659 | " #=======================================================\n", 660 | " # FINAL NOTE SEQ\n", 661 | "\n", 662 | " # Writing final note asynchronously\n", 663 | "\n", 664 | " dur_vel = (8 * dur) + velocity\n", 665 | " pat_ptc = (129 * pat) + ptc\n", 666 | "\n", 667 | " if delta_time != 0:\n", 668 | " melody_chords.extend([delta_time, dur_vel+256, pat_ptc+2304])\n", 669 | " else:\n", 670 | " melody_chords.extend([dur_vel+256, pat_ptc+2304])\n", 671 | " melody_chords2.append([delta_time, dur_vel+256, pat_ptc+2304])\n", 672 | "\n", 673 | " pe = e\n", 674 | "\n", 675 | " #=======================================================\n", 676 | "\n", 677 | " # melody_chords.extend([19462, 19462, 19462]) # EOS\n", 678 | "\n", 679 | " #=======================================================\n", 680 | "\n", 681 | " # TOTAL DICTIONARY SIZE 19462+1=19463\n", 682 | " #=======================================================\n", 683 | "\n", 684 | " #=======================================================\n", 685 | "\n", 686 | " song = melody_chords\n", 687 | "\n", 688 | " song_f = []\n", 689 | "\n", 690 | " time = 0\n", 691 | " dur = 0\n", 692 | " vel = 90\n", 693 | " pitch = 0\n", 694 | " channel = 0\n", 695 | "\n", 696 | " patches = [-1] * 16\n", 697 | "\n", 698 | " channels = [0] * 16\n", 699 | " channels[9] = 1\n", 700 | "\n", 701 | " for ss in song:\n", 702 | "\n", 703 | " if 0 <= ss < 256:\n", 704 | "\n", 705 | " time += ss * 16\n", 706 | "\n", 707 | " if 256 <= ss < 2304:\n", 708 | "\n", 709 | " dur = ((ss-256) // 8) * 16\n", 710 | " vel = (((ss-256) % 8)+1) * 15\n", 711 | "\n", 712 | " if 2304 <= ss < 18945:\n", 713 | "\n", 714 | " patch = (ss-2304) // 129\n", 715 | "\n", 716 | " if patch < 128:\n", 717 | "\n", 718 | " if patch not in patches:\n", 719 | " if 0 in channels:\n", 720 | " cha = channels.index(0)\n", 721 | " channels[cha] = 1\n", 722 | " else:\n", 723 | " cha = 15\n", 724 | "\n", 725 | " patches[cha] = patch\n", 726 | " channel = patches.index(patch)\n", 727 | " else:\n", 728 | " channel = patches.index(patch)\n", 729 | "\n", 730 | " if patch == 128:\n", 731 | " channel = 9\n", 732 | "\n", 733 | " pitch = (ss-2304) % 129\n", 734 | "\n", 735 | " song_f.append(['note', time, dur, channel, pitch, vel, patch ])\n", 736 | "\n", 737 | " patches = [0 if x==-1 else x for x in patches]\n", 738 | "\n", 739 | " detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f,\n", 740 | " output_signature = 'Monster Music Transformer',\n", 741 | " output_file_name = '/content/Monster-Music-Transformer-Seed-Composition',\n", 742 | " track_name='Project Los Angeles',\n", 743 | " list_of_MIDI_patches=patches\n", 744 | " )\n", 745 | "\n", 746 | " #=======================================================\n", 747 | "\n", 748 | " print('=' * 70)\n", 749 | " print('Composition stats:')\n", 750 | " print('Composition has', len(melody_chords2), 'notes')\n", 751 | " print('Composition has', len(melody_chords), 'tokens')\n", 752 | " print('Composition MIDI patches:', sorted(list(set([((y-2304) // 129) for y in melody_chords if 2304 <= y < 18945]))))\n", 753 | " print('=' * 70)\n", 754 | "\n", 755 | " print('Displaying resulting composition...')\n", 756 | " print('=' * 70)\n", 757 | "\n", 758 | " fname = '/content/Monster-Music-Transformer-Seed-Composition'\n", 759 | "\n", 760 | " if render_MIDI_to_audio:\n", 761 | " midi_audio = midi_to_colab_audio(fname + '.mid')\n", 762 | " display(Audio(midi_audio, rate=16000, normalize=False))\n", 763 | "\n", 764 | " TMIDIX.plot_ms_SONG(song_f, plot_title=fname)\n", 765 | "\n", 766 | "else:\n", 767 | " print('=' * 70)" 768 | ] 769 | }, 770 | { 771 | "cell_type": "markdown", 772 | "source": [ 773 | "# (CONTINUATION)" 774 | ], 775 | "metadata": { 776 | "id": "fmm3KjOtoVp9" 777 | } 778 | }, 779 | { 780 | "cell_type": "code", 781 | "execution_count": null, 782 | "metadata": { 783 | "id": "dkvXYwR_qSnx", 784 | "cellView": "form" 785 | }, 786 | "outputs": [], 787 | "source": [ 788 | "#@title Standard Continuation\n", 789 | "\n", 790 | "#@markdown Generation settings\n", 791 | "\n", 792 | "try_to_generate_outro = False #@param {type:\"boolean\"}\n", 793 | "number_of_prime_tokens = 7191 # @param {type:\"slider\", min:3, max:8190, step:3}\n", 794 | "number_of_tokens_to_generate = 504 # @param {type:\"slider\", min:30, max:8190, step:3}\n", 795 | "number_of_batches_to_generate = 4 #@param {type:\"slider\", min:1, max:16, step:1}\n", 796 | "temperature = 0.9 # @param {type:\"slider\", min:0.1, max:1, step:0.05}\n", 797 | "\n", 798 | "#@markdown Other settings\n", 799 | "include_prime_tokens_in_generated_output = False #@param {type:\"boolean\"}\n", 800 | "allow_model_to_stop_generation_if_needed = False #@param {type:\"boolean\"}\n", 801 | "render_MIDI_to_audio = True # @param {type:\"boolean\"}\n", 802 | "\n", 803 | "print('=' * 70)\n", 804 | "print('Monster Music Transformer Standard Continuation Model Generator')\n", 805 | "print('=' * 70)\n", 806 | "\n", 807 | "if allow_model_to_stop_generation_if_needed:\n", 808 | " min_stop_token = 19078\n", 809 | "else:\n", 810 | " min_stop_token = None\n", 811 | "\n", 812 | "outy = melody_chords[:number_of_prime_tokens]\n", 813 | "\n", 814 | "if try_to_generate_outro:\n", 815 | " outy.extend([18945])\n", 816 | "\n", 817 | "torch.cuda.empty_cache()\n", 818 | "\n", 819 | "inp = [outy] * number_of_batches_to_generate\n", 820 | "\n", 821 | "inp = torch.LongTensor(inp).cuda()\n", 822 | "\n", 823 | "with ctx:\n", 824 | " out = model.generate(inp,\n", 825 | " number_of_tokens_to_generate,\n", 826 | " temperature=temperature,\n", 827 | " return_prime=include_prime_tokens_in_generated_output,\n", 828 | " eos_token=min_stop_token,\n", 829 | " verbose=True)\n", 830 | "\n", 831 | "out0 = out.tolist()\n", 832 | "\n", 833 | "torch.cuda.empty_cache()\n", 834 | "\n", 835 | "print('=' * 70)\n", 836 | "print('Done!')\n", 837 | "print('=' * 70)\n", 838 | "\n", 839 | "#======================================================================\n", 840 | "print('Rendering results...')\n", 841 | "\n", 842 | "for i in range(number_of_batches_to_generate):\n", 843 | "\n", 844 | " print('=' * 70)\n", 845 | " print('Batch #', i)\n", 846 | " print('=' * 70)\n", 847 | "\n", 848 | " out1 = out0[i]\n", 849 | "\n", 850 | " print('Sample INTs', out1[:12])\n", 851 | " print('=' * 70)\n", 852 | "\n", 853 | " if len(out) != 0:\n", 854 | "\n", 855 | " song = out1\n", 856 | " song_f = []\n", 857 | "\n", 858 | " time = 0\n", 859 | " dur = 0\n", 860 | " vel = 90\n", 861 | " pitch = 0\n", 862 | " channel = 0\n", 863 | "\n", 864 | " patches = [-1] * 16\n", 865 | "\n", 866 | " channels = [0] * 16\n", 867 | " channels[9] = 1\n", 868 | "\n", 869 | " for ss in song:\n", 870 | "\n", 871 | " if 0 <= ss < 256:\n", 872 | "\n", 873 | " time += ss * 16\n", 874 | "\n", 875 | " if 256 <= ss < 2304:\n", 876 | "\n", 877 | " dur = ((ss-256) // 8) * 16\n", 878 | " vel = (((ss-256) % 8)+1) * 15\n", 879 | "\n", 880 | " if 2304 <= ss < 18945:\n", 881 | "\n", 882 | " patch = (ss-2304) // 129\n", 883 | "\n", 884 | " if patch < 128:\n", 885 | "\n", 886 | " if patch not in patches:\n", 887 | " if 0 in channels:\n", 888 | " cha = channels.index(0)\n", 889 | " channels[cha] = 1\n", 890 | " else:\n", 891 | " cha = 15\n", 892 | "\n", 893 | " patches[cha] = patch\n", 894 | " channel = patches.index(patch)\n", 895 | " else:\n", 896 | " channel = patches.index(patch)\n", 897 | "\n", 898 | " if patch == 128:\n", 899 | " channel = 9\n", 900 | "\n", 901 | " pitch = (ss-2304) % 129\n", 902 | "\n", 903 | " song_f.append(['note', time, dur, channel, pitch, vel, patch ])\n", 904 | "\n", 905 | " patches = [0 if x==-1 else x for x in patches]\n", 906 | "\n", 907 | " detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(song_f,\n", 908 | " output_signature = 'Monster Music Transformer',\n", 909 | " output_file_name = '/content/Monster-Music-Transformer-Music-Composition_'+str(i),\n", 910 | " track_name='Project Los Angeles',\n", 911 | " list_of_MIDI_patches=patches\n", 912 | " )\n", 913 | " print('=' * 70)\n", 914 | " print('Displaying resulting composition...')\n", 915 | " print('=' * 70)\n", 916 | "\n", 917 | " fname = '/content/Monster-Music-Transformer-Music-Composition_'+str(i)\n", 918 | "\n", 919 | " if render_MIDI_to_audio:\n", 920 | " midi_audio = midi_to_colab_audio(fname + '.mid')\n", 921 | " display(Audio(midi_audio, rate=16000, normalize=False))\n", 922 | "\n", 923 | " TMIDIX.plot_ms_SONG(song_f, plot_title=fname)" 924 | ] 925 | }, 926 | { 927 | "cell_type": "markdown", 928 | "source": [ 929 | "# Congrats! You did it! :)" 930 | ], 931 | "metadata": { 932 | "id": "eoWDEy6CwDr6" 933 | } 934 | } 935 | ], 936 | "metadata": { 937 | "accelerator": "GPU", 938 | "colab": { 939 | "private_outputs": true, 940 | "provenance": [], 941 | "gpuType": "A100", 942 | "gpuClass": "premium", 943 | "machine_shape": "hm" 944 | }, 945 | "kernelspec": { 946 | "display_name": "Python 3", 947 | "name": "python3" 948 | }, 949 | "language_info": { 950 | "codemirror_mode": { 951 | "name": "ipython", 952 | "version": 3 953 | }, 954 | "file_extension": ".py", 955 | "mimetype": "text/x-python", 956 | "name": "python", 957 | "nbconvert_exporter": "python", 958 | "pygments_lexer": "ipython3", 959 | "version": "3.9.13" 960 | } 961 | }, 962 | "nbformat": 4, 963 | "nbformat_minor": 0 964 | } -------------------------------------------------------------------------------- /Monster_MIDI_Dataset_GPU_Search_and_Filter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "gradient": { 7 | "editing": false, 8 | "id": "ac5a4cf0-d9d2-47b5-9633-b53f8d99a4d2", 9 | "kernelId": "" 10 | }, 11 | "id": "SiTIpPjArIyr" 12 | }, 13 | "source": [ 14 | "# Monster MIDI Dataset GPU Search and Filter (ver. 4.0)\n", 15 | "\n", 16 | "***\n", 17 | "\n", 18 | "Powered by tegridy-tools: https://github.com/asigalov61/tegridy-tools\n", 19 | "\n", 20 | "***\n", 21 | "\n", 22 | "#### Project Los Angeles\n", 23 | "\n", 24 | "#### Tegridy Code 2024\n", 25 | "\n", 26 | "***" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "# (GPU CHECK)" 33 | ], 34 | "metadata": { 35 | "id": "0rMwKVc9FFRw" 36 | } 37 | }, 38 | { 39 | "cell_type": "code", 40 | "source": [ 41 | "# @title NVIDIA GPU Check\n", 42 | "!nvidia-smi" 43 | ], 44 | "metadata": { 45 | "cellView": "form", 46 | "id": "dVSaUaEZFIip" 47 | }, 48 | "execution_count": null, 49 | "outputs": [] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "source": [ 54 | "# (SETUP ENVIRONMENT)" 55 | ], 56 | "metadata": { 57 | "id": "YRTt3Hx0FQeu" 58 | } 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": { 64 | "cellView": "form", 65 | "gradient": { 66 | "editing": false, 67 | "id": "a1a45a91-d909-4fd4-b67a-5e16b971d179", 68 | "kernelId": "" 69 | }, 70 | "id": "fX12Yquyuihc" 71 | }, 72 | "outputs": [], 73 | "source": [ 74 | "#@title Install all dependencies (run only once per session)\n", 75 | "\n", 76 | "!git clone --depth 1 https://github.com/asigalov61/Monster-MIDI-Dataset\n", 77 | "!pip install huggingface_hub\n", 78 | "!pip install hf_transfer" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": { 85 | "gradient": { 86 | "editing": false, 87 | "id": "b8207b76-9514-4c07-95db-95a4742e52c5", 88 | "kernelId": "" 89 | }, 90 | "id": "z7n9vnKmug1J", 91 | "cellView": "form" 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "#@title Import all needed modules\n", 96 | "\n", 97 | "print('Loading core modules... Please wait...')\n", 98 | "\n", 99 | "import os\n", 100 | "import copy\n", 101 | "from collections import Counter\n", 102 | "import random\n", 103 | "import pickle\n", 104 | "from tqdm import tqdm\n", 105 | "import pprint\n", 106 | "import statistics\n", 107 | "import shutil\n", 108 | "\n", 109 | "os.environ[\"HF_HUB_ENABLE_HF_TRANSFER\"] = \"1\"\n", 110 | "\n", 111 | "try:\n", 112 | " import locale\n", 113 | " locale.getpreferredencoding = lambda: \"UTF-8\"\n", 114 | "\n", 115 | "except:\n", 116 | " pass\n", 117 | "\n", 118 | "try:\n", 119 | " import cupy as cp\n", 120 | "\n", 121 | "except:\n", 122 | " import numpy as cp\n", 123 | "\n", 124 | "from huggingface_hub import hf_hub_download\n", 125 | "\n", 126 | "try:\n", 127 | " from google.colab import files\n", 128 | "\n", 129 | "except:\n", 130 | " pass\n", 131 | "\n", 132 | "print('Loading TMIDIX module...')\n", 133 | "os.chdir('/content/Monster-MIDI-Dataset')\n", 134 | "\n", 135 | "import TMIDIX\n", 136 | "\n", 137 | "os.chdir('/content/')\n", 138 | "\n", 139 | "print('Creating IO dirs... Please wait...')\n", 140 | "\n", 141 | "if not os.path.exists('/content/Master-MIDI-Dataset'):\n", 142 | " os.makedirs('/content/Master-MIDI-Dataset')\n", 143 | "\n", 144 | "if not os.path.exists('/content/Output-MIDI-Dataset'):\n", 145 | " os.makedirs('/content/Output-MIDI-Dataset')\n", 146 | "\n", 147 | "print('Done!')\n", 148 | "print('Enjoy! :)')" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "metadata": { 154 | "gradient": { 155 | "editing": false, 156 | "id": "20b8698a-0b4e-4fdb-ae49-24d063782e77", 157 | "kernelId": "" 158 | }, 159 | "id": "ObPxlEutsQBj" 160 | }, 161 | "source": [ 162 | "# (DOWNLOAD AND UNZIP MAIN MIDI DATASET)" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "source": [ 168 | "#@title Download Monster MIDI Dataset\n", 169 | "print('=' * 70)\n", 170 | "print('Downloading Monster MIDI Dataset...Please wait...')\n", 171 | "print('=' * 70)\n", 172 | "\n", 173 | "hf_hub_download(repo_id='projectlosangeles/Monster-MIDI-Dataset',\n", 174 | " filename='Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip',\n", 175 | " repo_type=\"dataset\",\n", 176 | " local_dir='/content/Main-MIDI-Dataset'\n", 177 | " )\n", 178 | "print('=' * 70)\n", 179 | "print('Done! Enjoy! :)')\n", 180 | "print('=' * 70)" 181 | ], 182 | "metadata": { 183 | "cellView": "form", 184 | "id": "7aItlhq9cRxZ" 185 | }, 186 | "execution_count": null, 187 | "outputs": [] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "source": [ 192 | "#@title Unzip Monster MIDI Dataset\n", 193 | "%cd /content/Main-MIDI-Dataset/\n", 194 | "\n", 195 | "print('=' * 70)\n", 196 | "print('Unzipping Monster MIDI Dataset...Please wait...')\n", 197 | "!unzip 'Monster-MIDI-Dataset-Ver-1-0-CC-BY-NC-SA.zip' > /dev/null\n", 198 | "print('=' * 70)\n", 199 | "\n", 200 | "print('Done! Enjoy! :)')\n", 201 | "print('=' * 70)\n", 202 | "%cd /content/" 203 | ], 204 | "metadata": { 205 | "cellView": "form", 206 | "id": "zMF4vdMNDYYg" 207 | }, 208 | "execution_count": null, 209 | "outputs": [] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "source": [ 214 | "# (CREATE MAIN MIDI DATASET FILES LIST)" 215 | ], 216 | "metadata": { 217 | "id": "GE0hPlAEjCrs" 218 | } 219 | }, 220 | { 221 | "cell_type": "code", 222 | "source": [ 223 | "#@title Create Monster MIDI Dataset files list\n", 224 | "print('=' * 70)\n", 225 | "print('Creating dataset files list...')\n", 226 | "dataset_addr = \"/content/Main-MIDI-Dataset/MIDIs\"\n", 227 | "\n", 228 | "# os.chdir(dataset_addr)\n", 229 | "filez = list()\n", 230 | "for (dirpath, dirnames, filenames) in os.walk(dataset_addr):\n", 231 | " filez += [os.path.join(dirpath, file) for file in filenames]\n", 232 | "\n", 233 | "if filez == []:\n", 234 | " print('Could not find any MIDI files. Please check Dataset dir...')\n", 235 | " print('=' * 70)\n", 236 | "\n", 237 | "print('=' * 70)\n", 238 | "print('Randomizing file list...')\n", 239 | "random.shuffle(filez)\n", 240 | "print('=' * 70)\n", 241 | "\n", 242 | "LAMD_files_list = []\n", 243 | "\n", 244 | "for f in tqdm(filez):\n", 245 | " LAMD_files_list.append([f.split('/')[-1].split('.mid')[0], f])\n", 246 | "print('Done!')\n", 247 | "print('=' * 70)" 248 | ], 249 | "metadata": { 250 | "cellView": "form", 251 | "id": "btrUDk8MDfdw" 252 | }, 253 | "execution_count": null, 254 | "outputs": [] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "source": [ 259 | "# (SIGNATURES SEARCH)" 260 | ], 261 | "metadata": { 262 | "id": "iaeqXuIHI0_T" 263 | } 264 | }, 265 | { 266 | "cell_type": "code", 267 | "source": [ 268 | "# @title Load Monster MIDI Dataset Signatures Data\n", 269 | "\n", 270 | "print('=' * 70)\n", 271 | "print('Loading Monster MIDI Dataset Signatures Data...')\n", 272 | "sigs_data = pickle.load(open('/content/Main-MIDI-Dataset/SIGNATURES_DATA/MONSTER_SIGNATURES_DATA.pickle', 'rb'))\n", 273 | "print('=' * 70)\n", 274 | "\n", 275 | "print('Prepping signatures...')\n", 276 | "print('=' * 70)\n", 277 | "\n", 278 | "random.shuffle(sigs_data)\n", 279 | "\n", 280 | "signatures_file_names = []\n", 281 | "sigs_matrixes = [ [0]*(len(TMIDIX.ALL_CHORDS_SORTED)+256) for i in range(len(sigs_data))]\n", 282 | "\n", 283 | "idx = 0\n", 284 | "for s in tqdm(sigs_data):\n", 285 | "\n", 286 | " signatures_file_names.append(s[0])\n", 287 | "\n", 288 | " for ss in s[1]:\n", 289 | " sigs_matrixes[idx][ss[0]] = ss[1]\n", 290 | "\n", 291 | " idx += 1\n", 292 | "\n", 293 | "print('=' * 70)\n", 294 | "print('Loading signatures...')\n", 295 | "print('=' * 70)\n", 296 | "\n", 297 | "signatures_data_full = cp.array(sigs_matrixes)\n", 298 | "\n", 299 | "print('Done!')\n", 300 | "print('=' * 70)" 301 | ], 302 | "metadata": { 303 | "id": "Mv-pjxbrIqi2", 304 | "cellView": "form" 305 | }, 306 | "execution_count": null, 307 | "outputs": [] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "source": [ 312 | "#@title Monster MIDI Dataset Search and Filter\n", 313 | "\n", 314 | "#@markdown DO NOT FORGET TO UPLOAD YOUR MASTER DATASET TO \"Master-MIDI-Dataset\" FOLDER\n", 315 | "\n", 316 | "#@markdown NOTE: You can stop the search at any time to render partial results\n", 317 | "\n", 318 | "number_of_top_matches_MIDIs_to_collect = 30 #@param {type:\"slider\", min:5, max:50, step:1}\n", 319 | "search_matching_type = \"Ratios\" # @param [\"Ratios\", \"Distances\", \"Correlations\"]\n", 320 | "maximum_match_ratio_to_search_for = 1 #@param {type:\"slider\", min:0, max:1, step:0.001}\n", 321 | "match_results_weight = 2 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 322 | "match_lengths_weight = 1 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 323 | "match_counts_weight = 1 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 324 | "distances_norm_order = 3 # @param {type:\"slider\", min:1, max:10, step:1}\n", 325 | "epsilon = 0.5 # @param {type:\"slider\", min:0.001, max:1, step:0.001}\n", 326 | "match_drums = False # @param {type:\"boolean\"}\n", 327 | "\n", 328 | "print('=' * 70)\n", 329 | "print('Monster MIDI Dataset GPU Search and Filter')\n", 330 | "print('=' * 70)\n", 331 | "\n", 332 | "###########\n", 333 | "\n", 334 | "search_settings_string = ''\n", 335 | "\n", 336 | "if match_drums:\n", 337 | " search_settings_string += 'Chords_Drums'\n", 338 | "else:\n", 339 | " search_settings_string += 'Chords'\n", 340 | "\n", 341 | "if search_matching_type == 'Distances':\n", 342 | " search_settings_string += '_O_' + str(distances_norm_order)\n", 343 | "\n", 344 | "search_settings_string += '_W_'\n", 345 | "search_settings_string += str(match_results_weight) + '_'\n", 346 | "search_settings_string += str(match_lengths_weight) + '_'\n", 347 | "search_settings_string += str(match_counts_weight)\n", 348 | "\n", 349 | "search_settings_string += '_E_' + str(epsilon)\n", 350 | "\n", 351 | "###########\n", 352 | "\n", 353 | "print('Loading MIDI files...')\n", 354 | "print('This may take a while on a large dataset in particular.')\n", 355 | "\n", 356 | "dataset_addr = \"/content/Master-MIDI-Dataset\"\n", 357 | "\n", 358 | "filez = list()\n", 359 | "\n", 360 | "for (dirpath, dirnames, filenames) in os.walk(dataset_addr):\n", 361 | " for file in filenames:\n", 362 | " if file.endswith(('.mid', '.midi', '.kar')):\n", 363 | " filez.append(os.path.join(dirpath, file))\n", 364 | "\n", 365 | "print('=' * 70)\n", 366 | "\n", 367 | "if filez:\n", 368 | "\n", 369 | " print('Randomizing file list...')\n", 370 | " random.shuffle(filez)\n", 371 | " print('=' * 70)\n", 372 | "\n", 373 | " ###################\n", 374 | "\n", 375 | " if not os.path.exists('/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string):\n", 376 | " os.makedirs('/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string)\n", 377 | "\n", 378 | " ###################\n", 379 | "\n", 380 | " input_files_count = 0\n", 381 | " files_count = 0\n", 382 | "\n", 383 | " for f in filez:\n", 384 | " try:\n", 385 | "\n", 386 | " input_files_count += 1\n", 387 | "\n", 388 | " fn = os.path.basename(f)\n", 389 | " fn1 = os.path.splitext(fn)[0]\n", 390 | " ext = os.path.splitext(f)[1]\n", 391 | "\n", 392 | " print('Processing MIDI File #', files_count+1, 'out of', len(filez))\n", 393 | " print('MIDI file name', fn)\n", 394 | " print('-' * 70)\n", 395 | "\n", 396 | " #=======================================================\n", 397 | "\n", 398 | " raw_score = TMIDIX.midi2single_track_ms_score(f)\n", 399 | " escore = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0]\n", 400 | "\n", 401 | " escore = TMIDIX.augment_enhanced_score_notes(escore)\n", 402 | "\n", 403 | " drums_offset = len(TMIDIX.ALL_CHORDS_SORTED) + 128\n", 404 | "\n", 405 | " src_sigs = []\n", 406 | "\n", 407 | " for i in range(-6, 6):\n", 408 | "\n", 409 | " escore_copy = copy.deepcopy(escore)\n", 410 | "\n", 411 | " for e in escore_copy:\n", 412 | " e[4] += i\n", 413 | "\n", 414 | " cscore = TMIDIX.chordify_score([1000, escore_copy])\n", 415 | "\n", 416 | " sig = []\n", 417 | " dsig = []\n", 418 | "\n", 419 | " for c in cscore:\n", 420 | " all_pitches = [e[4] if e[3] != 9 else e[4]+128 for e in c]\n", 421 | " chord = sorted(set(all_pitches))\n", 422 | "\n", 423 | " pitches = sorted([p for p in chord if p < 128], reverse=True)\n", 424 | " drums = [(d+drums_offset)-128 for d in chord if d > 127]\n", 425 | "\n", 426 | " if pitches:\n", 427 | " if len(pitches) > 1:\n", 428 | " tones_chord = sorted(set([p % 12 for p in pitches]))\n", 429 | "\n", 430 | " try:\n", 431 | " sig_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord) + 128\n", 432 | " except:\n", 433 | " checked_tones_chord = TMIDIX.check_and_fix_tones_chord(tones_chord)\n", 434 | " sig_token = TMIDIX.ALL_CHORDS_SORTED.index(checked_tones_chord) + 128\n", 435 | "\n", 436 | " elif len(pitches) == 1:\n", 437 | " sig_token = pitches[0]\n", 438 | "\n", 439 | " sig.append(sig_token)\n", 440 | "\n", 441 | " if drums:\n", 442 | " dsig.extend(drums)\n", 443 | "\n", 444 | " sig_p = dict.fromkeys(sig+dsig, 0)\n", 445 | " for item in sig+dsig:\n", 446 | " sig_p[item] += 1\n", 447 | "\n", 448 | " fsig = [list(v) for v in sig_p.items()]\n", 449 | "\n", 450 | " src_sig_mat = [0] * (len(TMIDIX.ALL_CHORDS_SORTED)+256)\n", 451 | "\n", 452 | " for s in fsig:\n", 453 | "\n", 454 | " src_sig_mat[s[0]] = s[1]\n", 455 | "\n", 456 | " src_sigs.append(src_sig_mat)\n", 457 | "\n", 458 | " src_signatures = cp.stack(cp.array(src_sigs))\n", 459 | "\n", 460 | " if not match_drums:\n", 461 | " src_signatures = src_signatures[:,:drums_offset]\n", 462 | " signatures_data = signatures_data_full[:,:drums_offset]\n", 463 | " else:\n", 464 | " signatures_data = signatures_data_full\n", 465 | "\n", 466 | " #=======================================================\n", 467 | "\n", 468 | " print('Searching for matches...Please wait...')\n", 469 | " print('-' * 70)\n", 470 | "\n", 471 | " lower_threshold = 0.0\n", 472 | " upper_threshold = maximum_match_ratio_to_search_for\n", 473 | " filter_size = number_of_top_matches_MIDIs_to_collect\n", 474 | "\n", 475 | " final_ratios = []\n", 476 | "\n", 477 | " avg_idxs = []\n", 478 | "\n", 479 | " all_filtered_means = []\n", 480 | " all_filtered_idxs = []\n", 481 | " all_filtered_tvs = []\n", 482 | "\n", 483 | " tv_idx = -6\n", 484 | "\n", 485 | " for target_sig in tqdm(src_signatures):\n", 486 | "\n", 487 | " comps_lengths = cp.vstack((cp.repeat(cp.sum(target_sig != 0), signatures_data.shape[0]), cp.sum(signatures_data != 0, axis=1)))\n", 488 | " comps_lengths_ratios = cp.divide(cp.min(comps_lengths, axis=0), cp.max(comps_lengths, axis=0))\n", 489 | "\n", 490 | " comps_counts_sums = cp.vstack((cp.repeat(cp.sum(target_sig), signatures_data.shape[0]), cp.sum(signatures_data, axis=1)))\n", 491 | " comps_counts_sums_ratios = cp.divide(cp.min(comps_counts_sums, axis=0), cp.max(comps_counts_sums, axis=0))\n", 492 | "\n", 493 | " if search_matching_type == 'Ratios':\n", 494 | "\n", 495 | " ratios = cp.where(target_sig != 0, cp.divide(cp.minimum(signatures_data, target_sig), cp.maximum(signatures_data, target_sig)), epsilon)\n", 496 | " results = cp.mean(ratios, axis=1)\n", 497 | "\n", 498 | " elif search_matching_type == 'Distances':\n", 499 | "\n", 500 | " distances = cp.power(cp.sum(cp.power(cp.abs(signatures_data - target_sig), distances_norm_order), axis=1), 1 / distances_norm_order)\n", 501 | "\n", 502 | " distances_mean = cp.mean(distances)\n", 503 | " distances_std = cp.std(distances)\n", 504 | "\n", 505 | " results = 1 - cp.divide((distances - distances_mean), distances_std)\n", 506 | "\n", 507 | " elif search_matching_type == 'Correlations':\n", 508 | "\n", 509 | " main_array_mean = cp.mean(signatures_data, axis=1, keepdims=True)\n", 510 | " main_array_std = cp.std(signatures_data, axis=1, keepdims=True)\n", 511 | " target_array_mean = cp.mean(target_sig)\n", 512 | " target_array_std = cp.std(target_sig)\n", 513 | "\n", 514 | " signatures_data_normalized = cp.where(main_array_std != 0, (signatures_data - main_array_mean) / main_array_std, epsilon)\n", 515 | " target_sig_normalized = cp.where(target_array_std != 0, (target_sig - target_array_mean) / target_array_std, epsilon)\n", 516 | "\n", 517 | " correlations = cp.divide(cp.einsum('ij,j->i', signatures_data_normalized, target_sig_normalized), (signatures_data.shape[1] - 1))\n", 518 | " scaled_correlations = cp.divide(correlations, cp.sqrt(cp.sum(correlations**2)))\n", 519 | " exp = cp.exp(scaled_correlations - cp.max(scaled_correlations))\n", 520 | " results = cp.multiply(cp.divide(exp, cp.sum(exp)), 1e5)\n", 521 | "\n", 522 | " results_weight = match_results_weight\n", 523 | " comp_lengths_weight = match_lengths_weight\n", 524 | " comp_counts_sums_weight = match_counts_weight\n", 525 | "\n", 526 | " results = cp.divide(cp.add(cp.add(results_weight, comp_lengths_weight), comp_counts_sums_weight), cp.add(cp.add(cp.divide(results_weight, cp.where(results !=0, results, epsilon)), cp.divide(comp_lengths_weight, cp.where(comps_lengths_ratios !=0, comps_lengths_ratios, epsilon))), cp.divide(comp_counts_sums_weight, cp.where(comps_counts_sums_ratios !=0, comps_counts_sums_ratios, epsilon))))\n", 527 | "\n", 528 | " unique_means = cp.unique(results)\n", 529 | " sorted_means = cp.sort(unique_means)[::-1]\n", 530 | "\n", 531 | " filtered_means = sorted_means[(sorted_means >= lower_threshold) & (sorted_means <= upper_threshold)][:filter_size]\n", 532 | "\n", 533 | " filtered_idxs = cp.nonzero(cp.in1d(results, filtered_means))[0]\n", 534 | "\n", 535 | " all_filtered_means.extend(results[filtered_idxs].tolist())\n", 536 | "\n", 537 | " all_filtered_idxs.extend(filtered_idxs.tolist())\n", 538 | "\n", 539 | " filtered_tvs = [tv_idx] * filtered_idxs.shape[0]\n", 540 | "\n", 541 | " all_filtered_tvs.extend(filtered_tvs)\n", 542 | "\n", 543 | " tv_idx += 1\n", 544 | "\n", 545 | " f_results = sorted(zip(all_filtered_means, all_filtered_idxs, all_filtered_tvs), key=lambda x: x[0], reverse=True)\n", 546 | "\n", 547 | " triplet_dict = {}\n", 548 | "\n", 549 | " for triplet in f_results:\n", 550 | "\n", 551 | " if triplet[0] not in triplet_dict:\n", 552 | " triplet_dict[triplet[0]] = triplet\n", 553 | " else:\n", 554 | " if triplet[2] == 0:\n", 555 | " triplet_dict[triplet[0]] = triplet\n", 556 | "\n", 557 | " filtered_results = list(triplet_dict.values())[:filter_size]\n", 558 | "\n", 559 | " #=======================================================\n", 560 | "\n", 561 | " print('Done!')\n", 562 | " print('-' * 70)\n", 563 | " print('Max match ratio:', filtered_results[0][0])\n", 564 | " print('Max match transpose value:', filtered_results[0][2])\n", 565 | " print('Max match signature index:', filtered_results[0][1])\n", 566 | " print('Max match file name:', signatures_file_names[filtered_results[0][1]])\n", 567 | " print('-' * 70)\n", 568 | " print('Copying max ratios MIDIs...')\n", 569 | "\n", 570 | " for fr in filtered_results:\n", 571 | "\n", 572 | " max_ratio_index = fr[1]\n", 573 | "\n", 574 | " ffn = signatures_file_names[fr[1]]\n", 575 | " ffn_idx = [y[0] for y in LAMD_files_list].index(ffn)\n", 576 | "\n", 577 | " ff = LAMD_files_list[ffn_idx][1]\n", 578 | "\n", 579 | " #=======================================================\n", 580 | "\n", 581 | " dir_str = str(fn1)\n", 582 | " copy_path = '/content/Output-MIDI-Dataset/'+search_matching_type+'_'+search_settings_string+'/'+dir_str\n", 583 | " if not os.path.exists(copy_path):\n", 584 | " os.mkdir(copy_path)\n", 585 | "\n", 586 | " fff = str(fr[0] * 100) + '_' + str(fr[2]) + '_' + ffn + '.mid'\n", 587 | "\n", 588 | " shutil.copy2(ff, copy_path+'/'+fff)\n", 589 | "\n", 590 | " shutil.copy2(f, copy_path+'/'+fn)\n", 591 | "\n", 592 | " #======================================================='''\n", 593 | " print('Done!')\n", 594 | " print('=' * 70)\n", 595 | "\n", 596 | " #=======================================================\n", 597 | "\n", 598 | " # Processed files counter\n", 599 | " files_count += 1\n", 600 | "\n", 601 | " except KeyboardInterrupt:\n", 602 | " print('Quitting...')\n", 603 | " print('Total number of processed MIDI files', files_count)\n", 604 | " print('=' * 70)\n", 605 | " break\n", 606 | "\n", 607 | " except Exception as ex:\n", 608 | " print('WARNING !!!')\n", 609 | " print('=' * 70)\n", 610 | " print('Bad file:', f)\n", 611 | " print('Error detected:', ex)\n", 612 | " print('=' * 70)\n", 613 | " continue\n", 614 | "\n", 615 | " print('Total number of processed MIDI files', files_count)\n", 616 | " print('=' * 70)\n", 617 | "\n", 618 | "else:\n", 619 | " print('Could not find any MIDI files. Please check Dataset dir...')\n", 620 | " print('=' * 70)" 621 | ], 622 | "metadata": { 623 | "cellView": "form", 624 | "id": "M0JWCPzBGNvh" 625 | }, 626 | "execution_count": null, 627 | "outputs": [] 628 | }, 629 | { 630 | "cell_type": "markdown", 631 | "source": [ 632 | "# (KILO-CHORDS SEARCH)" 633 | ], 634 | "metadata": { 635 | "id": "ekjgrYRaiFE0" 636 | } 637 | }, 638 | { 639 | "cell_type": "code", 640 | "source": [ 641 | "#@title Load Monster MIDI Dataset Kilo-Chords Data\n", 642 | "search_matching_type = \"Full-Kilo-Chords\" # @param [\"Full-Kilo-Chords\", \"Unique-Kilo-Chords\"]\n", 643 | "\n", 644 | "print('=' * 70)\n", 645 | "print('Loading Monster MIDI Dataset Kilo-Chords Data...')\n", 646 | "kilo_chords = pickle.load(open('/content/Main-MIDI-Dataset/KILO_CHORDS_DATA/MONSTER_KILO_CHORDS_DATA.pickle', 'rb'))\n", 647 | "print('=' * 70)\n", 648 | "\n", 649 | "print('Prepping Kilo-Chords...')\n", 650 | "print('=' * 70)\n", 651 | "\n", 652 | "random.shuffle(kilo_chords)\n", 653 | "\n", 654 | "if search_matching_type == 'Full-Kilo-Chords':\n", 655 | "\n", 656 | " kilo_chords_file_names = []\n", 657 | "\n", 658 | " for kc in tqdm(kilo_chords):\n", 659 | "\n", 660 | " kilo_chords_file_names.append(kc[0])\n", 661 | "\n", 662 | " kcho = kc[1]\n", 663 | "\n", 664 | " kcho += [0] * (1000 - len(kcho))\n", 665 | "\n", 666 | " print('=' * 70)\n", 667 | " print('Loading Kilo-Chords...')\n", 668 | " print('=' * 70)\n", 669 | "\n", 670 | " kilo_chords_data = cp.array([kc[1] for kc in kilo_chords])\n", 671 | "\n", 672 | "else:\n", 673 | "\n", 674 | " kilo_chords_file_names = []\n", 675 | "\n", 676 | " kilo_chords_matrixes = [ [0]*(len(TMIDIX.ALL_CHORDS_SORTED)+128) for i in range(len(kilo_chords))]\n", 677 | "\n", 678 | " idx = 0\n", 679 | " for kc in tqdm(kilo_chords):\n", 680 | "\n", 681 | " kilo_chords_file_names.append(kc[0])\n", 682 | "\n", 683 | " for c in kc[1]:\n", 684 | " kilo_chords_matrixes[idx][c] += 1\n", 685 | "\n", 686 | " idx += 1\n", 687 | "\n", 688 | " print('=' * 70)\n", 689 | " print('Loading Kilo-Chords...')\n", 690 | " print('=' * 70)\n", 691 | "\n", 692 | " kilo_chords_data = cp.array(kilo_chords_matrixes)\n", 693 | "\n", 694 | "print('Done!')\n", 695 | "print('=' * 70)" 696 | ], 697 | "metadata": { 698 | "cellView": "form", 699 | "id": "YVyUHQiNiJcX" 700 | }, 701 | "execution_count": null, 702 | "outputs": [] 703 | }, 704 | { 705 | "cell_type": "code", 706 | "source": [ 707 | "#@title Monster MIDI Dataset Search and Filter\n", 708 | "\n", 709 | "#@markdown DO NOT FORGET TO UPLOAD YOUR MASTER DATASET TO \"Master-MIDI-Dataset\" FOLDER\n", 710 | "\n", 711 | "#@markdown NOTE: You can stop the search at any time to render partial results\n", 712 | "\n", 713 | "number_of_top_matches_MIDIs_to_collect = 30 #@param {type:\"slider\", min:5, max:50, step:1}\n", 714 | "maximum_match_ratio_to_search_for = 1 #@param {type:\"slider\", min:0, max:1, step:0.001}\n", 715 | "match_results_weight = 2 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 716 | "match_lengths_weight = 1 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 717 | "match_counts_weight = 1 # @param {type:\"slider\", min:0.1, max:3, step:0.1}\n", 718 | "epsilon = 0.5 # @param {type:\"slider\", min:0.001, max:1, step:0.001}\n", 719 | "\n", 720 | "print('=' * 70)\n", 721 | "print('Monster MIDI Dataset GPU Search and Filter')\n", 722 | "print('=' * 70)\n", 723 | "\n", 724 | "###########\n", 725 | "\n", 726 | "search_settings_string = ''\n", 727 | "\n", 728 | "search_settings_string += str(search_matching_type).replace('-', '_')\n", 729 | "\n", 730 | "search_settings_string += '_W_'\n", 731 | "search_settings_string += str(match_results_weight) + '_'\n", 732 | "search_settings_string += str(match_lengths_weight) + '_'\n", 733 | "search_settings_string += str(match_counts_weight)\n", 734 | "\n", 735 | "search_settings_string += '_E_' + str(epsilon)\n", 736 | "\n", 737 | "###########\n", 738 | "\n", 739 | "print('Loading MIDI files...')\n", 740 | "print('This may take a while on a large dataset in particular.')\n", 741 | "\n", 742 | "dataset_addr = \"/content/Master-MIDI-Dataset\"\n", 743 | "\n", 744 | "filez = list()\n", 745 | "\n", 746 | "for (dirpath, dirnames, filenames) in os.walk(dataset_addr):\n", 747 | " for file in filenames:\n", 748 | " if file.endswith(('.mid', '.midi', '.kar')):\n", 749 | " filez.append(os.path.join(dirpath, file))\n", 750 | "\n", 751 | "print('=' * 70)\n", 752 | "\n", 753 | "if filez:\n", 754 | "\n", 755 | " print('Randomizing file list...')\n", 756 | " random.shuffle(filez)\n", 757 | " print('=' * 70)\n", 758 | "\n", 759 | " ###################\n", 760 | "\n", 761 | " if not os.path.exists('/content/Output-MIDI-Dataset/'+search_settings_string):\n", 762 | " os.makedirs('/content/Output-MIDI-Dataset/'+search_settings_string)\n", 763 | "\n", 764 | " ###################\n", 765 | "\n", 766 | " input_files_count = 0\n", 767 | " files_count = 0\n", 768 | "\n", 769 | " for f in filez:\n", 770 | "\n", 771 | " try:\n", 772 | "\n", 773 | " input_files_count += 1\n", 774 | "\n", 775 | " fn = os.path.basename(f)\n", 776 | " fn1 = os.path.splitext(fn)[0]\n", 777 | " ext = os.path.splitext(f)[1]\n", 778 | "\n", 779 | " print('Processing MIDI File #', files_count+1, 'out of', len(filez))\n", 780 | " print('MIDI file name', fn)\n", 781 | " print('-' * 70)\n", 782 | "\n", 783 | " #=======================================================\n", 784 | "\n", 785 | " raw_score = TMIDIX.midi2single_track_ms_score(f)\n", 786 | " escore = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0]\n", 787 | "\n", 788 | " escore = TMIDIX.augment_enhanced_score_notes(escore)\n", 789 | "\n", 790 | " src_kilo_chords = []\n", 791 | "\n", 792 | " for i in range(-6, 6):\n", 793 | "\n", 794 | " escore_copy = copy.deepcopy(escore)\n", 795 | "\n", 796 | " for e in escore_copy:\n", 797 | " e[4] += i\n", 798 | "\n", 799 | " cscore = TMIDIX.chordify_score([1000, escore_copy])\n", 800 | "\n", 801 | " kilo_chord = []\n", 802 | "\n", 803 | " for c in cscore:\n", 804 | "\n", 805 | " pitches = sorted(set([p[4] for p in c if p[3] != 9]), reverse=True)\n", 806 | "\n", 807 | " if pitches:\n", 808 | " if len(pitches) > 1:\n", 809 | " tones_chord = sorted(set([p % 12 for p in pitches]))\n", 810 | "\n", 811 | " try:\n", 812 | " chord_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord) + 128\n", 813 | " except:\n", 814 | " checked_tones_chord = TMIDIX.check_and_fix_tones_chord(tones_chord)\n", 815 | " chord_token = TMIDIX.ALL_CHORDS_SORTED.index(checked_tones_chord) + 128\n", 816 | "\n", 817 | " elif len(pitches) == 1:\n", 818 | " chord_token = pitches[0]\n", 819 | "\n", 820 | " kilo_chord.append(chord_token)\n", 821 | "\n", 822 | " if search_matching_type == 'Full-Kilo-Chords':\n", 823 | "\n", 824 | " kilo_chord = kilo_chord[:1000]\n", 825 | " kilo_chord_matrix = kilo_chord + [0] * (1000 - len(kilo_chord))\n", 826 | "\n", 827 | " else:\n", 828 | "\n", 829 | " kilo_chord_matrix = [0] * (len(TMIDIX.ALL_CHORDS_SORTED)+128)\n", 830 | "\n", 831 | " for c in kilo_chord:\n", 832 | " kilo_chord_matrix[c] += 1\n", 833 | "\n", 834 | " src_kilo_chords.append(kilo_chord_matrix)\n", 835 | "\n", 836 | " src_kilo_chords = cp.stack(cp.array(src_kilo_chords))\n", 837 | "\n", 838 | " #=======================================================\n", 839 | "\n", 840 | " print('Searching for matches...Please wait...')\n", 841 | " print('-' * 70)\n", 842 | "\n", 843 | " lower_threshold = 0.0\n", 844 | " upper_threshold = maximum_match_ratio_to_search_for\n", 845 | " filter_size = number_of_top_matches_MIDIs_to_collect\n", 846 | "\n", 847 | " final_ratios = []\n", 848 | "\n", 849 | " avg_idxs = []\n", 850 | "\n", 851 | " all_filtered_means = []\n", 852 | " all_filtered_idxs = []\n", 853 | " all_filtered_tvs = []\n", 854 | "\n", 855 | " tv_idx = -6\n", 856 | "\n", 857 | " for target_kc in tqdm(src_kilo_chords):\n", 858 | "\n", 859 | " comps_lengths = cp.vstack((cp.repeat(cp.sum(target_kc != 0), kilo_chords_data.shape[0]), cp.sum(kilo_chords_data != 0, axis=1)))\n", 860 | " comps_lengths_ratios = cp.divide(cp.min(comps_lengths, axis=0), cp.max(comps_lengths, axis=0))\n", 861 | "\n", 862 | " comps_counts_sums = cp.vstack((cp.repeat(cp.sum(target_kc), kilo_chords_data.shape[0]), cp.sum(kilo_chords_data, axis=1)))\n", 863 | " comps_counts_sums_ratios = cp.divide(cp.min(comps_counts_sums, axis=0), cp.max(comps_counts_sums, axis=0))\n", 864 | "\n", 865 | " intersections = cp.where((kilo_chords_data == target_kc), kilo_chords_data, 0)\n", 866 | " results = cp.mean(intersections != 0, axis=1)\n", 867 | "\n", 868 | " results_weight = match_results_weight\n", 869 | " comp_lengths_weight = match_lengths_weight\n", 870 | " comp_counts_sums_weight = match_counts_weight\n", 871 | "\n", 872 | " results = cp.divide(cp.add(cp.add(results_weight, comp_lengths_weight), comp_counts_sums_weight), cp.add(cp.add(cp.divide(results_weight, cp.where(results !=0, results, epsilon)), cp.divide(comp_lengths_weight, cp.where(comps_lengths_ratios !=0, comps_lengths_ratios, epsilon))), cp.divide(comp_counts_sums_weight, cp.where(comps_counts_sums_ratios !=0, comps_counts_sums_ratios, epsilon))))\n", 873 | "\n", 874 | " unique_means = cp.unique(results)\n", 875 | " sorted_means = cp.sort(unique_means)[::-1]\n", 876 | "\n", 877 | " filtered_means = sorted_means[(sorted_means >= lower_threshold) & (sorted_means <= upper_threshold)][:filter_size]\n", 878 | "\n", 879 | " filtered_idxs = cp.nonzero(cp.in1d(results, filtered_means))[0]\n", 880 | "\n", 881 | " all_filtered_means.extend(results[filtered_idxs].tolist())\n", 882 | "\n", 883 | " all_filtered_idxs.extend(filtered_idxs.tolist())\n", 884 | "\n", 885 | " filtered_tvs = [tv_idx] * filtered_idxs.shape[0]\n", 886 | "\n", 887 | " all_filtered_tvs.extend(filtered_tvs)\n", 888 | "\n", 889 | " tv_idx += 1\n", 890 | "\n", 891 | " f_results = sorted(zip(all_filtered_means, all_filtered_idxs, all_filtered_tvs), key=lambda x: x[0], reverse=True)\n", 892 | "\n", 893 | " triplet_dict = {}\n", 894 | "\n", 895 | " for triplet in f_results:\n", 896 | "\n", 897 | " if triplet[0] not in triplet_dict:\n", 898 | " triplet_dict[triplet[0]] = triplet\n", 899 | " else:\n", 900 | " if triplet[2] == 0:\n", 901 | " triplet_dict[triplet[0]] = triplet\n", 902 | "\n", 903 | " filtered_results = list(triplet_dict.values())[:filter_size]\n", 904 | "\n", 905 | " #=======================================================\n", 906 | "\n", 907 | " print('Done!')\n", 908 | " print('-' * 70)\n", 909 | " print('Max match ratio:', filtered_results[0][0])\n", 910 | " print('Max match transpose value:', filtered_results[0][2])\n", 911 | " print('Max match signature index:', filtered_results[0][1])\n", 912 | " print('Max match file name:', kilo_chords_file_names[filtered_results[0][1]])\n", 913 | " print('-' * 70)\n", 914 | " print('Copying max ratios MIDIs...')\n", 915 | "\n", 916 | " for fr in filtered_results:\n", 917 | "\n", 918 | " max_ratio_index = fr[1]\n", 919 | "\n", 920 | " ffn = kilo_chords_file_names[fr[1]]\n", 921 | " ffn_idx = [y[0] for y in LAMD_files_list].index(ffn)\n", 922 | "\n", 923 | " ff = LAMD_files_list[ffn_idx][1]\n", 924 | "\n", 925 | " #=======================================================\n", 926 | "\n", 927 | " dir_str = str(fn1)\n", 928 | " copy_path = '/content/Output-MIDI-Dataset/'+search_settings_string+'/'+dir_str\n", 929 | " if not os.path.exists(copy_path):\n", 930 | " os.mkdir(copy_path)\n", 931 | "\n", 932 | " fff = str(fr[0] * 100) + '_' + str(fr[2]) + '_' + ffn + '.mid'\n", 933 | "\n", 934 | " shutil.copy2(ff, copy_path+'/'+fff)\n", 935 | "\n", 936 | " shutil.copy2(f, copy_path+'/'+fn)\n", 937 | "\n", 938 | " #======================================================='''\n", 939 | " print('Done!')\n", 940 | " print('=' * 70)\n", 941 | "\n", 942 | " #=======================================================\n", 943 | "\n", 944 | " # Processed files counter\n", 945 | " files_count += 1\n", 946 | "\n", 947 | " except KeyboardInterrupt:\n", 948 | " print('Quitting...')\n", 949 | " print('Total number of processed MIDI files', files_count)\n", 950 | " print('=' * 70)\n", 951 | " break\n", 952 | "\n", 953 | " except Exception as ex:\n", 954 | " print('WARNING !!!')\n", 955 | " print('=' * 70)\n", 956 | " print('Bad file:', f)\n", 957 | " print('Error detected:', ex)\n", 958 | " print('=' * 70)\n", 959 | " continue\n", 960 | "\n", 961 | " print('Total number of processed MIDI files', files_count)\n", 962 | " print('=' * 70)\n", 963 | "\n", 964 | "else:\n", 965 | " print('Could not find any MIDI files. Please check Dataset dir...')\n", 966 | " print('=' * 70)" 967 | ], 968 | "metadata": { 969 | "cellView": "form", 970 | "id": "fhgpI31piWiX" 971 | }, 972 | "execution_count": null, 973 | "outputs": [] 974 | }, 975 | { 976 | "cell_type": "markdown", 977 | "source": [ 978 | "# (DOWNLOAD SEARCH RESULTS)" 979 | ], 980 | "metadata": { 981 | "id": "7Lyy0vjV0dlI" 982 | } 983 | }, 984 | { 985 | "cell_type": "code", 986 | "source": [ 987 | "#@title Zip and download all search results\n", 988 | "\n", 989 | "print('=' * 70)\n", 990 | "\n", 991 | "try:\n", 992 | " os.remove('Monster_MIDI_Dataset_Search_Results.zip')\n", 993 | "except OSError:\n", 994 | " pass\n", 995 | "\n", 996 | "print('Zipping... Please wait...')\n", 997 | "print('=' * 70)\n", 998 | "\n", 999 | "%cd /content/Output-MIDI-Dataset/\n", 1000 | "!zip -r Monster_MIDI_Dataset_Search_Results.zip *\n", 1001 | "%cd /content/\n", 1002 | "\n", 1003 | "print('=' * 70)\n", 1004 | "print('Done!')\n", 1005 | "print('=' * 70)\n", 1006 | "\n", 1007 | "print('Downloading final zip file...')\n", 1008 | "print('=' * 70)\n", 1009 | "\n", 1010 | "files.download('/content/Output-MIDI-Dataset/Monster_MIDI_Dataset_Search_Results.zip')\n", 1011 | "\n", 1012 | "print('Done!')\n", 1013 | "print('=' * 70)" 1014 | ], 1015 | "metadata": { 1016 | "cellView": "form", 1017 | "id": "1psdj0RJ0aWH" 1018 | }, 1019 | "execution_count": null, 1020 | "outputs": [] 1021 | }, 1022 | { 1023 | "cell_type": "code", 1024 | "source": [ 1025 | "# @title Delete search results directory and files\n", 1026 | "\n", 1027 | "#@markdown WARNING: This can't be undone so make sure you downloaded the search results first\n", 1028 | "\n", 1029 | "print('=' * 70)\n", 1030 | "print('Deleting... Please wait...')\n", 1031 | "print('=' * 70)\n", 1032 | "\n", 1033 | "!rm -rf /content/Output-MIDI-Dataset\n", 1034 | "print('Done!')\n", 1035 | "print('=' * 70)" 1036 | ], 1037 | "metadata": { 1038 | "cellView": "form", 1039 | "id": "z3B-YHIz0jDt" 1040 | }, 1041 | "execution_count": null, 1042 | "outputs": [] 1043 | }, 1044 | { 1045 | "cell_type": "markdown", 1046 | "source": [ 1047 | "# (META DATA SEARCH)" 1048 | ], 1049 | "metadata": { 1050 | "id": "kawXUInwyh2X" 1051 | } 1052 | }, 1053 | { 1054 | "cell_type": "code", 1055 | "source": [ 1056 | "#@title Load Monster MIDI Dataset Metadata\n", 1057 | "print('=' * 70)\n", 1058 | "print('Loading Monster MIDI Dataset Metadata...')\n", 1059 | "meta_data = pickle.load(open('/content/Main-MIDI-Dataset/META_DATA/MONSTER_META_DATA.pickle', 'rb'))\n", 1060 | "print('Done!')\n", 1061 | "print('=' * 70)\n", 1062 | "print('Enjoy!')\n", 1063 | "print('=' * 70)" 1064 | ], 1065 | "metadata": { 1066 | "cellView": "form", 1067 | "id": "l72wnOFAy9Ly" 1068 | }, 1069 | "execution_count": null, 1070 | "outputs": [] 1071 | }, 1072 | { 1073 | "cell_type": "code", 1074 | "source": [ 1075 | "#@title Monster MIDI Dataset Metadata Search\n", 1076 | "\n", 1077 | "#@markdown You can search the metadata by search query or by MIDI md5 hash file name\n", 1078 | "\n", 1079 | "search_query = \"Come To My Window\" #@param {type:\"string\"}\n", 1080 | "md5_hash_MIDI_file_name = \"68dfb00f24f5ebd9bb52823fa9a04c3e\" #@param {type:\"string\"}\n", 1081 | "case_sensitive_search = False #@param {type:\"boolean\"}\n", 1082 | "\n", 1083 | "fields_to_search = ['track_name',\n", 1084 | " 'text_event',\n", 1085 | " 'lyric',\n", 1086 | " 'copyright_text_event',\n", 1087 | " 'marker',\n", 1088 | " 'text_event_08',\n", 1089 | " 'text_event_09',\n", 1090 | " 'text_event_0a',\n", 1091 | " 'text_event_0b',\n", 1092 | " 'text_event_0c',\n", 1093 | " 'text_event_0d',\n", 1094 | " 'text_event_0e',\n", 1095 | " 'text_event_0f',\n", 1096 | " ]\n", 1097 | "\n", 1098 | "print('=' * 70)\n", 1099 | "print('Los Angeles MIDI Dataset Metadata Search')\n", 1100 | "print('=' * 70)\n", 1101 | "print('Searching...')\n", 1102 | "print('=' * 70)\n", 1103 | "\n", 1104 | "if md5_hash_MIDI_file_name != '':\n", 1105 | " for d in tqdm(meta_data):\n", 1106 | " try:\n", 1107 | " if d[0] == md5_hash_MIDI_file_name:\n", 1108 | " print('Found!')\n", 1109 | " print('=' * 70)\n", 1110 | " print('Metadata index:', meta_data.index(d))\n", 1111 | " print('MIDI file name:', meta_data[meta_data.index(d)][0])\n", 1112 | " print('-' * 70)\n", 1113 | " pprint.pprint(['Result:', d[1][:16]], compact = True)\n", 1114 | " print('=' * 70)\n", 1115 | " break\n", 1116 | "\n", 1117 | " except KeyboardInterrupt:\n", 1118 | " print('Ending search...')\n", 1119 | " print('=' * 70)\n", 1120 | " break\n", 1121 | "\n", 1122 | " except Exception as e:\n", 1123 | " print('WARNING !!!')\n", 1124 | " print('=' * 70)\n", 1125 | " print('Error detected:', e)\n", 1126 | " print('=' * 70)\n", 1127 | " continue\n", 1128 | "\n", 1129 | " if d[0] != md5_hash_MIDI_file_name:\n", 1130 | " print('Not found!')\n", 1131 | " print('=' * 70)\n", 1132 | " print('md5 hash was not found!')\n", 1133 | " print('Ending search...')\n", 1134 | " print('=' * 70)\n", 1135 | "\n", 1136 | "else:\n", 1137 | " for d in tqdm(meta_data):\n", 1138 | " try:\n", 1139 | " for dd in d[1]:\n", 1140 | " if dd[0] in fields_to_search:\n", 1141 | " if case_sensitive_search:\n", 1142 | " if str(search_query) in str(dd[2]):\n", 1143 | " print('Found!')\n", 1144 | " print('=' * 70)\n", 1145 | " print('Metadata index:', meta_data.index(d))\n", 1146 | " print('MIDI file name:', meta_data[meta_data.index(d)][0])\n", 1147 | " print('-' * 70)\n", 1148 | " pprint.pprint(['Result:', dd[2][:16]], compact = True)\n", 1149 | " print('=' * 70)\n", 1150 | "\n", 1151 | " else:\n", 1152 | " if str(search_query).lower() in str(dd[2]).lower():\n", 1153 | " print('Found!')\n", 1154 | " print('=' * 70)\n", 1155 | " print('Metadata index:', meta_data.index(d))\n", 1156 | " print('MIDI file name:', meta_data[meta_data.index(d)][0])\n", 1157 | " print('-' * 70)\n", 1158 | " pprint.pprint(['Result:', dd[2][:16]], compact = True)\n", 1159 | " print('=' * 70)\n", 1160 | "\n", 1161 | " except KeyboardInterrupt:\n", 1162 | " print('Ending search...')\n", 1163 | " print('=' * 70)\n", 1164 | " break\n", 1165 | "\n", 1166 | " except:\n", 1167 | " print('Ending search...')\n", 1168 | " print('=' * 70)\n", 1169 | " break" 1170 | ], 1171 | "metadata": { 1172 | "cellView": "form", 1173 | "id": "2iC3oMnZyksz" 1174 | }, 1175 | "execution_count": null, 1176 | "outputs": [] 1177 | }, 1178 | { 1179 | "cell_type": "markdown", 1180 | "metadata": { 1181 | "id": "YzCMd94Tu_gz" 1182 | }, 1183 | "source": [ 1184 | "# Congrats! You did it! :)" 1185 | ] 1186 | } 1187 | ], 1188 | "metadata": { 1189 | "colab": { 1190 | "private_outputs": true, 1191 | "provenance": [], 1192 | "gpuType": "A100", 1193 | "machine_shape": "hm" 1194 | }, 1195 | "kernelspec": { 1196 | "display_name": "Python 3", 1197 | "name": "python3" 1198 | }, 1199 | "language_info": { 1200 | "codemirror_mode": { 1201 | "name": "ipython", 1202 | "version": 3 1203 | }, 1204 | "file_extension": ".py", 1205 | "mimetype": "text/x-python", 1206 | "name": "python", 1207 | "nbconvert_exporter": "python", 1208 | "pygments_lexer": "ipython3", 1209 | "version": "3.9.7" 1210 | }, 1211 | "accelerator": "GPU" 1212 | }, 1213 | "nbformat": 4, 1214 | "nbformat_minor": 0 1215 | } --------------------------------------------------------------------------------