Spaces:
Running
Running
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Miamuy-midi - Générateur de notes</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| background-color: #f0f8ff; | |
| color: #4b0082; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| margin: 0; | |
| text-align: center; | |
| } | |
| .container { | |
| background-color: white; | |
| padding: 30px; | |
| border-radius: 10px; | |
| box-shadow: 0 0 20px rgba(75, 0, 130, 0.2); | |
| width: 90%; | |
| max-width: 500px; | |
| } | |
| h1 { | |
| color: #4b0082; | |
| margin-bottom: 20px; | |
| } | |
| .input-group { | |
| margin-bottom: 20px; | |
| text-align: left; | |
| } | |
| .input-group label { | |
| display: block; | |
| margin-bottom: 5px; | |
| color: #4b0082; | |
| } | |
| .input-group input[type="text"] { | |
| width: 100%; | |
| padding: 10px; | |
| border: 2px solid #4b0082; | |
| background-color: #e6e6fa; | |
| color: #4b0082; | |
| border-radius: 5px; | |
| box-sizing: border-box; | |
| font-size: 16px; | |
| } | |
| .button-group { | |
| display: flex; | |
| justify-content: center; | |
| gap: 10px; | |
| } | |
| button { | |
| background-color: #4b0082; | |
| color: #fff; | |
| border: none; | |
| padding: 12px 25px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 18px; | |
| transition: background-color 0.3s ease; | |
| } | |
| button:hover { | |
| background-color: #6a0dad; | |
| } | |
| #result { | |
| margin-top: 30px; | |
| padding: 15px; | |
| background-color: #e6e6fa; | |
| border: 2px solid #4b0082; | |
| border-radius: 5px; | |
| font-size: 18px; | |
| color: #4b0082; | |
| word-wrap: break-word; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>🌸Miamuy🌸</h1> | |
| <p>Ton générateur de mélodies midi</p> | |
| <div class="input-group"> | |
| <label for="startNote">Note de départ (ex: C4) :</label> | |
| <input type="text" id="startNote" value="C4"> | |
| </div> | |
| <div class="button-group"> | |
| <button id="generateBtn">Générer et jouer</button> | |
| <button id="downloadBtn" style="display: none;">⬇️ Télécharger MIDI</button> | |
| </div> | |
| <div id="result"> | |
| Mélodie générée : | |
| </div> | |
| </div> | |
| <script src="https://unpkg.com/tone@14.7.58/build/Tone.js"></script> | |
| <script type="module"> | |
| const modelName = 'Clemylia/Miamuy-midi'; | |
| let miamuyModel = null; | |
| let isModelReady = false; | |
| let generatedMidiNotes = null; | |
| const resultDiv = document.getElementById('result'); | |
| const startNoteInput = document.getElementById('startNote'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const downloadBtn = document.getElementById('downloadBtn'); | |
| const synth = new Tone.Synth().toDestination(); | |
| async function initializeModel() { | |
| resultDiv.textContent = 'Chargement du modèle...'; | |
| try { | |
| const response = await fetch(`https://huggingface.co/${modelName}/raw/main/transformer.js`); | |
| if (!response.ok) throw new Error(`Erreur de téléchargement : ${response.statusText}`); | |
| const scriptText = await response.text(); | |
| const scriptBlob = new Blob([scriptText], { type: 'application/javascript' }); | |
| const scriptUrl = URL.createObjectURL(scriptBlob); | |
| const module = await import(scriptUrl); | |
| miamuyModel = new module.default(); | |
| isModelReady = true; | |
| resultDiv.textContent = 'Modèle Miamuy-midi prêt !'; | |
| } catch (error) { | |
| resultDiv.textContent = `Erreur de chargement : ${error.message}`; | |
| console.error(error); | |
| } | |
| } | |
| async function generateAndPlay() { | |
| if (!isModelReady) { | |
| resultDiv.textContent = "Le modèle n'est pas encore prêt. Veuillez patienter."; | |
| return; | |
| } | |
| await Tone.start(); | |
| const startNote = startNoteInput.value; | |
| if (!startNote) { | |
| resultDiv.textContent = "Veuillez entrer une note de départ."; | |
| return; | |
| } | |
| resultDiv.textContent = 'Génération de la mélodie en cours...'; | |
| downloadBtn.style.display = 'none'; | |
| try { | |
| const result = await miamuyModel.generate(startNote); | |
| const generatedNotesText = result[0].generated_text; | |
| generatedMidiNotes = result[0].midi_notes; | |
| resultDiv.textContent = 'Mélodie générée : ' + generatedNotesText; | |
| downloadBtn.style.display = 'block'; | |
| let now = Tone.now(); | |
| generatedNotesText.split(' ').forEach((note, index) => { | |
| synth.triggerAttackRelease(note, "8n", now + index * 0.5); | |
| }); | |
| } catch (error) { | |
| resultDiv.textContent = `Erreur de génération : ${error.message}`; | |
| console.error(error); | |
| } | |
| } | |
| function downloadMidi() { | |
| if (!generatedMidiNotes) { | |
| alert("Veuillez d'abord générer une mélodie."); | |
| return; | |
| } | |
| // --- Le code pour fabriquer le fichier MIDI manuellement --- | |
| const midiHeader = [0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00]; | |
| const midiTrackHeader = [0x4d, 0x54, 0x72, 0x6b]; | |
| const midiData = [ | |
| 0x00, 0x90, 0x00, 0x00, // Note off (default) | |
| ]; | |
| generatedMidiNotes.forEach(note => { | |
| midiData.push( | |
| 0x00, 0x90, note, 0x7F, // Note on | |
| 0x81, 0x00, 0x80, note, 0x7F // Note off (after 1/4 note) | |
| ); | |
| }); | |
| const trackLength = midiData.length; | |
| const trackLengthArray = [ | |
| (trackLength >> 24) & 0xFF, | |
| (trackLength >> 16) & 0xFF, | |
| (trackLength >> 8) & 0xFF, | |
| trackLength & 0xFF | |
| ]; | |
| const midiFile = new Uint8Array([ | |
| ...midiHeader, | |
| ...midiTrackHeader, | |
| ...trackLengthArray, | |
| ...midiData | |
| ]); | |
| const blob = new Blob([midiFile], { type: 'audio/midi' }); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.href = url; | |
| link.download = 'melodie-miamuy.midi'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| } | |
| generateBtn.addEventListener('click', generateAndPlay); | |
| downloadBtn.addEventListener('click', downloadMidi); | |
| initializeModel(); | |
| </script> | |
| </body> | |
| </html> |