9. Entonasyon Analizi#

Open In Colab

9.1. Entonasyon Analizi#

Bir önceki defterimizde monofonik bir ses kaydında icra edilen ezgiyi sinyalin ardışık küçük kesitlerinde temel titreşim frekansı kestirimi yapıp bu değerlerden bir seri oluşturarak temsil etmiştik. Çizdirdiğimizde frekansın zamanla nasıl değiştiğini gözleyebildiğimiz bu dizilere frekans (zaman) serisi/dizisi adı verebiliriz. Bu defterde, ses sinyalinden otomatik analizle elde ettiğimiz bu dizilerin işlenmesini ele alacağız.

Frekans dizilerinin işlendiği birçok müzik sinyal işleme problemi vardır. Örneğin frekans dizisinden yola çıkarak nota dizisi tespit etmek, otomatik notaya dökme işlemi gerçekleştirmek isteyebiliriz. Veya elimizde eserin notası var ise nota ile ses kaydı arasında bir hizalama (zamanda eşleme) işlemi yapmak isteyebiliriz.

Bu defterde örnek uygulama olarak şu problemi ele alacağız: Klasik ve pop türünde Batı müziği kayıtları için nota frekanslarına dair yaygın kabul gören bir standart bulunmaktadır ve standart gerçek icra ile büyük oranda uyuşmaktadır. Ancak bu durum birçok müzik kültürü için geçerli değildir; bazı müzik kültürlerinde yaygın kabul gören standart bulunmamakta, bazılarında ise kabul gören standart bulunmakla beraber icra ile bazı yönlerden uyuşmazlık gözlenmektedir. İcra ile kuram arasında uyuşmazlıkların gözlendiği durumlarda ses sinyal işleme bize problemi tespit etme ve anlama konusunda yardımcı olabilir.

Örneğin Türk makam müziğinde Hüzzam makamını ele alalım. Bu makamda icra edilen müzikal aralıkların (notaların frekansları arası oranlar/uzaklıklar) yaygın kullanılan kuramda açıklanan ile uyumlu olmadığına birçok kaynakta değinilmektedir (örnek). Bu makamda bir icranın kaydından yola çıkarak otomatik analiz ile kayıtta kullanılan müzikal aralıkları tespit edebilir miyiz? Bu defterimizde bu problemi ele alalım.

Bunun için ilk olarak bir dizi kısa kaydı indirecek, frekans kestirimi yapıp frekans serilerini elde edeceğiz. Aşağıdaki hücreleri çalıştırarak bu işlemi gerçekleştirin ve ses kayıtlarını dinleyin.

İlk olarak kütüphanelerimiz kurup yükleyelim:

!pip install essentia 
import os 
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
import essentia.standard as ess
from scipy import signal
import urllib.request
from IPython.display import Audio
import librosa
Requirement already satisfied: essentia in /home/baris/miniconda3/envs/KitapYazim/lib/python3.9/site-packages (2.1b6.dev857)
Requirement already satisfied: six in /home/baris/miniconda3/envs/KitapYazim/lib/python3.9/site-packages (from essentia) (1.16.0)
Requirement already satisfied: pyyaml in /home/baris/miniconda3/envs/KitapYazim/lib/python3.9/site-packages (from essentia) (6.0)
Requirement already satisfied: numpy>=1.8.2 in /home/baris/miniconda3/envs/KitapYazim/lib/python3.9/site-packages (from essentia) (1.22.4)
[   INFO   ] MusicExtractorSVM: no classifier models were configured by default

Hüzzam makamında 3 adet kayıt indirelim.

baglantilar = {'Tanburi Cemil':'https://archive.org/download/cd_volumes-2-3_tanburi-cemil-bey/disc2/02.01.%20Tanburi%20Cemil%20Bey%20-%20Huzzam%20Taksim_sample.mp3',
               'Şükrü Tunar':'https://archive.org/download/cd_istanbul-1925_various-artists-deniz-kizikanuni-artaki-ha/disc1/01.%20Sukru%20Tunar%20-%20Huzzam%20Taksim_sample.mp3',
               'Udi Hrant':'https://archive.org/download/06UdiHrantKenkulianHzzamArkrBaharhGrmedenYazGeldiGedtiHoknadzDurtmadz/06%20-%20Udi%20Hrant%20Kenkulian%20-%20H%C3%BCzzam%20%C5%9Eark%C4%B1%20Bahar%C4%B1%20G%C3%B6rmeden%20Yaz%20Geldi%20Ge%C3%A7ti%20-%20Hoknadz%20Durtmadz.mp3'
              }
               
dosyalar = []
for muzisyen, link in baglantilar.items():
  dosya = muzisyen + '.mp3'
  dosyalar.append(dosya)
  urllib.request.urlretrieve(link, dosya)
  print(dosya, 'indirildi')
