{ "cells": [ { "cell_type": "markdown", "id": "af88475b-b18e-4512-bc1e-a1c7ebc3f2eb", "metadata": {}, "source": [ "# Generate a musique from equation" ] }, { "cell_type": "code", "execution_count": 1, "id": "70848987-2c52-4eaf-ad1f-7c30a7d354b8", "metadata": {}, "outputs": [], "source": [ "import cutcutcodec" ] }, { "cell_type": "markdown", "id": "41de16ff-14d9-41d4-8a72-165a8bd70f04", "metadata": {}, "source": [ "## Simplified functions that generate musical note equations\n", "\n", "* A note is considered as a fundamental and harmonics.\n", "* We consider an extremely simplified ADSR envellope" ] }, { "cell_type": "code", "execution_count": 2, "id": "952c2443-0e44-4658-85d4-e938d13a1a67", "metadata": {}, "outputs": [], "source": [ "# very simple note model\n", "\n", "def adsr(start: float, duration: float) -> str:\n", " \"\"\"Return the Attack, Decrease, Sustain and Release envellope equation.\"\"\"\n", " atack = f\"1/2 + atan(5*(t-{start}))/pi\"\n", " decrease_sustain = f\"1 - 0.05*(t-{start})\"\n", " release = f\"1/2 - atan(2*(t-{start+duration}-0.2))/pi\"\n", " return f\"({atack}) * ({decrease_sustain}) * ({release})\"\n", "\n", "def spectral(freq: float) -> str:\n", " \"\"\"Return the equation of an infinite note with harmonics.\"\"\"\n", " return \" + \".join(f\"0.25*{2**-i}*sin(2*pi*{freq*i}*t)\" for i in range(1, 9))\n", "\n", "def note(freq: float, start: float, duration: float) -> str:\n", " \"\"\"A finite duration note.\"\"\"\n", " return f\"({adsr(start, duration)}) * ({spectral(freq)})\"" ] }, { "cell_type": "code", "execution_count": 3, "id": "c3a19ad6-8834-4ea4-b12a-a11b0b2baf01", "metadata": {}, "outputs": [], "source": [ "# associate a frequency to each note\n", "\n", "# for a temperated octave scale\n", "R = 2.0**(1.0/12.0)\n", "\n", "# diapason\n", "A4 = 440.0\n", "\n", "# first octave\n", "C4 = A4*R**-9\n", "CIS4 = DES4 = A4*R**-8\n", "D4 = A4*R**-7\n", "DIS4 = EES4 = A4*R**-6\n", "E4 = A4*R**-5\n", "F4 = A4*R**-4\n", "FIS4 = GES4 = A4*R**-3\n", "G4 = A4*R**-2\n", "GIS4 = AES4 = A4*R**-1\n", "AIS4 = BES4 = A4*R**1\n", "B4 = A4*R**2\n", "\n", "# copy octaves\n", "C0, C1, C2, C3, C5, C6 = C4/16, C4/8, C4/4, C4/2, C4*2, C4*4\n", "CIS0, CIS1, CIS2, CIS3, CIS5, CIS6 = CIS4/16, CIS4/8, CIS4/4, CIS4/2, CIS4*2, CIS4*4\n", "DES0, DES1, DES2, DES3, DES5, DES6 = CIS0, CIS1, CIS2, CIS3, CIS5, CIS6\n", "D0, D1, D2, D3, D5, D6 = D4/16, D4/8, D4/4, D4/2, D4*2, D4*4\n", "DIS0, DIS1, DIS2, DIS3, DIS5, DIS6 = DIS4/16, DIS4/8, DIS4/4, DIS4/2, DIS4*2, DIS4*4\n", "EES0, EES1, EES2, EES3, EES5, EES6 = DIS0, DIS1, DIS2, DIS3, DIS5, DIS6\n", "E0, E1, E2, E3, E5, E6 = E4/16, E4/8, E4/4, E4/2, E4*2, E4*4\n", "F0, F1, F2, F3, F5, F6 = F4/16, F4/8, F4/4, F4/2, F4*2, F4*4\n", "FIS0, FIS1, FIS2, FIS3, FIS5, FIS6 = FIS4/16, FIS4/8, FIS4/4, FIS4/2, FIS4*2, FIS4*4\n", "GES0, GES1, GES2, GES3, GES5, GES6 = FIS0, FIS1, FIS2, FIS3, FIS5, FIS6\n", "G0, G1, G2, G3, G5, G6 = G4/16, G4/8, G4/4, G4/2, G4*2, G4*4\n", "GIS0, GIS1, GIS2, GIS3, GIS5, GIS6 = GIS4/16, GIS4/8, GIS4/4, GIS4/2, GIS4*2, GIS4*4\n", "AES0, AES1, AES2, AES3, AES5, AES6 = GIS0, GIS1, GIS2, GIS3, GIS5, GIS6\n", "A0, A1, A2, A3, A5, A6 = A4/16, A4/8, A4/4, A4/2, A4*2, A4*4\n", "AIS0, AIS1, AIS2, AIS3, AIS5, AIS6 = AIS4/16, AIS4/8, AIS4/4, AIS4/2, AIS4*2, AIS4*4\n", "BES0, BES1, BES2, BES3, BES5, BES6 = AIS0, AIS1, AIS2, AIS3, AIS5, AIS6\n", "B0, B1, B2, B3, B5, B6 = B4/16, B4/8, B4/4, B4/2, B4*2, B4*4" ] }, { "cell_type": "markdown", "id": "7337520e-fade-4c42-8d8d-7617b95a5db4", "metadata": {}, "source": [ "## Assembling notes to create a music" ] }, { "cell_type": "code", "execution_count": 4, "id": "916d6f2d-06f8-4de9-a62b-55ac2cf955a0", "metadata": {}, "outputs": [], "source": [ "music_equation = \" + \".join([ # sd mvt of the sd concerto of rachmaninof\n", " note(C3, 0, 2), note(EES3, 0, 2), note(G3, 0, 2), note(C4, 0, 2),\n", " note(BES2, 2, 1.5), note(F3, 2, 2), note(BES3, 2, 4), note(D4, 2, 2),\n", " note(AES2, 3.5, 0.5),\n", " note(G2, 4, 2), note(EES3, 4, 2), note(EES4, 4, 2),\n", " note(F2, 6, 2), note(C3, 6, 2), note(AES3, 6, 2), note(C4, 6, 4), note(F4, 6, 2),\n", " note(EES2, 8, 2), note(EES3, 8, 2), note(G3, 8, 2), note(G4, 8, 2),\n", " note(GIS1, 10, 1), note(GIS2, 10, 4), note(GIS3, 10, 4), note(C4, 10, 2), note(GIS4, 10, 4),\n", " note(FIS2, 11, 1),\n", " note(E2, 12, 1), note(A3, 12, 1), note(CIS4, 12, 1),\n", " note(D2, 13, 1), note(C4, 13, 1), note(DIS4, 13, 1),\n", " note(CIS2, 14, 1), note(CIS3, 14, 1), note(CIS4, 14, 1), note(E4, 14, 1),\n", " note(C2, 15, 1), note(C3, 15, 1), note(DIS4, 15, 1), note(FIS4, 15, 1),\n", " note(E0, 16, 4), note(E1, 16, 4), note(GIS3, 16, 4), note(B3, 16, 4), note(E4, 16, 4), note(GIS4, 16, 4),\n", "])" ] }, { "cell_type": "markdown", "id": "6fa78e9b-4738-4f83-932e-dffcf1e3ed2a", "metadata": {}, "source": [ "## Write the music file" ] }, { "cell_type": "code", "execution_count": 5, "id": "02bf29ce-9e43-49a0-a253-5ff6f1a9106d", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Encoding my_music.opus: 100%|█████████████████████████████████| 22.00s/22.00s [00:11<00:00]\n" ] } ], "source": [ "SETTINGS = [{\"encodec\": \"opus\", \"rate\": 48000, \"bitrate\": 128000}]\n", "stream = cutcutcodec.generation.audio.GeneratorAudioEquation(music_equation).out_streams[0]\n", "stream = stream.apply_audio_cut(22)\n", "cutcutcodec.write([stream], \"/tmp/my_music.opus\", streams_settings=SETTINGS)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.13.2" } }, "nbformat": 4, "nbformat_minor": 5 }