Utilisez le kit d'outils de traitement du signal vocal via python

Speech Signal Processing Toolkit (SPTK) est une bibliothèque de langage C qui peut effectuer une analyse vocale, une synthèse vocale, une quantification vectorielle, un traitement de données, etc. Je pensais qu'il pouvait être utilisé pour le traitement du signal tel que les vibrations, alors j'ai décidé de l'essayer.

Cette fois, les contenus que nous voulons réaliser en utilisant SPTK sont les suivants.

En tant que module python, il existe un outil de traitement du signal haute performance appelé librosa et un wrapper pour SPTK publié par des volontaires appelé pysptk, mais je veux utiliser SPTK. Il ne semblait pas prendre en charge la commande, alors j'ai dû y travailler.

De plus, je n'ai aucune connaissance du traitement du signal (la programmation est également suspecte), il peut donc y avoir des erreurs de termes. Veuillez comprendre que ce n'est pas mal.

1. Introduction de SPTK

Pour les fenêtres

J'ai fait référence aux HP suivants.

Construire avec VisualStudio2019 x64 Native Tools. Il a été plus facile à installer que prévu, mais dans mon environnement, j'ai eu un problème avec la construction de "pitch.exe". Donc, je l'ai évité en supprimant de force toutes les descriptions liées à "pitch.exe" dans le fichier bin / Makefile.mak avant la construction.

Pour ubuntu

J'ai fait référence aux HP suivants.

Il peut être installé avec ʻapt, mais SPTK qui peut être installé avec ʻapt semble avoir des fonctions optionnelles limitées avec certaines commandes (cela peut être un problème dans mon environnement). Je pense qu'il est préférable de construire docilement à partir du fichier source car il est possible que vous soyez accro à des choses inutiles lors de l'utilisation de commandes.

$ tar xvzf SPTK-3.11.tar.gz
$ cd SPTK-3.11
$ ./configure
$ make
$ sudo make install

1. Comment utiliser SPTK

Tout d'abord, j'ai appris à utiliser SPTK. Il existe un merveilleux HP qui peut être utile. Ce fut une expérience d'apprentissage formidable pour moi d'expliquer en détail. Merci beaucoup.

Opération de commande SPTK

SPTK est fondamentalement comme un outil qui fonctionne à l'aide de commandes via la console. Ici, créez des données sin wave avec la commande sin de SPTK et enregistrez-les avec le nom de fichier sin.data.

Ouvrez la console et entrez la commande suivante. Une séquence d'ondes sinusoïdales de période 16 et de longueur 48 (pour 3 cycles) est enregistrée sous le nom de fichier «sin.data».

$ sin -l 48 -p 16 > sin.data

Pour vérifier le contenu du fichier, entrez la commande SPTK comme suit:

$ x2x +f < sin.data | dmp +f

Le résultat est affiché comme indiqué ci-dessous et vous pouvez vérifier le contenu du fichier. Le numéro de gauche est le numéro d'index. Gardez à l'esprit que les numéros d'index sont automatiquement ajoutés pour l'affichage et que le fichier de données réel contient uniquement les numéros (à droite).

0       0
1       0.382683
2       0.707107
3       0.92388
4       1
5       0.92388
…

De plus, il semble que les données textuelles puissent également être lues. Dans ce cas, préparez un fichier de données texte (sin.txt dans l'exemple ci-dessous) dans lequel les valeurs numériques sont séparées par des espaces (valeur séparée par un espace?), Et lisez-le avec la commande suivante.

$ x2x +af < sin.txt | dmp +f

Lors de la lecture de données texte, l'option doit correspondre à ʻASCII, tel que + af`. (Parce que je ne comprenais pas ces spécifications de base, je n'ai pas pu obtenir les résultats d'analyse attendus et j'ai perdu environ une demi-journée ...)

Lire des données avec python

Maintenant, lisons les données de chaîne d'octets sin.data enregistrées précédemment avec python.

import numpy as np

with open('sin.data', mode='rb') as f:
    data = np.frombuffer(f.read(), dtype='float32')
    print(data)

résultat

[ 0.0000000e+00  3.8268343e-01  7.0710677e-01  9.2387950e-01
  1.0000000e+00  9.2387950e-01  7.0710677e-01  3.8268343e-01
  1.2246469e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
 -1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01
 -2.4492937e-16  3.8268343e-01  7.0710677e-01  9.2387950e-01
  1.0000000e+00  9.2387950e-01  7.0710677e-01  3.8268343e-01
  3.6739403e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
 -1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01
 -4.8985874e-16  3.8268343e-01  7.0710677e-01  9.2387950e-01
  1.0000000e+00  9.2387950e-01  7.0710677e-01  3.8268343e-01
  6.1232340e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
 -1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01]

