{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "cellView": "code",
    "id": "at5_o2QCg6YY"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "from scipy.fft import fft, ifft\n",
    "from IPython.display import Audio, display\n",
    "from scipy.io import wavfile\n",
    "from ipywidgets import widgets\n",
    "from functools import partial\n",
    "import pandas as pd\n",
    "from fractions import Fraction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "id": "C2t7WxG-jJac"
   },
   "outputs": [],
   "source": [
    "def create_signal(frequency, amplitude, delay, phase=0, sampling=44100, seconds=1.0):\n",
    "  timesteps = np.linspace(0,seconds, int(seconds * sampling))\n",
    "  # return np.sum(amplitude * np.sin(frequency * 2*np.pi * (timesteps[:, np.newaxis]-delay)*(timesteps[:, np.newaxis]-delay > 0)), axis=1), timesteps\n",
    "  return np.sum(amplitude * triangle(frequency, (timesteps[:, np.newaxis]-delay)*(timesteps[:, np.newaxis]-delay > 0)), axis=1), timesteps\n",
    "\n",
    "def create_waves(frequency, amplitude, phase=0, sampling=44100, seconds=1.0):\n",
    "  timesteps = np.linspace(0,seconds, int(seconds * sampling))\n",
    "  # return amplitude * np.sin(frequency * 2*np.pi * timesteps[:, np.newaxis]), timesteps\n",
    "  return amplitude * triangle(frequency, timesteps[:, np.newaxis]), timesteps\n",
    "\n",
    "def triangle(frequency, t):\n",
    "  phase = (t * frequency + 0.25) % 1 - 0.25\n",
    "  return (phase <= 0.25) * phase + (phase > 0.25) * (0.5 - phase)\n",
    "\n",
    "def nonlinearity(x, param=1.0): # param for scaling of argument; higher values = more nonlinearity\n",
    "  #return np.exp(x*param)\n",
    "  return np.sign(x)*np.log(1+np.abs(x*param))\n",
    "\n",
    "def myAudio(signal, rate=44100, autoplay=False, time_fade=0.2):\n",
    "  length = signal.shape[0]\n",
    "  print(length)\n",
    "  fade = np.minimum(np.ones(length),np.arange(length)/(time_fade * rate))\n",
    "  return Audio(signal * fade * fade[::-1],rate=rate,autoplay=autoplay)\n",
    "\n",
    "def toEDO(ratio, n=12):\n",
    "    return 2**((np.round(np.log(ratio) * n / np.log(2)))/n)\n",
    "\n",
    "def ratio2freq(ratio, base=220):\n",
    "    return base * ratio\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 897
    },
    "id": "yfTtI-OVmXIo",
    "outputId": "24995b1b-a7f5-486a-abe3-865685474314"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88200\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" >\n",
       "                    <source src=\"data:audio/wav;base64,[encoded data, 235260 characters]\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88200\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" >\n",
       "                    <source src=\"data:audio/wav;base64,[encoded data, 235260 characters]\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88200\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" >\n",
       "                    <source src=\"data:audio/wav;base64,[encoded data, 235260 characters]\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 186868 characters]\n",
      "text/plain": [
       "<Figure size 1440x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 150820 characters]\n",
      "text/plain": [
       "<Figure size 2880x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#frequency = np.array([100., 200., 300, 400])\n",
    "\n",
    "#frequency_edo12 = 220 * 2**(np.array([5,8,12,14])/12)\n",
    "#frequency_edo53 = 220 * 2**(np.array([22,36,53,62])/53)\n",
    "#frequency_edo53 = 220 * 2**(np.array([22,34,53,61])/53)\n",
    "#frequency_rein1 = 220 * 4/3 * np.array([1, 7/6, 9/6, 10/6])\n",
    "#frequency_rein2 = 220 * 4/3 * np.array([1, 12/10, 15/10, 17/10])\n",
    "dursept = 4/3*np.array([1,5/4,6/4,7/4])\n",
    "\n",
    "dursept_edo12 = 220 * toEDO(dursept, 12) # Durseptakkord in EDO12\n",
    "\n",
    "\n",
    "dursept_edo53 = 220 * toEDO(dursept, 53) # Dursept in EDO53\n",
    "\n",
    "dursept_rein = 220 * dursept # Dursept rein\n",
    "\n",
    "mollsept = 4/3 * np.array([1,12/10, 15/10, 17/10])\n",
    "mollsept_edo12 = 220 * toEDO(mollsept, 12) # Mollseptakkord in EDO12\n",
    "mollsept_edo53 = 220 * toEDO(mollsept, 53) # Mollseptakkord in EDO53\n",
    "mollsept_rein = 220 * mollsept # Mollsept rein\n",
    "\n",
    "doppeltritone = 4/3 * np.array([1, 12/10, 14/10, 17/10])\n",
    "doppeltritone_rein = 220 * doppeltritone # doppeltritone rein\n",
    "doppeltritone_edo12 = 220* toEDO(doppeltritone, 12)\n",
    "doppeltritone_edo53 = 220 * toEDO(doppeltritone, 53) # doppeltritone in EDO53\n",
    "\n",
    "amplitude = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])\n",
    "delay = np.array([0.0,0.2,0.4,0.6,0.8,1.0,1.2])\n",
    "\n",
    "# list of chords to display.\n",
    "# chords = [dursept_edo12, dursept_edo53, dursept_rein, ]\n",
    "# chords = [mollsept_edo12, mollsept_edo53, mollsept_rein, ]\n",
    "chords = [mollsept_edo12, mollsept_edo53, mollsept_rein ]\n",
    "\n",
    "to_display = []\n",
    "for chord in chords:\n",
    "    notes = len(chord)\n",
    "    signal, timesteps = create_signal(frequency=chord, amplitude=amplitude[:notes], delay=delay[:notes], phase=0, sampling=44100, seconds=5.0)\n",
    "    to_display.append(signal)\n",
    "\n",
    "max_play_time = 2.0\n",
    "for signal in to_display:\n",
    "    display(myAudio(signal[timesteps < max_play_time],rate=44100, autoplay=False))\n",
    "\n",
    "plot_time = 1.0\n",
    "\n",
    "plt.figure(1, figsize=(20,6))\n",
    "plt.xlabel(\"time [s]\")\n",
    "for signal in to_display:\n",
    "    plt.plot(timesteps[timesteps < plot_time], (1*signal[timesteps < plot_time]))\n",
    "\n",
    "plt.figure(2, figsize=(40,6))\n",
    "plt.subplot(111, xscale='log', yscale='log')\n",
    "plt.xlabel(\"Frequenz [Hz]\")\n",
    "plt.xlim(200,5000)\n",
    "plt.ylim(bottom=1e-1, top=1e4)\n",
    "for signal in to_display:\n",
    "    plt.plot(np.abs(fft(nonlinearity(signal[timesteps > 1.0], 0.1))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "uj1KsDoBQkym"
   },
   "source": [
    "A = 100, B = 152\n",
    "B-A = 52, 2*A-B = 48\n",
    "A = 100, 2*B-2*A = 104, 4*A-2*B=96\n",
    "2*A = 200, 2*B-A = 204, 4*B-4*A = 208"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 35
    },
    "id": "mGVxOys101H8",
    "outputId": "987a6b57-7b4a-49dc-bcb1-4970f7d664a9"
   },
   "source": [
    "#print((3/2)**3) #3 Quinten\n",
    "#print(2**2) #2 Oktaven\n",
    "81/80 #syntonisches Komma\n",
    "128/125 #Diesis\n",
    "(3/2)^12/2^7 #pythagoräisches Komma\n",
    "#print(6/5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EImFLStM4Cya"
   },
   "source": [
    "1 (C) 9/8 (D)   6/5 (Es)   5/4 (E)    4/3 (F)  3/2 (G) 8/5 (As) 5/3 (A) 15/8 (H) 2/1 (C) --> 5-limit tuning\n",
    "Ganztöne?\n",
    "C - D: 9/8\n",
    "D - E: 10/9\n",
    "Es - F: 10/9\n",
    "F - G: 9/8\n",
    "G - A: 10/9\n",
    "A - H: 9/8\n",
    "\n",
    "Halbtöne? 16/15, 25/24, 16/15, 16/15, 25/24, 16/15\n",
    "Große Terzen? 5/4, 5/4, 32/25, 5/4, 5/4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3-MNtcii-OMi"
   },
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 72
    },
    "id": "TtnU4FRY_p8f",
    "outputId": "8fdcbdec-f213-40f2-ea53-0cebd30d7eaa"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.125 1.122462048309373\n",
      "1.25 1.2599210498948732\n",
      "1.75 1.7817974362806785\n"
     ]
    }
   ],
   "source": [
    "print(9/8, 2**(2/12))\n",
    "print(5/4, 2**(4/12))\n",
    "print(7/4, 2**(10/12))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5mZHNFRO_xgZ"
   },
   "source": [
    "(3/2)**a = 2**b \n",
    "a * ln(3/2) = b * ln(2)\n",
    "a/b = ln(2) / ln(3/2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "85VfR2WxHAx9"
   },
   "source": [
    "[1; 1, 2, 2, 3, 1, 5, 2, 23, 2, 2, 1, 1, 55, 1, 4, 3, 1, 1, 15, 1, 9, 2, 5, 7, 1, 1, 4, 8, 1, 1, ...]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 35
    },
    "id": "61-Z8SsfHCe3",
    "outputId": "da53b747-99e4-4277-fc5f-27413ec67962"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.7096774193548385"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1 + 1/(1+1/2) #--> a=5, b=3\n",
    "1 + 1/(1+1/(2+1/2)) #--> a=12, b=7\n",
    "1 + 1/(1+1/(2+1/(2+1/3))) #--> a=41, b=24\n",
    "1 + 1/(1+1/(2+1/(2+1/(3+1)))) #--> a=53, b=31"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "iGJ4mYrSHF59",
    "outputId": "92fe9b7d-7542-43b7-f410-0213308084d2"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.5\n",
      "1.515716566510398\n",
      "1.4983070768766815\n",
      "1.4937589616544857\n",
      "1.5004194330574077\n",
      "1.4999409030781112\n"
     ]
    }
   ],
   "source": [
    "print(3/2)\n",
    "print(2**(3/5))\n",
    "print(2**(7/12))\n",
    "print(2**(11/19))\n",
    "print(2**(24/41))\n",
    "print(2**(31/53))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "WNsx7Md7UqM2"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "Akkorde",
   "provenance": []
  },
  "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.10.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
