{ "cells": [ { "metadata": {}, "cell_type": "markdown", "source": [ "\"Open\n", "\n", "# BeatHeritage V1 - Beatmap Generator\n", "\n", "An enhanced AI model for generating osu! beatmaps with improved stability and quality control.\n", "\n", "\n", "### Instructions:\n", "1. **Read and accept the rules** by clicking the checkbox in the first cell\n", "2. **Ensure GPU runtime**: Go to __Runtime โ†’ Change Runtime Type โ†’ GPU__\n", "3. **Execute cells in order**: Click โ–ถ๏ธ on each cell sequentially\n", "4. **Upload your audio**: Choose an MP3/OGG file when prompted\n", "5. **Configure parameters**: Adjust settings to your preference\n", "6. **Generate beatmap**: Run the generation cell and wait for results\n" ] }, { "cell_type": "code", "metadata": {}, "source": [ "#@title ๐Ÿš€ Setup Environment { display-mode: \"form\" }\n", "#@markdown ### โš ๏ธ Important: Please use this tool responsibly\n", "#@markdown - Always disclose AI usage in your beatmap descriptions\n", "#@markdown - Respect the original music artists and mappers\n", "#@markdown - This tool is for educational and creative purposes\n", "\n", "i_accept_the_rules = False #@param {type:\"boolean\"}\n", "#@markdown โ˜‘๏ธ **I accept the rules and will use this tool responsibly**\n", "\n", "import os\n", "import sys\n", "\n", "if not i_accept_the_rules:\n", " raise ValueError(\"Please read and accept the rules before proceeding!\")\n", "\n", "print(\"Installing BeatHeritage...\")\n", "print(\"=\"*50)\n", "\n", "# Clone repository if not exists\n", "if not os.path.exists('/content/BeatHeritage'):\n", " !git clone -q https://github.com/hongminh54/BeatHeritage.git\n", " print(\"โœ… Repository cloned\")\n", "else:\n", " print(\"โœ… Repository already exists\")\n", "\n", "%cd /content/BeatHeritage\n", "\n", "# Install dependencies\n", "print(\"\\nInstalling dependencies...\")\n", "!pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118\n", "!pip install -q -r requirements.txt\n", "!apt-get install -y ffmpeg > /dev/null 2>&1\n", "\n", "print(\"\\nSetup complete!\")\n", "\n", "# Import required libraries\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "import torch\n", "from google.colab import files\n", "from IPython.display import display, HTML, Audio\n", "from pathlib import Path\n", "import json\n", "import shlex\n", "import subprocess\n", "from datetime import datetime\n", "import zipfile\n", "\n", "# Check GPU availability\n", "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", "print(f\"\\nUsing device: {device}\")\n", "if device == 'cuda':\n", " gpu_name = torch.cuda.get_device_name(0)\n", " gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1024**3\n", " print(f\"GPU: {gpu_name}\")\n", " print(f\"Memory: {gpu_memory:.1f} GB\")\n", "else:\n", " print(\"No GPU detected! Generation will be VERY slow.\")\n", "\n", "# Initialize global variables\n", "audio_path = \"\"\n", "output_path = \"/content/BeatHeritage/output\"\n", "os.makedirs(output_path, exist_ok=True)" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "#@title ๐ŸŽต Upload Audio File { display-mode: \"form\" }\n", "#@markdown Upload your audio file (MP3, OGG, or WAV format)\n", "\n", "def upload_and_validate_audio():\n", " \"\"\"Upload and validate audio file with proper error handling\"\"\"\n", " global audio_path\n", " \n", " print(\"Please select an audio file to upload...\")\n", " uploaded = files.upload()\n", " \n", " if not uploaded:\n", " print(\"No file uploaded\")\n", " return None\n", " \n", " # Get the first uploaded file\n", " original_filename = list(uploaded.keys())[0]\n", " \n", " # Clean filename - remove special characters and spaces\n", " import re\n", " clean_filename = re.sub(r'[^a-zA-Z0-9._-]', '_', original_filename)\n", " clean_filename = clean_filename.replace(' ', '_')\n", " \n", " # Ensure proper extension\n", " if not any(clean_filename.lower().endswith(ext) for ext in ['.mp3', '.ogg', '.wav']):\n", " print(f\"Invalid file format: {original_filename}\")\n", " print(\"Please upload an MP3, OGG, or WAV file\")\n", " return None\n", " \n", " # Save with cleaned filename\n", " audio_path = f'/content/BeatHeritage/{clean_filename}'\n", " \n", " # Write the uploaded content to the new path\n", " with open(audio_path, 'wb') as f:\n", " f.write(uploaded[original_filename])\n", " \n", " print(f\"Audio uploaded successfully!\")\n", " print(f\"Original: {original_filename}\")\n", " print(f\"Saved as: {clean_filename}\")\n", " print(f\"Path: {audio_path}\")\n", " \n", " # Display audio player\n", " display(Audio(audio_path))\n", " \n", " return audio_path\n", "\n", "# Upload audio\n", "audio_path = upload_and_validate_audio()\n", "\n", "if not audio_path:\n", " print(\"\\nโš Please run this cell again and upload a valid audio file\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "#@title โš™๏ธ Configure Generation Parameters { display-mode: \"form\" }\n", "\n", "#@markdown ### ๐ŸŽฏ Basic Settings\n", "#@markdown ---\n", "#@markdown Choose the AI model version to use:\n", "model_version = \"BeatHeritage V1 (Enhanced)\" #@param [\"BeatHeritage V1 (Enhanced)\", \"Mapperatorinator V30\", \"Mapperatorinator V29\", \"Mapperatorinator V28\"]\n", "\n", "#@markdown Select the game mode for your beatmap:\n", "gamemode = \"Standard\" #@param [\"Standard\", \"Taiko\", \"Catch the Beat\", \"Mania\"]\n", "\n", "#@markdown Target difficulty (โ˜… rating):\n", "difficulty = 5.5 #@param {type:\"slider\", min:1, max:10, step:0.1}\n", "\n", "#@markdown ### ๐ŸŽจ Style Configuration\n", "#@markdown ---\n", "#@markdown Primary mapping style descriptor:\n", "descriptor_1 = \"clean\" #@param [\"clean\", \"tech\", \"jump aim\", \"stream\", \"aim\", \"speed\", \"flow\", \"complex\", \"simple\", \"modern\", \"classic\", \"slider tech\", \"alt\", \"precision\", \"stamina\"]\n", "\n", "#@markdown Secondary style descriptor (optional):\n", "descriptor_2 = \"\" #@param [\"\", \"clean\", \"tech\", \"jump aim\", \"stream\", \"aim\", \"speed\", \"flow\", \"complex\", \"simple\", \"modern\", \"classic\", \"slider tech\", \"alt\", \"precision\", \"stamina\"]\n", "\n", "#@markdown ### ๐Ÿ”ง Advanced Parameters\n", "#@markdown ---\n", "#@markdown Generation temperature (lower = more conservative):\n", "temperature = 0.85 #@param {type:\"slider\", min:0.1, max:2.0, step:0.05}\n", "\n", "#@markdown Top-p sampling (nucleus sampling):\n", "top_p = 0.92 #@param {type:\"slider\", min:0.1, max:1.0, step:0.01}\n", "\n", "#@markdown Classifier-free guidance scale:\n", "cfg_scale = 7.5 #@param {type:\"slider\", min:1.0, max:20.0, step:0.5}\n", "\n", "#@markdown ### ๐Ÿ“Š Quality Control (BeatHeritage V1)\n", "#@markdown ---\n", "enable_auto_correction = True #@param {type:\"boolean\"}\n", "enable_flow_optimization = True #@param {type:\"boolean\"}\n", "enable_pattern_variety = True #@param {type:\"boolean\"}\n", "\n", "#@markdown ### ๐ŸŽฏ Export Options\n", "#@markdown ---\n", "super_timing = False #@param {type:\"boolean\"}\n", "#@markdown Enable for songs with variable BPM (slower generation)\n", "\n", "export_osz = True #@param {type:\"boolean\"}\n", "#@markdown Export as .osz package (includes audio)\n", "\n", "# Map model names to config names\n", "model_configs = {\n", " \"BeatHeritage V1 (Enhanced)\": \"beatheritage_v1\",\n", " \"Mapperatorinator V30\": \"v30\",\n", " \"Mapperatorinator V29\": \"v29\",\n", " \"Mapperatorinator V28\": \"v28\"\n", "}\n", "\n", "# Map gamemode names to indices\n", "gamemode_indices = {\n", " \"Standard\": 0,\n", " \"Taiko\": 1,\n", " \"Catch the Beat\": 2,\n", " \"Mania\": 3\n", "}\n", "\n", "selected_model = model_configs[model_version]\n", "selected_gamemode = gamemode_indices[gamemode]\n", "\n", "# Build descriptor list\n", "descriptors = [d for d in [descriptor_1, descriptor_2] if d]\n", "\n", "# Display configuration summary\n", "print(\"Configuration Summary\")\n", "print(\"=\"*50)\n", "print(f\"Model: {model_version}\")\n", "print(f\"Game Mode: {gamemode}\")\n", "print(f\"Difficulty: {difficulty}โ˜…\")\n", "print(f\"Style: {', '.join(descriptors) if descriptors else 'Default'}\")\n", "print(f\"Temperature: {temperature}\")\n", "print(f\"Top-p: {top_p}\")\n", "print(f\"CFG Scale: {cfg_scale}\")\n", "\n", "if selected_model == \"beatheritage_v1\":\n", " print(\"\\nBeatHeritage V1 Features:\")\n", " if enable_auto_correction:\n", " print(\" โœ“ Auto-correction enabled\")\n", " if enable_flow_optimization:\n", " print(\" โœ“ Flow optimization enabled\")\n", " if enable_pattern_variety:\n", " print(\" โœ“ Pattern variety enabled\")\n", "\n", "if super_timing:\n", " print(\"\\nSuper timing enabled (for variable BPM)\")\n", "\n", "print(\"\\nConfiguration ready!\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "#@title ๐ŸŽฎ Generate Beatmap { display-mode: \"form\" }\n", "#@markdown Click the play button to start generation. This may take a few minutes depending on song length.\n", "\n", "def generate_beatmap():\n", " \"\"\"Generate beatmap with proper error handling and progress tracking\"\"\"\n", " \n", " if not audio_path or not os.path.exists(audio_path):\n", " print(\"Error: No audio file found!\")\n", " print(\"Please upload an audio file first.\")\n", " return None\n", " \n", " print(\"Starting beatmap generation...\")\n", " print(\"=\"*50)\n", " print(f\"Audio: {os.path.basename(audio_path)}\")\n", " print(f\"Model: {model_version}\")\n", " print(f\"Mode: {gamemode}\")\n", " print(f\"Difficulty: {difficulty}โ˜…\")\n", " print(\"=\"*50)\n", " print()\n", " \n", " # Build command with proper escaping\n", " cmd = [\n", " 'python', 'inference.py',\n", " '-cn', selected_model,\n", " f'audio_path={shlex.quote(audio_path)}',\n", " f'output_path={shlex.quote(output_path)}',\n", " f'gamemode={selected_gamemode}',\n", " f'difficulty={difficulty}',\n", " f'temperature={temperature}',\n", " f'top_p={top_p}',\n", " f'cfg_scale={cfg_scale}',\n", " f'super_timing={str(super_timing).lower()}',\n", " f'export_osz={str(export_osz).lower()}',\n", " ]\n", " \n", " # Add descriptors if specified\n", " if descriptors:\n", " desc_str = json.dumps(descriptors)\n", " cmd.append(f'descriptors={shlex.quote(desc_str)}')\n", " \n", " # Add BeatHeritage V1 specific features\n", " if selected_model == \"beatheritage_v1\":\n", " if enable_auto_correction:\n", " cmd.append('quality_control.enable_auto_correction=true')\n", " if enable_flow_optimization:\n", " cmd.append('quality_control.enable_flow_optimization=true')\n", " if enable_pattern_variety:\n", " cmd.append('advanced_features.enable_pattern_variety=true')\n", " \n", " # Always enable these for V1\n", " cmd.extend([\n", " 'advanced_features.enable_context_aware_generation=true',\n", " 'advanced_features.enable_style_preservation=true',\n", " 'generate_positions=true',\n", " 'position_refinement=true'\n", " ])\n", " \n", " # Execute command\n", " try:\n", " print(\"โณ Generating beatmap... (this may take several minutes)\\n\")\n", " \n", " # Run the command\n", " process = subprocess.Popen(\n", " cmd,\n", " stdout=subprocess.PIPE,\n", " stderr=subprocess.STDOUT,\n", " text=True,\n", " bufsize=1,\n", " universal_newlines=True\n", " )\n", " \n", " # Stream output in real-time\n", " for line in process.stdout:\n", " print(line, end='')\n", " \n", " # Wait for completion\n", " return_code = process.wait()\n", " \n", " if return_code == 0:\n", " print(\"\\n\" + \"=\"*50)\n", " print(\"Beatmap generation complete!\")\n", " \n", " # List generated files\n", " generated_files = list(Path(output_path).glob('*'))\n", " if generated_files:\n", " print(f\"\\nGenerated {len(generated_files)} file(s):\")\n", " for file in generated_files:\n", " size_mb = file.stat().st_size / (1024 * 1024)\n", " print(f\" โ€ข {file.name} ({size_mb:.2f} MB)\")\n", " \n", " return generated_files\n", " else:\n", " print(f\"\\nGeneration failed with error code: {return_code}\")\n", " return None\n", " \n", " except Exception as e:\n", " print(f\"\\nError during generation: {str(e)}\")\n", " print(\"\\nTroubleshooting tips:\")\n", " print(\"1. Ensure the audio file is valid\")\n", " print(\"2. Check if GPU memory is sufficient\")\n", " print(\"3. Try reducing temperature or cfg_scale\")\n", " print(\"4. Disable super_timing if enabled\")\n", " return None\n", "\n", "# Run generation\n", "generated_files = generate_beatmap()" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "#@title ๐Ÿ“ฅ Download Generated Files { display-mode: \"form\" }\n", "#@markdown Download your generated beatmap files\n", "\n", "def download_results():\n", " \"\"\"Package and download generated beatmap files\"\"\"\n", " \n", " output_files = list(Path(output_path).glob('*'))\n", " \n", " if not output_files:\n", " print(\"No files to download\")\n", " print(\"Please generate a beatmap first.\")\n", " return\n", " \n", " print(\"Preparing files for download...\")\n", " print(\"=\"*50)\n", " \n", " # Create timestamp for unique naming\n", " timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')\n", " \n", " # Check if we have .osz files\n", " osz_files = [f for f in output_files if f.suffix == '.osz']\n", " osu_files = [f for f in output_files if f.suffix == '.osu']\n", " \n", " # Download .osz files directly if available\n", " if osz_files:\n", " for osz_file in osz_files:\n", " print(f\"\\n๐Ÿ“ฅ Downloading: {osz_file.name}\")\n", " files.download(str(osz_file))\n", " \n", " # Download .osu files\n", " elif osu_files:\n", " if len(osu_files) == 1:\n", " # Single file - download directly\n", " osu_file = osu_files[0]\n", " print(f\"\\n๐Ÿ“ฅ Downloading: {osu_file.name}\")\n", " files.download(str(osu_file))\n", " else:\n", " # Multiple files - create zip\n", " zip_name = f'beatheritage_{gamemode.lower()}_{timestamp}.zip'\n", " zip_path = f'/content/{zip_name}'\n", " \n", " with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:\n", " for file in output_files:\n", " zipf.write(file, file.name)\n", " print(f\" โ€ข Added: {file.name}\")\n", " \n", " print(f\"\\nDownloading: {zip_name}\")\n", " files.download(zip_path)\n", " \n", " # Also handle other files\n", " other_files = [f for f in output_files if f.suffix not in ['.osz', '.osu']]\n", " if other_files:\n", " print(\"\\nAdditional files generated:\")\n", " for file in other_files:\n", " print(f\" โ€ข {file.name}\")\n", " \n", " print(\"\\nDownload complete!\")\n", " print(\"\\nTips:\")\n", " print(\"โ€ข .osz files can be opened directly in osu!\")\n", " print(\"โ€ข .osu files should be placed in your Songs folder\")\n", " print(\"โ€ข Press F5 in osu! to refresh after adding files\")\n", "\n", "# Download files\n", "download_results()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Additional Information\n", "\n", "### Tips for Best Results:\n", "- **Audio Quality**: Use high-quality audio files (320kbps MP3 or FLAC)\n", "- **Difficulty Matching**: Match the difficulty rating to song intensity\n", "- **Style Descriptors**: Choose descriptors that match the music genre\n", "- **Variable BPM**: Enable `super_timing` for songs with tempo changes\n", "\n", "### Troubleshooting:\n", "\n", "**Out of Memory:**\n", "- Restart runtime to clear GPU memory\n", "- Use shorter songs or segments\n", "- Reduce cfg_scale value\n", "\n", "**Poor Quality Output:**\n", "- Lower temperature (0.7-0.8) for stability\n", "- Increase cfg_scale (10-15) for stronger guidance\n", "- Use more specific descriptors\n", "\n", "**Generation Errors:**\n", "- Ensure audio file has no special characters\n", "- Check GPU is enabled in runtime\n", "- Try different model versions\n", "\n", "### Resources:\n", "- [GitHub Repository](https://github.com/hongminh54/BeatHeritage)\n", "- [Documentation](https://github.com/hongminh54/BeatHeritage/blob/main/README.md)\n", "\n", "### License & Credits:\n", "- BeatHeritage V1 by hongminh54\n", "- Based on Mapperatorinator by OliBomby\n", "- Please credit AI usage in your beatmap descriptions\n", "\n", "---" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.0" }, "colab": { "provenance": [], "gpuType": "T4", "collapsed_sections": [] }, "accelerator": "GPU" }, "nbformat": 4, "nbformat_minor": 4 }