Créer des données en python

Ensuite, créons des données de chaîne d'octets à passer à SPTK avec python. Il est assez important de spécifier le type. (J'étais accro ici aussi)

arr = np.array(range(0,5)) #Faites une séquence de nombres appropriée

with open('test.data', mode='wb') as f:
    arr = arr.astype(np.float32) #Faire le type float32
    barr = bytearray(arr.tobytes()) #au bytarray
    f.write(barr)

Lisez le fichier avec SPTK et vérifiez-le.

$ x2x +f < test.data | dmp +f
0       0
1       1
2       2
3       3
4       4

Coopération entre python et SPTK

Si vous enregistrez le numpy.ndarray créé par python de cette manière dans un fichier sous forme de chaîne d'octets et passez le fichier via une commande, il semble que vous puissiez traiter les données avec SPTK. Essayons d'utiliser sin.data pendant un moment.

import subprocess

#Commande pour lire les données et appliquer la fonction de fenêtre
cmd = 'x2x +f < sin.data | window -l 16'

p = subprocess.check_output(cmd, shell = True)
out = np.frombuffer(p, dtype='float32')
print(out)
[-0.0000000e+00  3.0001572e-03  2.5496081e-02  8.6776853e-02
  1.8433140e-01  2.7229854e-01  2.8093100e-01  1.7583697e-01
  5.6270582e-17 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
 -9.3926586e-02 -3.3312235e-02 -5.5435672e-03  2.4845590e-18
  1.5901955e-33  3.0001572e-03  2.5496081e-02  8.6776853e-02
  1.8433140e-01  2.7229854e-01  2.8093100e-01  1.7583697e-01
  1.6881173e-16 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
 -9.3926586e-02 -3.3312235e-02 -5.5435672e-03  2.4845590e-18
  3.1803911e-33  3.0001572e-03  2.5496081e-02  8.6776853e-02
  1.8433140e-01  2.7229854e-01  2.8093100e-01  1.7583697e-01
  2.8135290e-16 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
 -9.3926586e-02 -3.3312235e-02 -5.5435672e-03  2.4845590e-18]

Transfert de données plus efficace

Je déplorais combien il était inutile de créer un fichier juste pour passer des données à SPTK, mais il y a quelque chose d'utile appelé ʻio.BytesIO`.

En fin de compte, j'ai préparé quelque chose comme ça.


import io
import shlex, subprocess
from typing import List

import numpy

def sptk_wrap(in_array : numpy.ndarray, sptk_cmd : str) -> numpy.ndarray:
    '''
contribution
        in_array :Données de forme d'onde
        sptk_cmd :commandes sptk (par exemple'window -l 16')
production
Données après analyse
    '''
    # numpy.Convertir ndarray en bytearray
    arr = in_array.astype(np.float32)
    barr = bytearray(arr.tobytes())
    bio = io.BytesIO(barr)
    
    #commande sptk
    cmd = shlex.split(sptk_cmd)
    proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc.communicate(input=bio.read())
    
    return np.frombuffer(out, dtype='float32')
   
    
def sptk_wrap_pipe(in_array : numpy.ndarray, sptk_cmd_pipe : List[str]) -> numpy.ndarray:
    '''
contribution
        in_array :Données de forme d'onde
        sptk_cmd_pipe :Commandes Sptk stockées dans une liste dans l'ordre dans lequel vous souhaitez diriger
(Exemple)
        cmd_list = [
            'window -l 512 -L 512 -w 2',
            'spec -l 512 -o 0',
           ]
production
Données après analyse
    '''
    out_array = numpy.copy(in_array)
    for l in sptk_cmd_pipe:
        out_array = sptk_wrap(out_array, l)
        
    return out_array


#Exemple d'analyse de spectre
def ndarr2sp_ndarr(in_array : numpy.ndarray, length : int, wo : int = 2, oo : int = 0) -> numpy.ndarray:
    '''
contribution:Données de forme d'onde
production:Spectre de puissance log
    
option:
    wo :Options de fonction de la fenêtre (0:blackman 1:hammin 2:hanning 3:barlett)
    oo :Forme du spectre de sortie (0: 20 × log |Xk| )

exemple de commande sptk
    window -l 512 -L 512 -w 2 | spec -l 512 -o 0
    '''
    cmd_list = [
        "window -l {0} -L {0} -w {1} ".format(length, wo),
        "spec -l {0} -o {1}".format(length, oo),
    ]

    return sptk_wrap_pipe(in_array, cmd_list)

2. Exemple d'utilisation