Tanburi Cemil.mp3 indirildi
Şükrü Tunar.mp3 indirildi
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
/tmp/ipykernel_9621/2934216479.py in <module>
      8   dosya = muzisyen + '.mp3'
      9   dosyalar.append(dosya)
---> 10   urllib.request.urlretrieve(link, dosya)
     11   print(dosya, 'indirildi')

~/miniconda3/envs/KitapYazim/lib/python3.9/urllib/request.py in urlretrieve(url, filename, reporthook, data)
    266 
    267             while True:
--> 268                 block = fp.read(bs)
    269                 if not block:
    270                     break

~/miniconda3/envs/KitapYazim/lib/python3.9/http/client.py in read(self, amt)
    461             # Amount is given, implement using readinto
    462             b = bytearray(amt)
--> 463             n = self.readinto(b)
    464             return memoryview(b)[:n].tobytes()
    465         else:

~/miniconda3/envs/KitapYazim/lib/python3.9/http/client.py in readinto(self, b)
    505         # connection, and the user is reading more bytes than will be provided
    506         # (for example, reading in 1k chunks)
--> 507         n = self.fp.readinto(b)
    508         if not n and b:
    509             # Ideally, we would raise IncompleteRead if the content-length

~/miniconda3/envs/KitapYazim/lib/python3.9/socket.py in readinto(self, b)
    702         while True:
    703             try:
--> 704                 return self._sock.recv_into(b)
    705             except timeout:
    706                 self._timeout_occurred = True

~/miniconda3/envs/KitapYazim/lib/python3.9/ssl.py in recv_into(self, buffer, nbytes, flags)
   1239                   "non-zero flags not allowed in calls to recv_into() on %s" %
   1240                   self.__class__)
-> 1241             return self.read(nbytes, buffer)
   1242         else:
   1243             return super().recv_into(buffer, nbytes, flags)

~/miniconda3/envs/KitapYazim/lib/python3.9/ssl.py in read(self, len, buffer)
   1097         try:
   1098             if buffer is not None:
-> 1099                 return self._sslobj.read(len, buffer)
   1100             else:
   1101                 return self._sslobj.read(len)

KeyboardInterrupt: 

Kayıtların ilk 30 saniyelik kısımlarını alarak Librosa.pyin fonksiyonu ile frekans serilerini elde edelim. Serileri çizdirelim.

ornekleme_fr = 44100
max_uzunluk = 30 # saniye cinsinden maksimum uzunluk
minF0 = 50 # Hz cinsinden gözlenmesi beklenen minimum frekans
maxF0 = 800 # Hz cinsinden gözlenmesi beklenen maksimum frekans

frekans_serileri = {} # dosya ismi ile frekans serisini eşleyen bir kütüphane oluşturalım
print('PYIN frekans kestirimi gerçekleştiriliyor')
for dosya in dosyalar:
  muzik_sinyali = ess.MonoLoader(filename=dosya, sampleRate=ornekleme_fr)()

  # Sinyal uzun ise kırpalım
  muzik_sinyali = muzik_sinyali[:min(muzik_sinyali.size, int(max_uzunluk*ornekleme_fr))]

  # PYIN ile temel titreşim frekans kestirimi
  frekans_serisi_pyin, periyodiklik, periyodiklik_olasiligi = librosa.pyin(muzik_sinyali, fmin=minF0, fmax=maxF0, sr=ornekleme_fr)
  frekans_serileri[dosya] = frekans_serisi_pyin
  print(dosya, 'için frekans kestirimi tamamlandı')
PYIN frekans kestirimi gerçekleştiriliyor
Tanburi Cemil.mp3 için frekans kestirimi tamamlandı
Şükrü Tunar.mp3 için frekans kestirimi tamamlandı
Udi Hrant.mp3 için frekans kestirimi tamamlandı

Şimdi elde ettiğimiz frekans serilerini çizdirelim ve ses kayıtlarını dinleyelim.

dosya = dosyalar[0] # ilk kayıt

fig = plt.figure(figsize=(15,3))
plt.plot(frekans_serileri[dosya])
plt.title(dosya + " frekans serisi");
plt.xlabel('zaman (analiz pencere endeksi)');
plt.ylabel('f0(Hz)');
plt.grid()
../_images/09_EntonasyonAnalizi_13_0.png

Şekil 9.1: Tanburi Cemil kaydının temel titreşim frekans serisi

muzik_sinyali = ess.MonoLoader(filename=dosya, sampleRate=ornekleme_fr)()
muzik_sinyali = muzik_sinyali[:min(muzik_sinyali.size, int(max_uzunluk*ornekleme_fr))]
Audio(muzik_sinyali, rate=ornekleme_fr)