├── .github └── FUNDING.yml ├── LICENSE ├── MUSIC_INT_EVAL_DATASET.zip ├── README.md ├── Super Chamber Piano MIDI Sample.mid ├── Super Chamber Piano Only Notewise DataSet.zip ├── Super Chamber Piano Screenshot 1.png ├── Super Chamber Piano Screenshot 2.png ├── Super Chamber Piano Violin Notewise DataSet.zip ├── Super Chamber Piano WAV Sample.wav ├── Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip ├── SuperPiano.ipynb ├── SuperPiano5_(Reformer_TPU).ipynb ├── Super_Chamber_Piano.ipynb ├── Super_Piano_2.ipynb ├── Super_Piano_3.ipynb ├── Super_Piano_3_Alt.ipynb ├── Super_Piano_3_Alt_2.ipynb ├── Super_Piano_4.ipynb ├── Super_Piano_6_Performer_GPU.ipynb ├── [TMIDI]_Super_Piano_3.ipynb ├── trained_model.h5 ├── trained_model_jazz.h5 └── trained_model_piano.h5 /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/AleksandrSigalov'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /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 2021 Project Los Angeles / Tegridy Code 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 | -------------------------------------------------------------------------------- /MUSIC_INT_EVAL_DATASET.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/MUSIC_INT_EVAL_DATASET.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Super Piano 2 | ## SOTA Music AI Implementations Repo 3 | ### Built on Google XLNet/Transformer-XL SOTA AI Architecture) 4 | 5 | ![Super Piano](https://github.com/asigalov61/SuperPiano/raw/master/Super%20Chamber%20Piano%20Screenshot%202.png?raw=true) 6 | 7 | Absolutely fantastic SOTA Google Colab (Jupyter) Notebooks to easily and quickly train a SOTA Music AI model and for generating music with Transformer technology (Google XLNet/Transformer-XL) 8 | 9 | Huge thanks goes to creators of the original repos/code that made these amazing Notebooks possible :) Thank you very much and the credit is all yours :) 10 | 11 | ## Description of each Super Piano Colab 12 | 13 | ### [THE BEST] Super Chamber Piano (Non-Transformer, pure LSTM, go figure :) 14 | 15 | Absolutely fantastic implementation of Chamber Piano that is capable of playing two instruments at once (Piano and Violin). Plays incredibly well and is capable of smooth continuations. Works well with Jazz as well. Check out screenshots, pre-trained model, and the dataset. 16 | 17 | Enjoy :) 18 | 19 | ### 1) Super Piano Original 20 | 21 | This All-In-One Composition Piano Colab/Model that is capable of either generating a perfomance or a pretty decent continuation of your own composition (Custom MIDI continuation option). 22 | 23 | Recommended for every purpose as it can handle any Piano composition task. 24 | 25 | It also uses block continuation schema, meaning that you can continue your composition to any desired length and you have full control over each continuation block (size, temp, etc). 26 | 27 | Most capable of my Super Piano Music AI models :) 28 | 29 | A better pre-trained model for this Piano will be coming very soon. 30 | 31 | ### 2) Super Piano 2 32 | 33 | This is by far the most capable of my Performance Super Pianos. Capable of super fast piano perfomances generation (any lenghs, any number of perfomances/batches). 34 | 35 | This version also has a histogram-based control option that produces very nice results. 36 | 37 | Does not work well with MAESTRO DataSet so please use provided Super Piano 2 MIDIs DataSet or use your own. 38 | 39 | Recommended use: Batch/Monster Perfomance generation based on a Histogram primer key. See instructions at the Generation Section in Colab where I provide examples. 40 | 41 | ### 3) Super Piano 3 [DOES NOT PLAY WELL DUE TO PROBLEMS WITH MIDI PROCESSOR and with some other stuff] 42 | 43 | SOTA Perfomance Colab/Model. 44 | 45 | This Piano also pretty much a very close copy (or rather a reproduction) of the Google Piano Trainsformer Paper/Model/Colab. Definitely check it out so that you can compare the output and reproducability with my implementation. 46 | 47 | Custom MIDI options also present but since it is a Performance model, it is not really designed to be controled or influenced. 48 | 49 | ### 4) Super Piano 4 50 | 51 | Fully Multi-instrumental LSTM Colab based on Google Transformer-XL architecture. Works well. Check it out. 52 | 53 | ## Some stats: 54 | 55 | Architecture Google XLNet/Transformer-XL (FastAI/PyTorch) 56 | 57 | You are welcome to train original models further or fine-tune them with your (smaller) MIDI dataset. 58 | 59 | Thank you and enjoy these amazing Music AI Notebooks :) 60 | 61 | Alex 62 | ![Super Piano](https://github.com/asigalov61/SuperPiano/raw/master/Super%20Chamber%20Piano%20Screenshot%201.png?raw=true) 63 | 64 | [![Alex's github stats](https://github-readme-stats.vercel.app/api?username=asigalov61&count_private=true&show_icons=true&theme=radical)](https://github.com/anuraghazra/github-readme-stats) 65 | -------------------------------------------------------------------------------- /Super Chamber Piano MIDI Sample.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano MIDI Sample.mid -------------------------------------------------------------------------------- /Super Chamber Piano Only Notewise DataSet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Only Notewise DataSet.zip -------------------------------------------------------------------------------- /Super Chamber Piano Screenshot 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Screenshot 1.png -------------------------------------------------------------------------------- /Super Chamber Piano Screenshot 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Screenshot 2.png -------------------------------------------------------------------------------- /Super Chamber Piano Violin Notewise DataSet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Violin Notewise DataSet.zip -------------------------------------------------------------------------------- /Super Chamber Piano WAV Sample.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano WAV Sample.wav -------------------------------------------------------------------------------- /Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip -------------------------------------------------------------------------------- /SuperPiano.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "kernelspec": { 6 | "name": "python3", 7 | "display_name": "Python 3" 8 | }, 9 | "language_info": { 10 | "codemirror_mode": { 11 | "name": "ipython", 12 | "version": 3 13 | }, 14 | "file_extension": ".py", 15 | "mimetype": "text/x-python", 16 | "name": "python", 17 | "nbconvert_exporter": "python", 18 | "pygments_lexer": "ipython3", 19 | "version": "3.7.2" 20 | }, 21 | "colab": { 22 | "name": "SuperPiano.ipynb", 23 | "provenance": [], 24 | "collapsed_sections": [], 25 | "toc_visible": true, 26 | "include_colab_link": true 27 | }, 28 | "accelerator": "GPU" 29 | }, 30 | "cells": [ 31 | { 32 | "cell_type": "markdown", 33 | "metadata": { 34 | "id": "view-in-github", 35 | "colab_type": "text" 36 | }, 37 | "source": [ 38 | "\"Open" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": { 44 | "id": "B15H9oWKZSA7", 45 | "colab_type": "text" 46 | }, 47 | "source": [ 48 | "# SUPER PIANO (XLNet Piano)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": { 54 | "id": "WSDH5TNUZcex", 55 | "colab_type": "text" 56 | }, 57 | "source": [ 58 | "\"Open\n", 59 | "\n", 60 | "Huge thanks goes to Andrew Shaw (bearpelican) for the MusicAutoBot repo/code that was used to create this notebook. This notebook is a fork of Andrew's notebook for MusicTransformer\n", 61 | "\n", 62 | "https://github.com/bearpelican\n", 63 | "\n", 64 | "https://github.com/bearpelican/musicautobot" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": { 70 | "id": "F3N-SRlpNtm7", 71 | "colab_type": "text" 72 | }, 73 | "source": [ 74 | "# SETUP THE ENVIRONMENT" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "metadata": { 80 | "id": "dzrRdTvlJdFd", 81 | "colab_type": "code", 82 | "cellView": "form", 83 | "colab": {} 84 | }, 85 | "source": [ 86 | "#@title Install all dependencies/clone repos/import modules\n", 87 | "!git clone https://github.com/asigalov61/musicautobot.git\n", 88 | "!nvidia-smi\n", 89 | "!apt install fluidsynth\n", 90 | "!gsutil -q -m cp gs://magentadata/soundfonts/Yamaha-C5-Salamander-JNv5.1.sf2 /content/musicautobot\n", 91 | "!pip install torch fastai music21 pebble fluidsynth midi2audio\n", 92 | "!pip install pretty_midi\n", 93 | "!pip install pypianoroll\n", 94 | "!pip install mir_eval\n", 95 | "\n", 96 | "import os\n", 97 | "os.chdir('musicautobot')\n", 98 | "from musicautobot.numpy_encode import *\n", 99 | "from musicautobot.utils.file_processing import process_all, process_file\n", 100 | "from musicautobot.config import *\n", 101 | "from musicautobot.music_transformer import *\n", 102 | "from musicautobot.numpy_encode import stream2npenc_parts\n", 103 | "from musicautobot.utils.midifile import *\n", 104 | "from fastai.text import *\n", 105 | "from midi2audio import FluidSynth\n", 106 | "from IPython.display import Audio\n", 107 | "# Colab cannot play music directly from music21 - must convert to .wav first\n", 108 | "def play_wav(stream):\n", 109 | " out_midi = stream.write('midi')\n", 110 | " out_wav = str(Path(out_midi).with_suffix('.wav'))\n", 111 | " FluidSynth(\"/content/musicautobot/Yamaha-C5-Salamander-JNv5.1.sf2\").midi_to_audio(out_midi, out_wav)\n", 112 | " return Audio(out_wav)\n", 113 | "from google.colab import files\n" 114 | ], 115 | "execution_count": null, 116 | "outputs": [] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "metadata": { 121 | "id": "YEdl4mqo6IAo", 122 | "colab_type": "code", 123 | "cellView": "form", 124 | "colab": {} 125 | }, 126 | "source": [ 127 | "#@title Mount your Google Drive (Highly recommended)\n", 128 | "from google.colab import drive\n", 129 | "drive.mount('/content/drive')" 130 | ], 131 | "execution_count": null, 132 | "outputs": [] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "metadata": { 137 | "id": "S-bqwERQKo2b", 138 | "colab_type": "code", 139 | "cellView": "form", 140 | "colab": {} 141 | }, 142 | "source": [ 143 | "#@title (OPTIONAL) Download SuperPiano original and ready-to-use training data and model\n", 144 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/training-data-piano-no-dynamics.pkl'\n", 145 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/SuperPianoModel.pth'" 146 | ], 147 | "execution_count": null, 148 | "outputs": [] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "wAQrJh1kjud-", 154 | "colab_type": "text" 155 | }, 156 | "source": [ 157 | "# PREP TRAINING DATA" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "metadata": { 163 | "id": "_wSL15svjxjN", 164 | "colab_type": "code", 165 | "cellView": "form", 166 | "colab": {} 167 | }, 168 | "source": [ 169 | "#@title Initialize the paths and variables\n", 170 | "# Location of your midi filesfiles\n", 171 | "midi_path = Path('/content/musicautobot/data/midi')\n", 172 | "midi_path.mkdir(parents=True, exist_ok=True)\n", 173 | "\n", 174 | "# Location to save dataset\n", 175 | "data_path = Path('/content/musicautobot')\n", 176 | "data_path.mkdir(parents=True, exist_ok=True)\n", 177 | "\n", 178 | "# Location of preprocessed numpy files\n", 179 | "numpy_path = Path('/content/musicautobot/lm')\n", 180 | "\n", 181 | "# Location to save trained model/take saved model checkpoint\n", 182 | "model_path = Path('/content/musicautobot')\n", 183 | "\n", 184 | "data_save_name = 'training-data-piano-no-dynamics.pkl'\n", 185 | "[p.mkdir(parents=True, exist_ok=True) for p in [midi_path, numpy_path, data_path, model_path]];" 186 | ], 187 | "execution_count": null, 188 | "outputs": [] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": { 193 | "id": "oRqyd4H5kAyn", 194 | "colab_type": "text" 195 | }, 196 | "source": [ 197 | "#Upload your own MIDI files or dowload ready-to-use DataSet" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "metadata": { 203 | "id": "ACKpDyBDmp-m", 204 | "colab_type": "code", 205 | "cellView": "form", 206 | "colab": {} 207 | }, 208 | "source": [ 209 | "#@title Upload Files Here\n", 210 | "from google.colab import files\n", 211 | "uploaded = files.upload()" 212 | ], 213 | "execution_count": null, 214 | "outputs": [] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "metadata": { 219 | "id": "dwVMmwXm3SXb", 220 | "colab_type": "code", 221 | "cellView": "form", 222 | "colab": {} 223 | }, 224 | "source": [ 225 | "#@title (The Best Choice/Works best stand-alone) Super Piano 2 Original 2500 MIDIs of Piano Music\n", 226 | "%cd /content/musicautobot/data/midi\n", 227 | "!wget 'https://github.com/asigalov61/SuperPiano/raw/master/Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'\n", 228 | "!unzip -j 'Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'" 229 | ], 230 | "execution_count": null, 231 | "outputs": [] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "metadata": { 236 | "id": "GGIX4-ptrwUa", 237 | "colab_type": "code", 238 | "cellView": "form", 239 | "colab": {} 240 | }, 241 | "source": [ 242 | "#@title (Second Best Choice/Works best stand-alone) Alex Piano Only Drafts Original 1500 MIDIs \n", 243 | "%cd /content/musicautobot/data/midi\n", 244 | "!wget 'https://github.com/asigalov61/AlexMIDIDataSet/raw/master/AlexMIDIDataSet-CC-BY-NC-SA-All-Drafts-Piano-Only.zip'\n", 245 | "!unzip -j 'AlexMIDIDataSet-CC-BY-NC-SA-All-Drafts-Piano-Only.zip'" 246 | ], 247 | "execution_count": null, 248 | "outputs": [] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "metadata": { 253 | "id": "vuoi5nZb3dL_", 254 | "colab_type": "code", 255 | "cellView": "form", 256 | "colab": {} 257 | }, 258 | "source": [ 259 | "#@title (Optional) Google Magenta MAESTRO Piano MIDI Dataset (~1300 MIDIs)\n", 260 | "%cd /content/musicautobot/data/midi\n", 261 | "!wget 'https://storage.googleapis.com/magentadata/datasets/maestro/v2.0.0/maestro-v2.0.0-midi.zip'\n", 262 | "!unzip -j maestro-v2.0.0-midi.zip" 263 | ], 264 | "execution_count": null, 265 | "outputs": [] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "id": "yHEGFP-IOqaE", 271 | "colab_type": "text" 272 | }, 273 | "source": [ 274 | "#MIDI PROCESSING" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "metadata": { 280 | "id": "w_0l5fZfbEov", 281 | "colab_type": "code", 282 | "cellView": "form", 283 | "colab": {} 284 | }, 285 | "source": [ 286 | "#@title Calculate and display number of indexed MIDI files\n", 287 | "# num_tracks = [1, 2] # number of tracks to support\n", 288 | "cutoff = 5 # max instruments\n", 289 | "min_variation = 3 # minimum number of different midi notes played\n", 290 | "# max_dur = 128\n", 291 | "\n", 292 | "midi_files = get_files(midi_path, '.midi', recurse=False); len(midi_files)" 293 | ], 294 | "execution_count": null, 295 | "outputs": [] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "metadata": { 300 | "id": "xLe-Jy7ebkKL", 301 | "colab_type": "code", 302 | "cellView": "form", 303 | "colab": {} 304 | }, 305 | "source": [ 306 | "#@title Parse, Compress, and Convert MIDI files into Numpy format\n", 307 | "def process_metadata(midi_file):\n", 308 | " # Get outfile and check if it exists\n", 309 | " out_file = numpy_path/midi_file.relative_to(midi_path).with_suffix('.npy')\n", 310 | " out_file.parent.mkdir(parents=True, exist_ok=True)\n", 311 | " if out_file.exists(): return\n", 312 | " \n", 313 | " npenc = transform_midi(midi_file)\n", 314 | " if npenc is not None: np.save(out_file, npenc)\n", 315 | "\n", 316 | "#===============================================================\n", 317 | "\n", 318 | "def transform_midi(midi_file):\n", 319 | " input_path = midi_file\n", 320 | " \n", 321 | " # Part 1: Filter out midi tracks (drums, repetitive instruments, etc.)\n", 322 | " try: \n", 323 | "# if duet_only and num_piano_tracks(input_path) not in [1, 2]: return None\n", 324 | " input_file = compress_midi_file(input_path, min_variation=min_variation, cutoff=cutoff) # remove non note tracks and standardize instruments\n", 325 | " \n", 326 | " if input_file is None: return None\n", 327 | " except Exception as e:\n", 328 | " if 'badly form' in str(e): return None # ignore badly formatted midi errors\n", 329 | " if 'out of range' in str(e): return None # ignore badly formatted midi errors\n", 330 | " print('Error parsing midi', input_path, e)\n", 331 | " return None\n", 332 | " \n", 333 | " # Part 2. Compress rests and long notes\n", 334 | " stream = file2stream(input_file) # 1.\n", 335 | " try:\n", 336 | " chordarr = stream2chordarr(stream) # 2. max_dur = quarter_len * sample_freq (4). 128 = 8 bars\n", 337 | " except Exception as e:\n", 338 | " print('Could not encode to chordarr:', input_path, e)\n", 339 | " print(traceback.format_exc())\n", 340 | " return None\n", 341 | " \n", 342 | " # Part 3. Compress song rests - Don't want songs with really long pauses \n", 343 | " # (this happens because we filter out midi tracks).\n", 344 | " chord_trim = trim_chordarr_rests(chordarr)\n", 345 | " chord_short = shorten_chordarr_rests(chord_trim)\n", 346 | " delta_trim = chord_trim.shape[0] - chord_short.shape[0]\n", 347 | " if delta_trim > 500: \n", 348 | " print(f'Removed {delta_trim} rests from {input_path}. Skipping song')\n", 349 | " return None\n", 350 | " chordarr = chord_short\n", 351 | " \n", 352 | " # Part 3. Chord array to numpy\n", 353 | " npenc = chordarr2npenc(chordarr)\n", 354 | " if not is_valid_npenc(npenc, input_path=input_path):\n", 355 | " return None\n", 356 | " \n", 357 | " return npenc\n", 358 | "\n", 359 | "#===============================================================\n", 360 | "def timeout_func(data, seconds):\n", 361 | " print(\"Timeout:\", seconds, data.get('midi'))\n", 362 | "\n", 363 | "#===============================================================\n", 364 | "processed = process_all(process_metadata, midi_files, timeout=120, timeout_func=timeout_func)" 365 | ], 366 | "execution_count": null, 367 | "outputs": [] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "metadata": { 372 | "id": "Rjdoka86dUrS", 373 | "colab_type": "code", 374 | "cellView": "form", 375 | "colab": {} 376 | }, 377 | "source": [ 378 | "#@title Calculate and display number of resulting Numpy files\n", 379 | "def create_databunch(files, data_save_name, path=data_path):\n", 380 | " save_file = path/data_save_name\n", 381 | " if save_file.exists():\n", 382 | " data = load_data(path, data_save_name)\n", 383 | " else:\n", 384 | " save_file.parent.mkdir(exist_ok=True, parents=True)\n", 385 | " vocab = MusicVocab.create()\n", 386 | " processors = [OpenNPFileProcessor(), MusicItemProcessor()]\n", 387 | "\n", 388 | " data = MusicDataBunch.from_files(files, path, processors=processors, encode_position=True)\n", 389 | " data.save(data_save_name)\n", 390 | " return data\n", 391 | "numpy_files = get_files(numpy_path, extensions='.npy', recurse=False); len(numpy_files)" 392 | ], 393 | "execution_count": null, 394 | "outputs": [] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "metadata": { 399 | "id": "y8fu3PVgdZW4", 400 | "colab_type": "code", 401 | "cellView": "form", 402 | "colab": {} 403 | }, 404 | "source": [ 405 | "#@title Create final training dataset file (training-data-piano-no-dynamics.pkl)\n", 406 | "all_data = create_databunch(numpy_files, data_save_name=data_save_name); all_data" 407 | ], 408 | "execution_count": null, 409 | "outputs": [] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": { 414 | "id": "IRvnFMqWP1Ai", 415 | "colab_type": "text" 416 | }, 417 | "source": [ 418 | "# TRAIN, SAVE, AND PLOT MODEL PERFOMANCE" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "metadata": { 424 | "id": "AkrdRghxkXzB", 425 | "colab_type": "code", 426 | "cellView": "form", 427 | "colab": {} 428 | }, 429 | "source": [ 430 | "#@title Initialize the model\n", 431 | "!nvidia-smi\n", 432 | "batch_size = 32\n", 433 | "encode_position = True\n", 434 | "config = default_config()\n", 435 | "dl_tfms = [batch_position_tfm] if encode_position else []\n", 436 | "data = load_data(data_path, data_save_name, bs=batch_size, encode_position=encode_position, transpose_range=[0, 12], dl_tfms=dl_tfms)\n", 437 | "learn = music_model_learner(data, config=config.copy(), metrics=[accuracy, error_rate])\n", 438 | "!nvidia-smi\n" 439 | ], 440 | "execution_count": null, 441 | "outputs": [] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "metadata": { 446 | "id": "xXAD2KWazW0d", 447 | "colab_type": "code", 448 | "cellView": "form", 449 | "colab": {} 450 | }, 451 | "source": [ 452 | "#@title (Optional) Load Existing Model Checkpoint\n", 453 | "config = default_config()\n", 454 | "pretrained_path = Path('/content/musicautobot/SuperPianoModel.pth')\n", 455 | "learn = music_model_learner(data, config=config, pretrained_path=pretrained_path, metrics=[accuracy, error_rate])" 456 | ], 457 | "execution_count": null, 458 | "outputs": [] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "metadata": { 463 | "id": "04QoLCIEH2v7", 464 | "colab_type": "code", 465 | "cellView": "form", 466 | "colab": {} 467 | }, 468 | "source": [ 469 | "#@title Find the optimum learning rate first by running this cell\n", 470 | "learn.lr_find()\n", 471 | "learn.recorder.plot()\n", 472 | "learn.recorder.plot_lr(show_moms=True)" 473 | ], 474 | "execution_count": null, 475 | "outputs": [] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "metadata": { 480 | "id": "Eq55lYQlkhht", 481 | "colab_type": "code", 482 | "cellView": "form", 483 | "colab": {} 484 | }, 485 | "source": [ 486 | "#@title Start/Continue Training\n", 487 | "number_of_training_epochs = 2 #@param {type:\"slider\", min:0, max:10, step:1}\n", 488 | "optimum_learning_rate = 0.01 #@param {type:\"number\"}\n", 489 | "\n", 490 | "learn.fit_one_cycle(number_of_training_epochs, optimum_learning_rate)" 491 | ], 492 | "execution_count": null, 493 | "outputs": [] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "metadata": { 498 | "id": "3pvhIoY3klFe", 499 | "colab_type": "code", 500 | "cellView": "form", 501 | "colab": {} 502 | }, 503 | "source": [ 504 | "#@title Save and Plot\n", 505 | "learn.save('/content/musicautobot/SuperPianoModel')\n", 506 | "learn.recorder.plot_lr(show_moms=True)" 507 | ], 508 | "execution_count": null, 509 | "outputs": [] 510 | }, 511 | { 512 | "cell_type": "markdown", 513 | "metadata": { 514 | "id": "EckFLJkjJdFg", 515 | "colab_type": "text" 516 | }, 517 | "source": [ 518 | "# GENERATE MUSIC WITH THE MODEL" 519 | ] 520 | }, 521 | { 522 | "cell_type": "markdown", 523 | "metadata": { 524 | "id": "FmhNm2TcJdFh", 525 | "colab_type": "text" 526 | }, 527 | "source": [ 528 | "## SETUP VARIABLES AND LOAD/RE-LOAD THE MODEL (just in case)" 529 | ] 530 | }, 531 | { 532 | "cell_type": "code", 533 | "metadata": { 534 | "id": "hH7drZxkJdFi", 535 | "colab_type": "code", 536 | "cellView": "form", 537 | "colab": {} 538 | }, 539 | "source": [ 540 | "#@title Setup Paths and Intialize the Model\n", 541 | "# Location of your midi files\n", 542 | "midi_path = Path('/content/musicautobot')\n", 543 | "\n", 544 | "# Location of saved datset\n", 545 | "data_path = Path('/content/musicautobot')\n", 546 | "\n", 547 | "# Data and Vocab variables initialization\n", 548 | "data = MusicDataBunch.empty(data_path) #for pretrained models\n", 549 | "vocab = data.vocab\n", 550 | "\n", 551 | "# Location of pretrained model\n", 552 | "pretrained_path = Path('/content/musicautobot/SuperPianoModel.pth')\n", 553 | "pretrained_path.parent.mkdir(parents=True, exist_ok=True)\n", 554 | "\n", 555 | "# Initialize the model\n", 556 | "config = default_config()\n", 557 | "learn = music_model_learner(data, config=config, pretrained_path=pretrained_path)" 558 | ], 559 | "execution_count": null, 560 | "outputs": [] 561 | }, 562 | { 563 | "cell_type": "markdown", 564 | "metadata": { 565 | "id": "G3HDp9EMJdFr", 566 | "colab_type": "text" 567 | }, 568 | "source": [ 569 | "### PREDICTION" 570 | ] 571 | }, 572 | { 573 | "cell_type": "markdown", 574 | "metadata": { 575 | "id": "UDWCdsHFJdFr", 576 | "colab_type": "text" 577 | }, 578 | "source": [ 579 | "## Choose existing midi file as a starting point" 580 | ] 581 | }, 582 | { 583 | "cell_type": "code", 584 | "metadata": { 585 | "id": "tJGaOvmbt08K", 586 | "colab_type": "code", 587 | "cellView": "form", 588 | "colab": {} 589 | }, 590 | "source": [ 591 | "#@title Upload your seed MIDI (will purge all MID/MIDI files you might've uploaded before)\n", 592 | "%cd /content/musicautobot\n", 593 | "!rm *.mid *.midi\n", 594 | "uploaded = files.upload()\n", 595 | "midi_files = get_files(midi_path, recurse=False, extensions='.mid'); midi_files[:5]\n", 596 | "idx = 0\n", 597 | "f = midi_files[idx]; f" 598 | ], 599 | "execution_count": null, 600 | "outputs": [] 601 | }, 602 | { 603 | "cell_type": "markdown", 604 | "metadata": { 605 | "id": "nJShT9HKJdFw", 606 | "colab_type": "text" 607 | }, 608 | "source": [ 609 | "## Trim (use seed from a MIDI file to predict next sequence/continuation)\n", 610 | "\n" 611 | ] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "metadata": { 616 | "id": "pPvOU-sUPqGc", 617 | "colab_type": "code", 618 | "cellView": "form", 619 | "colab": {} 620 | }, 621 | "source": [ 622 | "##@title Setup Pianoroll Output :) { run: \"auto\" }\n", 623 | "graphs_length_inches = 18 #@param {type:\"slider\", min:0, max:20, step:1}\n", 624 | "notes_graph_height = 5 #@param {type:\"slider\", min:0, max:20, step:1}\n", 625 | "\n", 626 | "import librosa\n", 627 | "import numpy as np\n", 628 | "import pretty_midi\n", 629 | "import pypianoroll\n", 630 | "from pypianoroll import Multitrack, Track\n", 631 | "import matplotlib\n", 632 | "import matplotlib.pyplot as plt\n", 633 | "#matplotlib.use('SVG')\n", 634 | "# For plotting\n", 635 | "import mir_eval.display\n", 636 | "import librosa.display\n", 637 | "%matplotlib inline\n", 638 | "\n", 639 | "\n", 640 | "#midi_data = pretty_midi.PrettyMIDI('/content/MusicTransformer-Pytorch/output/rand.mid')\n", 641 | "\n", 642 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n", 643 | " # Use librosa's specshow function for displaying the piano roll\n", 644 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n", 645 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n", 646 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n", 647 | "\n", 648 | "\n", 649 | "\n", 650 | "roll = np.zeros([int(graphs_length_inches), 128])\n" 651 | ], 652 | "execution_count": null, 653 | "outputs": [] 654 | }, 655 | { 656 | "cell_type": "code", 657 | "metadata": { 658 | "id": "WUPmoGqcJdFx", 659 | "colab_type": "code", 660 | "cellView": "form", 661 | "colab": {} 662 | }, 663 | "source": [ 664 | "#@title Show/Plot/Listen to the seed uploaded above. You can also run this cell to see Seed Continuation output below\n", 665 | "MIDI_cutoff_beat = 20 #@param {type:\"slider\", min:0, max:100, step:1}\n", 666 | "cutoff_beat = 20\n", 667 | "item = MusicItem.from_file(f, data.vocab)\n", 668 | "seed_item = item.trim_to_beat(cutoff_beat)\n", 669 | "\n", 670 | "seed_item.stream.write('midi', '/content/musicautobot/seed_item.mid')\n", 671 | "\n", 672 | "roll = np.zeros([int(graphs_length_inches), 128])\n", 673 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/seed_item.mid')\n", 674 | "\n", 675 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n", 676 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n", 677 | "plt.show(block=False)\n", 678 | "\n", 679 | "play_wav(seed_item.stream)" 680 | ], 681 | "execution_count": null, 682 | "outputs": [] 683 | }, 684 | { 685 | "cell_type": "markdown", 686 | "metadata": { 687 | "id": "W_h-A5huKxXu", 688 | "colab_type": "text" 689 | }, 690 | "source": [ 691 | "## GENERATE (CHOOSE ONE OPTION BELOW)" 692 | ] 693 | }, 694 | { 695 | "cell_type": "markdown", 696 | "metadata": { 697 | "id": "EerOfXwwsOBD", 698 | "colab_type": "text" 699 | }, 700 | "source": [ 701 | "### GENERATE w/starting sequence (Continuation)" 702 | ] 703 | }, 704 | { 705 | "cell_type": "code", 706 | "metadata": { 707 | "id": "2LA7EeVpKh4Y", 708 | "colab_type": "code", 709 | "cellView": "form", 710 | "colab": {} 711 | }, 712 | "source": [ 713 | "#@title Seed Continuation\n", 714 | "number_of_tokens_to_generate = 256 #@param {type:\"slider\", min:0, max:4096, step:64}\n", 715 | "max_model_temperature = 0.7 #@param {type:\"slider\", min:0, max:4, step:0.1}\n", 716 | "min_model_temperature = 1.3 #@param {type:\"slider\", min:0, max:4, step:0.1}\n", 717 | "model_top_k = 30 #@param {type:\"slider\", min:0, max:50, step:1}\n", 718 | "model_top_p = 0.9 #@param {type:\"slider\", min:0, max:1, step:0.1}\n", 719 | "minimum_number_of_bars_to_generate = 8 #@param {type:\"slider\", min:0, max:64, step:1}\n", 720 | "seed_item = MusicItem.from_file('seed_item.mid', data.vocab)\n", 721 | "pred, full = learn.predict(seed_item, n_words=number_of_tokens_to_generate, temperatures=(max_model_temperature, min_model_temperature), min_bars=minimum_number_of_bars_to_generate, top_k=model_top_k, top_p=model_top_p)\n", 722 | "#pred.show()\n", 723 | "pred.stream.write('midi', '/content/musicautobot/continuation.mid')\n", 724 | "\n", 725 | "\n", 726 | "roll = np.zeros([int(graphs_length_inches), 128])\n", 727 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/continuation.mid')\n", 728 | "\n", 729 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n", 730 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n", 731 | "plt.show(block=False)\n", 732 | "\n", 733 | "play_wav(pred.stream)" 734 | ], 735 | "execution_count": null, 736 | "outputs": [] 737 | }, 738 | { 739 | "cell_type": "code", 740 | "metadata": { 741 | "id": "UZg6f8mVJdF_", 742 | "colab_type": "code", 743 | "cellView": "form", 744 | "colab": {} 745 | }, 746 | "source": [ 747 | "#@title Would you like to add generated continuation to the seed/previous section??? If yes, run this cell, if not, go back and start over.\n", 748 | "seed_item = seed_item.append(pred)\n", 749 | "#seed_item.show()\n", 750 | "\n", 751 | "seed_item.stream.write('midi', '/content/musicautobot/seed_continuation.mid')\n", 752 | "\n", 753 | "roll = np.zeros([int(graphs_length_inches), 128])\n", 754 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/seed_continuation.mid')\n", 755 | "\n", 756 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n", 757 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n", 758 | "plt.show(block=False)\n", 759 | "\n", 760 | "play_wav(seed_item.stream)" 761 | ], 762 | "execution_count": null, 763 | "outputs": [] 764 | }, 765 | { 766 | "cell_type": "markdown", 767 | "metadata": { 768 | "id": "b-hAoe5HJdGS", 769 | "colab_type": "text" 770 | }, 771 | "source": [ 772 | "### GENERATE w/o a starting sequence (Performance)" 773 | ] 774 | }, 775 | { 776 | "cell_type": "code", 777 | "metadata": { 778 | "id": "h9gF6rt7JdGU", 779 | "colab_type": "code", 780 | "cellView": "form", 781 | "colab": {} 782 | }, 783 | "source": [ 784 | "#@title Original Uninfluenced Performance\n", 785 | "number_of_tokens_to_generate = 1024 #@param {type:\"slider\", min:0, max:4096, step:64}\n", 786 | "max_model_temperature = 1.4 #@param {type:\"slider\", min:0, max:4, step:0.1}\n", 787 | "min_model_temperature = 0.7 #@param {type:\"slider\", min:0, max:4, step:0.1}\n", 788 | "model_top_k = 20 #@param {type:\"slider\", min:0, max:50, step:1}\n", 789 | "model_top_p = 0.8 #@param {type:\"slider\", min:0, max:1, step:0.1}\n", 790 | "minimum_number_of_bars_to_generate = 8 #@param {type:\"slider\", min:0, max:64, step:1}\n", 791 | "\n", 792 | "empty_item = MusicItem.empty(vocab)\n", 793 | "pred, full = learn.predict(empty_item, n_words=number_of_tokens_to_generate, temperatures=(max_model_temperature, min_model_temperature), min_bars=minimum_number_of_bars_to_generate, top_k=model_top_k, top_p=model_top_p)\n", 794 | "#pred.show()\n", 795 | "pred.stream.write('midi', '/content/musicautobot/performance.mid')\n", 796 | "\n", 797 | "roll = np.zeros([int(graphs_length_inches), 128])\n", 798 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/performance.mid')\n", 799 | "\n", 800 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n", 801 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n", 802 | "plt.show(block=False)\n", 803 | "\n", 804 | "play_wav(pred.stream)" 805 | ], 806 | "execution_count": null, 807 | "outputs": [] 808 | } 809 | ] 810 | } -------------------------------------------------------------------------------- /SuperPiano5_(Reformer_TPU).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "accelerator": "TPU", 6 | "colab": { 7 | "name": "SuperPiano5 (Reformer_TPU).ipynb", 8 | "private_outputs": true, 9 | "provenance": [], 10 | "collapsed_sections": [], 11 | "toc_visible": true, 12 | "include_colab_link": true 13 | }, 14 | "kernelspec": { 15 | "display_name": "Python 3", 16 | "language": "python", 17 | "name": "python3" 18 | }, 19 | "language_info": { 20 | "codemirror_mode": { 21 | "name": "ipython", 22 | "version": 3 23 | }, 24 | "file_extension": ".py", 25 | "mimetype": "text/x-python", 26 | "name": "python", 27 | "nbconvert_exporter": "python", 28 | "pygments_lexer": "ipython3", 29 | "version": "3.7.7" 30 | } 31 | }, 32 | "cells": [ 33 | { 34 | "cell_type": "markdown", 35 | "metadata": { 36 | "id": "view-in-github", 37 | "colab_type": "text" 38 | }, 39 | "source": [ 40 | "\"Open" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "lgn4KUAATtXS" 47 | }, 48 | "source": [ 49 | "# Super Piano 5 (v.0.5)\r\n", 50 | "\r\n", 51 | "Uses integer version of the https://github.com/asigalov61/Tegridy-MIDI-Dataset/blob/master/Tegridy-Piano-CC-BY-NC-SA.zip\r\n", 52 | "\r\n", 53 | "Most of the colab as found here:\r\n", 54 | "\r\n", 55 | "https://github.com/jlilleberg/Philosophical-Text-Generation-using-Reformers" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "metadata": { 61 | "id": "QINqPZH6FzB3" 62 | }, 63 | "source": [ 64 | "# Install dependencies\n", 65 | "\n", 66 | "!git clone https://github.com/asigalov61/tegridy-tools\n", 67 | "%cd /content/tegridy-tools/tegridy-tools/\n", 68 | "import TMIDI\n", 69 | "%cd /content/\n", 70 | "\n", 71 | "!wget https://github.com/asigalov61/SuperPiano/raw/master/MUSIC_INT_EVAL_DATASET.zip\n", 72 | "\n", 73 | "!pip install --upgrade -q jax\n", 74 | "!pip install --upgrade -q jaxlib\n", 75 | "!pip install --upgrade -q trax==1.3.6\n", 76 | "!pip install --upgrade -q sentencepiece\n", 77 | "!pip install --upgrade -q gin \n", 78 | "\n", 79 | "# Make sure the Colab Runtime is set to Accelerator: TPU.\n", 80 | "import requests\n", 81 | "import os\n", 82 | "if 'TPU_DRIVER_MODE' not in globals():\n", 83 | " url = 'http://' + os.environ['COLAB_TPU_ADDR'].split(':')[0] + ':8475/requestversion/tpu_driver0.1-dev20191206'\n", 84 | " resp = requests.post(url)\n", 85 | " TPU_DRIVER_MODE = 1\n", 86 | "\n", 87 | "# The following is required to use TPU Driver as JAX's backend.\n", 88 | "from jax.config import config\n", 89 | "config.FLAGS.jax_xla_backend = \"tpu_driver\"\n", 90 | "config.FLAGS.jax_backend_target = \"grpc://\" + os.environ['COLAB_TPU_ADDR']\n", 91 | "print(config.FLAGS.jax_backend_target)" 92 | ], 93 | "execution_count": null, 94 | "outputs": [] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "metadata": { 99 | "id": "s4-aGTZBUxAy" 100 | }, 101 | "source": [ 102 | "!wget https://github.com/asigalov61/SuperPiano/raw/master/MUSIC_INT_EVAL_DATASET.zip\r\n", 103 | "!unzip MUSIC_INT_EVAL_DATASET.zip" 104 | ], 105 | "execution_count": null, 106 | "outputs": [] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "metadata": { 111 | "id": "pv0PuxC3F-jn" 112 | }, 113 | "source": [ 114 | "import gin\n", 115 | "import os\n", 116 | "import numpy as np\n", 117 | "from scipy.special import softmax\n", 118 | "\n", 119 | "# Zipping and downloading files\n", 120 | "from google.colab import files\n", 121 | "import shutil\n", 122 | "\n", 123 | "# Trax\n", 124 | "import jax\n", 125 | "import trax\n", 126 | "from trax.data import inputs\n", 127 | "import jax.numpy as jnp\n", 128 | "\n", 129 | "# NLP Vocab Generation\n", 130 | "import sentencepiece as spm\n", 131 | "\n", 132 | "# TensorFlow\n", 133 | "from tensorflow.compat.v1.io.gfile import GFile\n", 134 | "import tensorflow as tf" 135 | ], 136 | "execution_count": null, 137 | "outputs": [] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "metadata": { 142 | "id": "L7shBqm0T6rz" 143 | }, 144 | "source": [ 145 | "# This is for the future MIDI Processor code/section.\r\n", 146 | "# This is to create custom datasets.\r\n", 147 | "\r\n", 148 | "# TXT2, STR2 = TMIDI.Tegridy_TXT_to_INT_Converter(TXT1)\r\n", 149 | "# TXT3 = '\\n'.join([str(elem) for elem in TXT2])\r\n", 150 | "# with open('/content/INT_DATASET.TXT', 'a') as t:\r\n", 151 | "# t.write(TXT3)" 152 | ], 153 | "execution_count": null, 154 | "outputs": [] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "metadata": { 159 | "id": "yRnIoCBkNXyd" 160 | }, 161 | "source": [ 162 | "# Load the dataset\n", 163 | "with GFile('/content/MUSIC_INT_EVAL_DATASET.TXT') as f:\n", 164 | " text = f.read()" 165 | ], 166 | "execution_count": null, 167 | "outputs": [] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "metadata": { 172 | "id": "_l9Znw2bS-Pg" 173 | }, 174 | "source": [ 175 | "# Train a BPE model on the dataset\n", 176 | "spm.SentencePieceTrainer.train('--input=/content/MUSIC_INT_EVAL_DATASET.TXT \\\n", 177 | " --model_prefix=cp.320 \\\n", 178 | " --vocab_size=320 \\\n", 179 | " --model_type=bpe')\n", 180 | "# Load BPE vocabulary\n", 181 | "TOKENIZER = spm.SentencePieceProcessor() \n", 182 | "TOKENIZER.load('cp.320.model')" 183 | ], 184 | "execution_count": null, 185 | "outputs": [] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "metadata": { 190 | "id": "OQwhEqJzS-I2" 191 | }, 192 | "source": [ 193 | "# Tokenize (set to max for the provided dataset)\n", 194 | "\n", 195 | "IDS = TOKENIZER.EncodeAsIds(text[:1600000])\n", 196 | "IDS = np.asarray(IDS, dtype=np.int32)\n", 197 | "PAD_AMOUNT = 512 * 1024 - len(IDS)\n", 198 | "print(\"Number of tokens:\", IDS.shape[0])" 199 | ], 200 | "execution_count": null, 201 | "outputs": [] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "metadata": { 206 | "id": "bdKnx2FyS-AO" 207 | }, 208 | "source": [ 209 | "# Set up the data pipeline.\n", 210 | "def my_inputs(n_devices):\n", 211 | " while True:\n", 212 | " inputs = []\n", 213 | " mask = []\n", 214 | " pad_amounts = np.random.choice(PAD_AMOUNT, n_devices)\n", 215 | " for i in range(n_devices):\n", 216 | " inputs.append(np.pad(IDS, (pad_amounts[i], PAD_AMOUNT - pad_amounts[i]), # Pad IDS by different amount for each device\n", 217 | " mode='constant'))\n", 218 | " mask.append(np.pad(np.ones_like(IDS, dtype=np.float32),\n", 219 | " (pad_amounts[i], PAD_AMOUNT - pad_amounts[i]),\n", 220 | " mode='constant'))\n", 221 | " inputs = np.stack(inputs)\n", 222 | " mask = np.stack(mask)\n", 223 | " yield (inputs, inputs, mask)\n", 224 | "\n", 225 | "print(\"(device count, tokens per device) = \",\n", 226 | " next(my_inputs(trax.fastmath.device_count()))[0].shape)" 227 | ], 228 | "execution_count": null, 229 | "outputs": [] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "metadata": { 234 | "id": "-NeFGlGGS959" 235 | }, 236 | "source": [ 237 | "# Configure hyperparameters.\n", 238 | "gin.parse_config(\"\"\"\n", 239 | "import trax.layers\n", 240 | "import trax.models\n", 241 | "import trax.optimizers\n", 242 | "import trax.data.inputs\n", 243 | "import trax.supervised.trainer_lib\n", 244 | "\n", 245 | "# Parameters that will vary between experiments:\n", 246 | "# ==============================================================================\n", 247 | "train.model = @trax.models.ReformerLM\n", 248 | "# Model will have 6 layers, alternating between the LSH attention\n", 249 | "# and local attention within a certain context window.\n", 250 | "n_layers = 6\n", 251 | "attn_type = [\n", 252 | " @trax.layers.SelfAttention,\n", 253 | " @LSHSelfAttention, \n", 254 | " @trax.layers.SelfAttention,\n", 255 | " @LSHSelfAttention,\n", 256 | " @trax.layers.SelfAttention,\n", 257 | " @LSHSelfAttention,\n", 258 | " ]\n", 259 | "share_qk = False # LSH attention ignores this flag and always shares q & k\n", 260 | "n_heads = 2\n", 261 | "attn_kv = 64\n", 262 | "dropout = 0.05\n", 263 | "n_tokens = 524288\n", 264 | "\n", 265 | "# Parameters for multifactor:\n", 266 | "# ==============================================================================\n", 267 | "multifactor.constant = 0.01\n", 268 | "multifactor.factors = 'constant * linear_warmup * cosine_decay'\n", 269 | "multifactor.warmup_steps = 100\n", 270 | "multifactor.steps_per_cycle = 900\n", 271 | "\n", 272 | "# Parameters for Adam:\n", 273 | "# ==============================================================================\n", 274 | "Adam.weight_decay_rate=0.0\n", 275 | "Adam.b1 = 0.86\n", 276 | "Adam.b2 = 0.92\n", 277 | "Adam.eps = 1e-9\n", 278 | "\n", 279 | "# Parameters for SelfAttention:\n", 280 | "# ==============================================================================\n", 281 | "trax.layers.SelfAttention.attention_dropout = 0.05\n", 282 | "trax.layers.SelfAttention.chunk_len = 64\n", 283 | "trax.layers.SelfAttention.n_chunks_before = 1\n", 284 | "trax.layers.SelfAttention.n_parallel_heads = 1\n", 285 | "\n", 286 | "# Parameters for LSHSelfAttention:\n", 287 | "# ==============================================================================\n", 288 | "LSHSelfAttention.attention_dropout = 0.0\n", 289 | "LSHSelfAttention.chunk_len = 64\n", 290 | "LSHSelfAttention.n_buckets = [64, 128]\n", 291 | "LSHSelfAttention.n_chunks_after = 0\n", 292 | "LSHSelfAttention.n_chunks_before = 1\n", 293 | "LSHSelfAttention.n_hashes = 1\n", 294 | "LSHSelfAttention.n_parallel_heads = 1\n", 295 | "LSHSelfAttention.predict_drop_len = 128\n", 296 | "LSHSelfAttention.predict_mem_len = 1024\n", 297 | "\n", 298 | "# Parameters for ReformerLM:\n", 299 | "# ==============================================================================\n", 300 | "ReformerLM.attention_type = %attn_type\n", 301 | "ReformerLM.d_attention_key = %attn_kv\n", 302 | "ReformerLM.d_attention_value = %attn_kv\n", 303 | "ReformerLM.d_model = 256\n", 304 | "ReformerLM.d_ff = 512\n", 305 | "ReformerLM.dropout = %dropout\n", 306 | "ReformerLM.ff_activation = @trax.layers.Relu\n", 307 | "ReformerLM.max_len = %n_tokens\n", 308 | "ReformerLM.mode = 'train'\n", 309 | "ReformerLM.n_heads = %n_heads\n", 310 | "ReformerLM.n_layers = %n_layers\n", 311 | "ReformerLM.vocab_size = 320\n", 312 | "ReformerLM.axial_pos_shape = (512, 1024)\n", 313 | "ReformerLM.d_axial_pos_embs= (64, 192)\n", 314 | "\"\"\")" 315 | ], 316 | "execution_count": null, 317 | "outputs": [] 318 | }, 319 | { 320 | "cell_type": "code", 321 | "metadata": { 322 | "id": "X8ay-6VxS9xw" 323 | }, 324 | "source": [ 325 | "# Trainer.\n", 326 | "output_dir = os.path.expanduser('model')\n", 327 | "!rm -f ~/model/model.pkl.gz # Remove old model\n", 328 | "\n", 329 | "trainer = trax.supervised.Trainer(\n", 330 | " model=trax.models.ReformerLM,\n", 331 | " loss_fn=trax.layers.CrossEntropyLoss(),\n", 332 | " optimizer=trax.optimizers.Adam,\n", 333 | " lr_schedule=trax.lr.multifactor(),\n", 334 | " inputs=trax.data.inputs.Inputs(my_inputs),\n", 335 | " output_dir=output_dir)" 336 | ], 337 | "execution_count": null, 338 | "outputs": [] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "metadata": { 343 | "id": "Qf0HITY7Wz8C" 344 | }, 345 | "source": [ 346 | "# Train Model\n", 347 | "import tqdm\n", 348 | "for _ in tqdm.tqdm(range(50)):\n", 349 | " trainer.train_epoch(n_steps=100, n_eval_steps=20)" 350 | ], 351 | "execution_count": null, 352 | "outputs": [] 353 | }, 354 | { 355 | "cell_type": "code", 356 | "metadata": { 357 | "id": "JEikLctyte-m" 358 | }, 359 | "source": [ 360 | "# Zip directory contents\n", 361 | "shutil.make_archive(\"project\", \"zip\", \".\")\n", 362 | "\n", 363 | "# Download zipped directory\n", 364 | "files.download('project.zip')" 365 | ], 366 | "execution_count": null, 367 | "outputs": [] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "metadata": { 372 | "id": "FLebeiAFrItK" 373 | }, 374 | "source": [ 375 | "# In the Reformer paper, increasing the number of hashing rounds helps with quality. \n", 376 | "# The number of hashing rounds at can be increased at evaluation time only.\n", 377 | "gin.parse_config(\"\"\"LSHSelfAttention.n_hashes = 8\"\"\")" 378 | ], 379 | "execution_count": null, 380 | "outputs": [] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "metadata": { 385 | "id": "thdiRvGDrJhy" 386 | }, 387 | "source": [ 388 | "# Load the trained Reformer in 'predict' mode\n", 389 | "model = trax.models.ReformerLM(mode='predict')\n", 390 | "output_dir = os.path.expanduser('model')\n", 391 | "model.init_from_file(os.path.join(output_dir,'model.pkl.gz'),\n", 392 | " weights_only=True)\n", 393 | "\n", 394 | "# Sample from ReformerLM\n", 395 | "output_token_ids = trax.supervised.decoding.autoregressive_sample(\n", 396 | " model, temperature=0.8, max_length=1024, accelerate=True)\n", 397 | "\n", 398 | "# Decode token IDs\n", 399 | "# Reformer outputed a batch with one item so access it using [0]\n", 400 | "# tolist() converts from int64 to int, the type SentencePiece expects\n", 401 | "input = TOKENIZER.DecodeIds(output_token_ids[0].tolist())" 402 | ], 403 | "execution_count": null, 404 | "outputs": [] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "metadata": { 409 | "id": "Ox03iX3KHCKa" 410 | }, 411 | "source": [ 412 | "# Run the cells below to convert generated output to MIDI.\r\n", 413 | "# If you getting errors/halts, regenerate the output again.\r\n", 414 | "# Model must be sufficiently trained. Rec. 0.90+ accuracy for the output to make sense and pass error control.\r\n", 415 | "\r\n", 416 | "TXT = TMIDI.Tegridy_INT_String_to_TXT_Converter(input, line_by_line_input=False)" 417 | ], 418 | "execution_count": null, 419 | "outputs": [] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "metadata": { 424 | "id": "WggjV2NNHCti" 425 | }, 426 | "source": [ 427 | "SONG = TMIDI.Tegridy_Reduced_TXT_to_Notes_Converter(TXT, has_MIDI_channels=False, has_velocities=False)" 428 | ], 429 | "execution_count": null, 430 | "outputs": [] 431 | }, 432 | { 433 | "cell_type": "code", 434 | "metadata": { 435 | "id": "z0MvzNCOHEXZ" 436 | }, 437 | "source": [ 438 | "stats = TMIDI.Tegridy_SONG_to_MIDI_Converter(SONG=SONG[0], output_file_name='/content/OUTPUT_MIDI')" 439 | ], 440 | "execution_count": null, 441 | "outputs": [] 442 | } 443 | ] 444 | } -------------------------------------------------------------------------------- /Super_Chamber_Piano.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "kernelspec": { 6 | "display_name": "Python 3", 7 | "language": "python", 8 | "name": "python3" 9 | }, 10 | "language_info": { 11 | "codemirror_mode": { 12 | "name": "ipython", 13 | "version": 3 14 | }, 15 | "file_extension": ".py", 16 | "mimetype": "text/x-python", 17 | "name": "python", 18 | "nbconvert_exporter": "python", 19 | "pygments_lexer": "ipython3", 20 | "version": "3.6.5" 21 | }, 22 | "colab": { 23 | "name": "[Ver 2.0] Super Chamber Piano.ipynb", 24 | "provenance": [], 25 | "private_outputs": true, 26 | "collapsed_sections": [], 27 | "toc_visible": true, 28 | "include_colab_link": true 29 | }, 30 | "accelerator": "GPU" 31 | }, 32 | "cells": [ 33 | { 34 | "cell_type": "markdown", 35 | "metadata": { 36 | "id": "view-in-github", 37 | "colab_type": "text" 38 | }, 39 | "source": [ 40 | "\"Open" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "HIqS2usIWHeI" 47 | }, 48 | "source": [ 49 | "# Super Chamber Piano (Ver 2.0): Notewise Music NN\n", 50 | "\n", 51 | "***\n", 52 | "\n", 53 | "## A Mini Musical Neural Net" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": { 59 | "id": "J5SX5WuiWThz" 60 | }, 61 | "source": [ 62 | "***\n", 63 | "\n", 64 | "All thanks and credit for this beautiful colab go out to edtky of GitHub on whose repo and code it is based: https://github.com/edtky/mini-musical-neural-net\n", 65 | "\n", 66 | "***\n", 67 | "\n" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": { 73 | "id": "ML_w70Rcod6f" 74 | }, 75 | "source": [ 76 | "# Model Specs and Default Parameters\n", 77 | "\n", 78 | "## 2 Layers LSTM\n", 79 | "\n", 80 | "### Hyperparameters\n", 81 | "\n", 82 | "1. sequence_len / n_word = 512 (previous: 128)\n", 83 | "2. batch_size / n_seq = 128\n", 84 | "3. hidden_dim = 512\n", 85 | "4. top_k words = 3 (previous: 5)\n", 86 | "5. predict seq_len = 512 (previous: 1024)\n", 87 | "6. epoch = 300\n", 88 | "\n", 89 | "***" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": { 95 | "id": "isGj8yhe0DvT" 96 | }, 97 | "source": [ 98 | "# System setup" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "metadata": { 104 | "id": "FVrjMED_5sCO", 105 | "cellView": "form" 106 | }, 107 | "source": [ 108 | "#@title Install dependencies\n", 109 | "!pip install pyknon\n", 110 | "!pip install pretty_midi\n", 111 | "!pip install pypianoroll\n", 112 | "!pip install mir_eval\n", 113 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works\n", 114 | "!pip install midi2audio\n", 115 | "!git clone https://github.com/asigalov61/arc-diagrams\n", 116 | "!cp /usr/share/sounds/sf2/FluidR3_GM.sf2 /content/font.sf2" 117 | ], 118 | "execution_count": null, 119 | "outputs": [] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": { 124 | "id": "sZajWNtE0Hwr" 125 | }, 126 | "source": [ 127 | "# Setup modules, functions, variables, and GPU check" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "metadata": { 133 | "id": "Sj9Af0iFod6g", 134 | "cellView": "form" 135 | }, 136 | "source": [ 137 | "#@title Load all modules, check the available devices (GPU/CPU), and setup MIDI parameters\n", 138 | "import numpy as np\n", 139 | "\n", 140 | "import torch\n", 141 | "from torch import nn\n", 142 | "from torch import optim\n", 143 | "import torch.nn.functional as F\n", 144 | "\n", 145 | "import keras\n", 146 | "from keras.utils import to_categorical\n", 147 | "\n", 148 | "import time\n", 149 | "\n", 150 | "import pretty_midi\n", 151 | "from midi2audio import FluidSynth\n", 152 | "from google.colab import output\n", 153 | "from IPython.display import display, Javascript, HTML, Audio\n", 154 | "\n", 155 | "import librosa\n", 156 | "import numpy as np\n", 157 | "import pretty_midi\n", 158 | "import pypianoroll\n", 159 | "from pypianoroll import Multitrack, Track\n", 160 | "import matplotlib\n", 161 | "import matplotlib.pyplot as plt\n", 162 | "#matplotlib.use('SVG')\n", 163 | "# For plotting\n", 164 | "import mir_eval.display\n", 165 | "import librosa.display\n", 166 | "%matplotlib inline\n", 167 | "\n", 168 | "\n", 169 | "from mido import MidiFile\n", 170 | "%cd /content/arc-diagrams/\n", 171 | "from arc_diagram import plot_arc_diagram\n", 172 | "\n", 173 | "\n", 174 | "dtype = torch.float\n", 175 | "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n", 176 | "# Assume that we are on a CUDA machine, then this should print a CUDA device:\n", 177 | "print('Available Device:', device)\n", 178 | "\n", 179 | "!mkdir /content/midis\n", 180 | "\n", 181 | "sample_freq_variable = 12 #@param {type:\"number\"}\n", 182 | "note_range_variable = 62 #@param {type:\"number\"}\n", 183 | "note_offset_variable = 33 #@param {type:\"number\"}\n", 184 | "number_of_instruments = 2 #@param {type:\"number\"}\n", 185 | "chamber_option = True #@param {type:\"boolean\"}\n", 186 | "\n", 187 | "%cd /content/" 188 | ], 189 | "execution_count": null, 190 | "outputs": [] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": { 195 | "id": "SiNnwNj80UwP" 196 | }, 197 | "source": [ 198 | "# (OPTIONS)" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "metadata": { 204 | "id": "9EpQajTGqIKr", 205 | "cellView": "form" 206 | }, 207 | "source": [ 208 | "#@title (OPTION 1) Convert your own MIDIs to Notewise TXT DataSet (before running this cell, upload your MIDI DataSet to /content/midis folder)\n", 209 | "import tqdm.auto\n", 210 | "import argparse\n", 211 | "import random\n", 212 | "import os\n", 213 | "import numpy as np\n", 214 | "from math import floor\n", 215 | "from pyknon.genmidi import Midi\n", 216 | "from pyknon.music import NoteSeq, Note\n", 217 | "import music21\n", 218 | "from music21 import instrument, volume\n", 219 | "from music21 import midi as midiModule\n", 220 | "from pathlib import Path\n", 221 | "import glob, sys\n", 222 | "from music21 import converter, instrument\n", 223 | "%cd /content\n", 224 | "notes=[]\n", 225 | "InstrumentID=0\n", 226 | "folder = '/content/midis/*mid'\n", 227 | "for file in tqdm.auto.tqdm(glob.glob(folder)):\n", 228 | " filename = file[-53:]\n", 229 | " print(filename)\n", 230 | "\n", 231 | " # fname = \"../midi-files/mozart/sonat-3.mid\"\n", 232 | " fname = filename\n", 233 | "\n", 234 | " mf=music21.midi.MidiFile()\n", 235 | " mf.open(fname)\n", 236 | " mf.read()\n", 237 | " mf.close()\n", 238 | " midi_stream=music21.midi.translate.midiFileToStream(mf)\n", 239 | " midi_stream\n", 240 | "\n", 241 | "\n", 242 | "\n", 243 | " sample_freq=sample_freq_variable\n", 244 | " note_range=note_range_variable\n", 245 | " note_offset=note_offset_variable\n", 246 | " chamber=chamber_option\n", 247 | " numInstruments=number_of_instruments\n", 248 | "\n", 249 | " s = midi_stream\n", 250 | " #print(s.duration.quarterLength)\n", 251 | "\n", 252 | " s[0].elements\n", 253 | "\n", 254 | "\n", 255 | " maxTimeStep = floor(s.duration.quarterLength * sample_freq)+1\n", 256 | " score_arr = np.zeros((maxTimeStep, numInstruments, note_range))\n", 257 | "\n", 258 | " #print(maxTimeStep, \"\\n\", score_arr.shape)\n", 259 | "\n", 260 | " # define two types of filters because notes and chords have different structures for storing their data\n", 261 | " # chord have an extra layer because it consist of multiple notes\n", 262 | "\n", 263 | " noteFilter=music21.stream.filters.ClassFilter('Note')\n", 264 | " chordFilter=music21.stream.filters.ClassFilter('Chord')\n", 265 | " \n", 266 | "\n", 267 | " # pitch.midi-note_offset: pitch is the numerical representation of a note. \n", 268 | " # note_offset is the the pitch relative to a zero mark. eg. B-=25, C=27, A=24\n", 269 | "\n", 270 | " # n.offset: the timestamps of each note, relative to the start of the score\n", 271 | " # by multiplying with the sample_freq, you make all the timestamps integers\n", 272 | "\n", 273 | " # n.duration.quarterLength: the duration of that note as a float eg. quarter note = 0.25, half note = 0.5\n", 274 | " # multiply by sample_freq to represent duration in terms of timesteps\n", 275 | "\n", 276 | " notes = []\n", 277 | " instrumentID = 0\n", 278 | " parts = instrument.partitionByInstrument(s)\n", 279 | " for i in range(len(parts.parts)): \n", 280 | " instru = parts.parts[i].getInstrument()\n", 281 | " \n", 282 | "\n", 283 | " for n in s.recurse().addFilter(noteFilter):\n", 284 | " if chamber:\n", 285 | " # assign_instrument where 0 means piano-like and 1 means violin-like, and -1 means neither\n", 286 | " if instru.instrumentName == 'Violin':\n", 287 | " notes.append((n.pitch.midi-note_offset, floor(n.offset*sample_freq), \n", 288 | " floor(n.duration.quarterLength*sample_freq), 1))\n", 289 | " \n", 290 | " notes.append((n.pitch.midi-note_offset, floor(n.offset*sample_freq), \n", 291 | " floor(n.duration.quarterLength*sample_freq), 0))\n", 292 | " \n", 293 | " #print(len(notes))\n", 294 | " notes[-5:]\n", 295 | "\n", 296 | " # do the same using a chord filter\n", 297 | "\n", 298 | " for c in s.recurse().addFilter(chordFilter):\n", 299 | " # unlike the noteFilter, this line of code is necessary as there are multiple notes in each chord\n", 300 | " # pitchesInChord is a list of notes at each chord eg. (, )\n", 301 | " pitchesInChord=c.pitches\n", 302 | " \n", 303 | " # do same as noteFilter and append all notes to the notes list\n", 304 | " for p in pitchesInChord:\n", 305 | " notes.append((p.midi-note_offset, floor(c.offset*sample_freq), \n", 306 | " floor(c.duration.quarterLength*sample_freq), 1))\n", 307 | "\n", 308 | " # do same as noteFilter and append all notes to the notes list\n", 309 | " for p in pitchesInChord:\n", 310 | " notes.append((p.midi-note_offset, floor(c.offset*sample_freq), \n", 311 | " floor(c.duration.quarterLength*sample_freq), 0))\n", 312 | " #print(len(notes))\n", 313 | " notes[-5:]\n", 314 | "\n", 315 | " # the variable/list \"notes\" is a collection of all the notes in the song, not ordered in any significant way\n", 316 | "\n", 317 | " for n in notes:\n", 318 | " \n", 319 | " # pitch is the first variable in n, previously obtained by n.midi-note_offset\n", 320 | " pitch=n[0]\n", 321 | " \n", 322 | " # do some calibration for notes that fall our of note range\n", 323 | " # i.e. less than 0 or more than note_range\n", 324 | " while pitch<0:\n", 325 | " pitch+=12\n", 326 | " while pitch>=note_range:\n", 327 | " pitch-=12\n", 328 | " \n", 329 | " # 3rd element refers to instrument type => if instrument is violin, use different pitch calibration\n", 330 | " if n[3]==1: #Violin lowest note is v22\n", 331 | " while pitch<22:\n", 332 | " pitch+=12\n", 333 | "\n", 334 | " # start building the 3D-tensor of shape: (796, 1, 38)\n", 335 | " # score_arr[0] = timestep\n", 336 | " # score_arr[1] = type of instrument\n", 337 | " # score_arr[2] = pitch/note out of the range of note eg. 38\n", 338 | " \n", 339 | " # n[0] = pitch\n", 340 | " # n[1] = timestep\n", 341 | " # n[2] = duration\n", 342 | " # n[3] = instrument\n", 343 | " #print(n[3])\n", 344 | " try:\n", 345 | " score_arr[n[1], n[3], pitch]=1 # Strike note\n", 346 | " score_arr[n[1]+1:n[1]+n[2], n[3], pitch]=2 # Continue holding note\n", 347 | " except:\n", 348 | " continue\n", 349 | "\n", 350 | " #print(score_arr.shape)\n", 351 | " # print first 5 timesteps\n", 352 | " score_arr[:5,0,]\n", 353 | "\n", 354 | "\n", 355 | " for timestep in score_arr:\n", 356 | " #print(list(reversed(range(len(timestep)))))\n", 357 | " break\n", 358 | "\n", 359 | " instr={}\n", 360 | " instr[0]=\"p\"\n", 361 | " instr[1]=\"v\"\n", 362 | "\n", 363 | " score_string_arr=[]\n", 364 | "\n", 365 | " # loop through all timesteps\n", 366 | " for timestep in score_arr:\n", 367 | " \n", 368 | " # selecting the instruments: i=0 means piano and i=1 means violin\n", 369 | " for i in list(reversed(range(len(timestep)))): # List violin note first, then piano note\n", 370 | " \n", 371 | " # \n", 372 | " score_string_arr.append(instr[i]+''.join([str(int(note)) for note in timestep[i]]))\n", 373 | "\n", 374 | " #print(type(score_string_arr), len(score_string_arr))\n", 375 | " score_string_arr[:5]\n", 376 | "\n", 377 | " modulated=[]\n", 378 | " # get the note range from the array\n", 379 | " note_range=len(score_string_arr[0])-1\n", 380 | "\n", 381 | " for i in range(0,12):\n", 382 | " for chord in score_string_arr:\n", 383 | " \n", 384 | " # minus the instrument letter eg. 'p'\n", 385 | " # add 6 zeros on each side of the string\n", 386 | " padded='000000'+chord[1:]+'000000'\n", 387 | " \n", 388 | " # add back the instrument letter eg. 'p'\n", 389 | " # append window of len=note_range back into \n", 390 | " # eg. if we have \"00012345000\"\n", 391 | " # iteratively, we want to get \"p00012\", \"p00123\", \"p01234\", \"p12345\", \"p23450\", \"p34500\", \"p45000\",\n", 392 | " modulated.append(chord[0]+padded[i:i+note_range])\n", 393 | "\n", 394 | " # 796 * 12\n", 395 | " #print(len(modulated))\n", 396 | " modulated[:5]\n", 397 | "\n", 398 | " # input of this function is a modulated string\n", 399 | " long_string = modulated\n", 400 | "\n", 401 | " translated_list=[]\n", 402 | "\n", 403 | " # for every timestep of the string\n", 404 | " for j in range(len(long_string)):\n", 405 | " \n", 406 | " # chord at timestep j eg. 'p00000000000000000000000000000000000100'\n", 407 | " chord=long_string[j]\n", 408 | " next_chord=\"\"\n", 409 | " \n", 410 | " # range is from next_timestep to max_timestep\n", 411 | " for k in range(j+1, len(long_string)):\n", 412 | " \n", 413 | " # checking if instrument of next chord is same as current chord\n", 414 | " if long_string[k][0]==chord[0]:\n", 415 | " \n", 416 | " # if same, set next chord as next element in modulation\n", 417 | " # otherwise, keep going until you find a chord with the same instrument\n", 418 | " # when you do, set it as the next chord\n", 419 | " next_chord=long_string[k]\n", 420 | " break\n", 421 | " \n", 422 | " # set prefix as the instrument\n", 423 | " # set chord and next_chord to be without the instrument prefix\n", 424 | " # next_chord is necessary to check when notes end\n", 425 | " prefix=chord[0]\n", 426 | " chord=chord[1:]\n", 427 | " next_chord=next_chord[1:]\n", 428 | " \n", 429 | " # checking for non-zero notes at one particular timestep\n", 430 | " # i is an integer indicating the index of each note the chord\n", 431 | " for i in range(len(chord)):\n", 432 | " \n", 433 | " if chord[i]==\"0\":\n", 434 | " continue\n", 435 | " \n", 436 | " # set note as 2 elements: instrument and index of note\n", 437 | " # examples: p22, p16, p4\n", 438 | " #p = music21.pitch.Pitch()\n", 439 | " #nt = music21.note.Note(p)\n", 440 | " #n.volume.velocity = 20\n", 441 | " #nt.volume.client == nt\n", 442 | " #V = nt.volume.velocity\n", 443 | " #print(V)\n", 444 | " #note=prefix+str(i)+' V' + str(V)\n", 445 | " note=prefix+str(i) \n", 446 | " \n", 447 | " # if note in chord is 1, then append the note eg. p22 to the list\n", 448 | " if chord[i]==\"1\":\n", 449 | " translated_list.append(note)\n", 450 | " \n", 451 | " # If chord[i]==\"2\" do nothing - we're continuing to hold the note\n", 452 | " \n", 453 | " # unless next_chord[i] is back to \"0\" and it's time to end the note.\n", 454 | " if next_chord==\"\" or next_chord[i]==\"0\": \n", 455 | " translated_list.append(\"end\"+note)\n", 456 | "\n", 457 | " # wait indicates end of every timestep\n", 458 | " if prefix==\"p\":\n", 459 | " translated_list.append(\"wait\")\n", 460 | "\n", 461 | " #print(len(translated_list))\n", 462 | " translated_list[:10]\n", 463 | "\n", 464 | " # this section transforms the list of notes into a string of notes\n", 465 | "\n", 466 | " # initialize i as zero and empty string\n", 467 | " i=0\n", 468 | " translated_string=\"\"\n", 469 | "\n", 470 | "\n", 471 | " while i \"wait2\"\n", 475 | " wait_count=1\n", 476 | " if translated_list[i]=='wait':\n", 477 | " while wait_count<=sample_freq*2 and i+wait_count