Créez des données de forme d'onde appropriées et analysez-les réellement. Ici, 10 ensembles d'échantillons avec une longueur de données de 512 ont été créés tout en modifiant la fréquence des données à créer.

import numpy as np
import matplotlib.pyplot as plt

N = 2**9            #Nombre d'échantillons de forme d'onde à analyser 512
dt = 0.01          #Intervalle d'échantillonnage
t = np.arange(0, N*dt, dt) #Axe du temps
freq = np.linspace(0, 1.0/dt, N) #Axe de fréquence

samples = []
for f in range(1,11):
    #Réglez la fréquence de la forme d'onde à créer sur 1~Créez 10 ensembles d'échantillons de forme d'onde en passant à 10.
    wave = np.sin(2*np.pi*f*t)
    samples.append(wave)
    
samples = np.asarray(samples)
print(samples.shape)

Sortie: (10, 512)

Lorsque vous tracez les données créées, cela ressemble à ceci.

1ère donnée (fréquence 1Hz)

plt.plot(t, samples[0])

index1.png

10ème données (fréquence 10Hz)

plt.plot(t, samples[9])

index2.png

Maintenant, analysons le spectre des 10èmes données en utilisant SPTK.

ps = ndarr2sp_ndarr(samples[9], N)

plt.plot(freq[:N//2+1], ps)
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")

index3.png

Vous pouvez également analyser plusieurs données à la fois. Cependant, le résultat est sorti dans un état connecté de manière plate, un remodelage est donc nécessaire.

Commencez par vérifier la «forme» du jeu de données.

samples_shape = samples.shape
print(samples_shape)

Sortie: (10, 512)

Analysez 10 pièces avec «SPTK».

ps_s = ndarr2sp_ndarr(samples, N)
print(ps_s.shape)

Sortie: (2570,)

Remodeler.

ps_s = ps_s.reshape((samples_shape[0],-1))
print(ps_s.shape)

Sortie: (10, 257)

10ème données (fréquence 10Hz)

print(np.max(ps_s[9]))
plt.plot(freq[:N//2+1], ps_s[9])
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")

Sortie: 19.078928 index4.png

3. 3. Supplément

Je l'ai comparé au résultat de ma propre analyse. J'ai essayé de normaliser avec le nombre de données et de multiplier par la valeur de correction de la fonction de fenêtre, mais la valeur en décibels est légèrement différente du résultat analysé par SPTK.

Je ne connais pas la raison ... Il est probable que vous fassiez quelque chose de stupide. (S'il vous plaît dites-moi qui le connaît)

wavedata = samples[9]

#Mettez une fenêtre de miel
hanningWindow = np.hanning(len(wavedata))
wavedata = wavedata * hanningWindow

#Calculer le coefficient de correction
acf = 1/(sum(hanningWindow)/len(wavedata))

#Conversion de Fourier (convertie en signal de fréquence)
F = np.fft.fft(wavedata)

#Normalisation+Doublez le composant AC
F = 2*(F/N)
F[0] = F[0]/2

#Spectre d'oscillation
Adft = np.abs(F)

#Multipliez le coefficient de correction lors de la multiplication de la fonction de fenêtre
Adft = acf * Adft

#Spectre de puissance
Pdft = Adft ** 2
#Spectre de puissance logistique
PdftLog = 10 * np.log10(Pdft)
# PdftLog = 10 * np.log(Pdft)

print(np.max(PdftLog))

start=0
stop=int(N/2)
plt.plot(freq[start:stop], PdftLog[start:stop])
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")

plt.show()

Sortie: -0,2237693

index5.png

Recommended Posts

Utilisez le kit d'outils de traitement du signal vocal via python
python3 Mesurez la vitesse de traitement.
Traitement du signal acoustique avec Python (2)
Traitement du signal acoustique avec Python
Laissez le traitement gênant à Python
Traitement du signal en Python (1): transformée de Fourier
[Python] Utiliser automatiquement le navigateur avec Selenium
L'histoire du traitement A du blackjack (python)
Obtenez la météo à Osaka via l'API Web (python)
Le moyen le plus simple de synthétiser la voix avec python
Afficher le résultat du traitement de la géométrie en Python
Traitement d'image? L'histoire du démarrage de Python pour
Installez MongoDB sur Ubuntu 16.04 et utilisez python
Traitement de fichiers Python
[Python] Mesure et affiche le temps nécessaire au traitement
[Réintroduction à python] Comment importer via le répertoire parent
Utilisez CASA Toolkit dans votre propre environnement Python
Envoyer des données de Python au traitement via une communication socket
Envoyez et recevez Gmail via l'API Gmail en utilisant Python
Examiner le traitement de fermeture de l'ensemble de données Python (wrapper SQLAlchemy)