Akustische Signalverarbeitung beginnend mit Python-Lassen Sie uns ein dreidimensionales akustisches System erstellen

Überblick

In letzter Zeit nimmt die Anzahl der Distributoren zu, die 3D-Modelle wie VTuber verwenden. Viele Verteiler verwenden akustische Einkanalinformationen für die Verteilung. Um die Verteilung jedoch immersiver zu gestalten, wird mithilfe eines Mikrofonarrays wie 3Dio stereoskopischer Klang erzeugt. Wenn mehrere Schallquellen vorhanden sind, wird empfohlen, ein solches Mikrofonarray zu verwenden. In einer Situation wie ASMR kann jedoch durch Signalverarbeitung stereoskopischer Schall erzeugt werden, wenn eine einzelne Schallquelle (Person) zu stereoskopischem Schall verarbeitet wird. Natürlich sind mehrere Schallquellen möglich, aber ...

Wichtig ist hierbei, dass der Mikrofonteil des für ASMR verwendeten Mikrofonarrays wie 3Dio, bei dem es sich um die Kopfübertragungsfunktion handelt, die Form eines Ohrs hat. Dies liegt daran, dass es die Übertragung von Schall von der Schallquelle zum Trommelfell des Ohrs nachahmt. Diese Übertragungsfunktion wird als Kopfübertragungsfunktion (HRTF) bezeichnet. In diesem Artikel werde ich beschreiben, wie ein System implementiert wird, das stereophonen Klang durch Signalverarbeitung mit HRTF für das rechte und linke Ohr in Python erzeugt.

Hinweis: HRTFs variieren von Person zu Person, und Schätzungen der Tonbildposition vorher und nachher sind häufig inkonsistent. Selbst wenn 3Dio usw. verwendet wird, ahmt es nur die Standardohrform nach und kann keine individuellen Unterschiede lösen.

Da das Programm lang ist, werde ich nur die Gliederung erklären. Weitere Informationen finden Sie im folgenden Git-Programm. Außerdem wird in git beschrieben, wie man es benutzt. Git: k-washi/stereophonic-Sound-System

Informationen zum Protokollieren, Lesen der Einstellungsdatei und zur gRPC-Kommunikation zum Abrufen der im Programm beschriebenen Standortinformationen finden Sie im folgenden Qiita-Artikel.

Dreidimensionales Klangbeispiel (Kopfhörer erforderlich)

Bitte klicken Sie auf das Bild unten. Sie können den dreidimensionalen Klang hören, der tatsächlich durch Verknüpfen auf Youtube erzeugt wird. Da das Mikrofon an den Mac angeschlossen ist, ist der Originalton schlecht, aber Sie können sehen, dass es sich um einen dreidimensionalen Ton handelt.

Youtube Link

Bibliotheksinstallation


pip install PyAudio==0.2.11
pip install grpcio-tools
pip install numpy

HRTF erhalten

Hier wird die HRTF-Datenbank gelesen, in den Frequenzbereich konvertiert und mit pickle gespeichert.

Für die HRTF wurden HRTF-Daten (2) der Nagoya University HRTF verwendet.

Das Programm wird unten beschrieben. Die Details werden weggelassen als ... Das vollständige Programm finden Sie unter acoustic / spacialSound.py.

acoustic/spacialSound.py


...

class HRTF():
  def __init__(self):
    ...
  
  def checkModel(self):
    #Modelldateinamen abrufen
    ...
      self.getModelNameList()
    ...

  def getModelNameList(self):
    #Analysieren Sie den Namen der HRTF-Datei für jeden Azimut und jede Höhe
    ...
  
  def openData(self, path, dataType = np.int16):
    #H jede Richtung,Die Anzahl der Abtastungen des HRTF-Signals im Elevationswinkel beträgt 512 Punkte, und diese Daten werden gelesen und in das Numpy-Format konvertiert.
    with open(path, 'r') as rData:
      temp = rData.read().split("\n")
      data = []
      for item in temp:
        if item != '':
          data.append(float(item))
      return np.array(data)
  
  def convHRTF2Np(self):
    #Lesen Sie die HRTF-Daten für jede Ausrichtung und Höhe sowie 512 Punkte basierend auf der Überlappungs-Add-Methode+0 füllen(512 Punkte)Ist FFT.(FFT wird im nächsten Kapitel beschrieben)
    #Die obige FFT wird an beiden Ohren durchgeführt und alle Daten werden durch Pickle gespeichert. Die Funktion saveData wird zum Speichern verwendet.
    #Zum Lesen können die gespeicherten Pickle-Daten mit readData gelesen werden.
    for e, _ in enumerate(self.elev):
      LaziData = []
      RaziData = []
      for a, _ in enumerate(self.azimuth[e]):
        
        Lpath = self.Lpath[e][a]
        Rpath  = self.Rpath[e][a]

        Ldata = spec.overlapAdderFFT(self.openData(Lpath))
        Rdata = spec.overlapAdderFFT(self.openData(Rpath))
        
        LaziData.append(Ldata)
        RaziData.append(Rdata)

      self.hrtf[self.left].append(LaziData)
      self.hrtf[self.right].append(RaziData)

    self.saveData(self.hrtf, Conf.HRTFpath)
    self.saveData(self.elev, Conf.Elevpath)
    self.saveData(self.azimuth, Conf.Azimuthpath)

  def saveData(self, data, path):
    #Pickle-Datenspeicherung
    try:
      with open(path, 'wb') as hrtf:
        pickle.dump(data, hrtf)
    except Exception as e:
      logger.critical(e)

  def readData(self, path):
    #Lesen von Pickle-Daten
    try:
      with open(path, 'rb') as hrtf:
        data = pickle.load(hrtf)
    except Exception as e:
      logger.critical(e)

    return data

Schnelle Fourier-Transformation (FFT)

Hier wird die Implementierung in Bezug auf FFT beschrieben.

Weitere Informationen finden Sie unter acoustic / acousticSignalProc.py

Bei der Verarbeitung akustischer Informationen ist eine Faltungsintegration von HRTF und Mikrofoneingang erforderlich. Bei der Verarbeitung mit einem rohen akustischen Signal nimmt die Verarbeitung jedoch Zeit in Anspruch und die Daten sind schwierig zu verarbeiten. Daher ist eine Fourier-Transformation erforderlich, die das Signal im Frequenzbereich in Informationen umwandelt. FFT ist diejenige, die diese Fourier-Transformation mit hoher Geschwindigkeit durchführt.

Die OverLap Add-Methode (OLA) wird häufig verwendet, wenn die HRTF mit dem Mikrofoneingang gefaltet wird. Wenn beispielsweise die Anzahl der Abtastwerte für HRTF und Mikrofoneingang 512 Punkte beträgt, werden zusätzlich zu den Daten 512 Punkte mit 0 gefüllt. Das heißt, 512 + 512 (0) Daten werden erstellt. Danach wird die positive Frequenz von FFT durch die rfft-Funktion von numpy berechnet. Im Fall von fft of numpy werden 512/2 = 256 Punkte positiver Frequenzkomponenten und 256 Punkte negativer Frequenzkomponenten berechnet. Rfft wird jedoch in vielen technischen Anwendungen verwendet, da häufig nur positive Frequenzkomponenten ausreichen. Obwohl die Berechnungsalgorithmen von numpys rfft und fft unterschiedlich sind, ist der Fehler des Ergebnisses ziemlich klein, so dass diesmal rfft verwendet wird. Nach dem Ausführen von FFT werden dann HRTF und Mikrofoneingang für jede Frequenz multipliziert. Diese Kombination wird im nächsten Kapitel erläutert.

Im folgenden Programm werden zwei FFTs, OverlapAdderFFT und SpacializeFFT, vorbereitet. Was ist der Unterschied? Gibt an, ob das Fenster (Fensterfunktion) multipliziert wird. Da die Fensterfunktion die Periodizität des durch die Fourier-Transformation ausgeschnittenen Bereichs annimmt, wird eine Funktion, die das Ende kleiner macht, auf die Daten angewendet, so dass die Enden verbunden werden. HRTF hat jedoch nur 512 Punkte pro Daten. Wenn die Fensterfunktion angewendet wird, können die Originaldaten nicht wiederhergestellt werden, sodass sie ohne Anwendung der Fensterfunktion verwendet werden. Andererseits hat der Mikrofoneingang eine Fensterfunktion. Wie im nächsten Kapitel erläutert wird, gehen bei Anwendung der Fensterfunktion die Endinformationen verloren, sodass alle Daten beim Verschieben um 128 Punkte verwendet werden.

acoustic/acousticSignalProc.py


import pyaudio
import numpy as np


class SpectrogramProcessing():
  def __init__(self, freq = Conf.SamplingRate):
    self.window = np.hamming(Conf.SysChunk)
    self.overlapFreq = np.fft.rfftfreq(Conf.SysChunk * 2, d=1./freq)
    self.overlapData = np.zeros((int(Conf.SysChunk * 2)), dtype = np.float32)
  
  def overlapAdderFFT(self, data):
    #Füllen Sie 0 und FFT aus
    self.overlapData[:Conf.SysChunk] = data
    return np.fft.rfft(self.overlapData)
  
  def spacializeFFT(self, data):
    #Füllen Sie 0 aus und wenden Sie das Hanning-Fenster an.
    self.overlapData[:Conf.SysChunk] = data * self.window
    return np.fft.rfft(self.overlapData)


  def ifft(self, data):
    #in: chanel_num x freq num (if 1.6kHz, 0,...,7984.375 Hz) 
    #out: chanel_num x frame num(Conf.SysChunk = 512)
   
    return np.fft.irfft(data)

Mikrofoneingang, -ausgang, Tonverarbeitungsprogramm

Als nächstes wird das tatsächliche Mikrofoneingabe-, -ausgabe- und -konvertierungsprogramm für stereophonen Klang beschrieben. Die Verarbeitung erfolgt unter Verwendung der oben beschriebenen Funktionen und dergleichen. Bezüglich der Einstellungen und des gRPC verweisen wir bitte auf meine früheren Artikel, wie am Anfang erwähnt.

acoustic/audioStreamOverlapAdder.py



...

from acoustic.acousticSignalProc import AudioDevice, SpectrogramProcessing, WaveProcessing, convNp2pa, convPa2np
from acoustic.spacialSound import spacialSound
# ------------

import pyaudio
import numpy as np
import time

class MicAudioStream():
  def __init__(self):
    self.pAudio = pyaudio.PyAudio()
    self.micInfo = AudioDevice(Conf.MicID)
    self.outInfo = AudioDevice(Conf.OutpuID)

    #Verarbeitung der Einschränkung von Ausgabegeräten
    if self.outInfo.micOutChannelNum < 2:
      self.left = 0
      self.right = 0
    else:
      self.left = 0
      self.right = 1
      if self.outInfo.micOutChannelNum > 2:
        self.outInfo.micChannelNum = 2
        logger.info("Ich habe es auf 2 Kanäle begrenzt, weil die Anzahl der Ausgangsmikrofone zu hoch ist.")

    self.startTime = time.time()

    #Derzeit wird nur eine Bitbreite von 16 Bit unterstützt.(Weil wir die Operation in anderen Fällen nicht bestätigt haben)
    if Conf.SysSampleWidth == 2:
      self.format = pyaudio.paInt16
      self.dtype = np.int16
    else:
      logger.critical("Wird derzeit nicht unterstützt")
      exec(-1)

    self.fft = SpectrogramProcessing()

    #Wenn Sie jedes Mal Daten im Numpy-Array-Format erstellen und die Speicherzuweisung ausführen, dauert dies einige Zeit. Erstellen Sie sie daher im Voraus.
    self.data = np.zeros((int(Conf.StreamChunk * 2)), dtype=self.dtype)
    self.npData = np.zeros((int(Conf.StreamChunk * 2)) , dtype=self.dtype)

    self.overlapNum = int(Conf.StreamChunk / Conf.SysFFToverlap) 

    self.freqData = np.zeros((self.overlapNum, self.outInfo.micOutChannelNum, self.fft.overlapFreq.shape[0]), dtype=np.complex)
    self.convFreqData = np.zeros((self.outInfo.micOutChannelNum, int(Conf.StreamChunk*3)) , dtype=self.dtype)
    self.outData = np.zeros((self.outInfo.micOutChannelNum * Conf.StreamChunk), dtype=self.dtype)
    
    self.Aweight = self.fft.Aweight() #Das A-Merkmal wird angewendet, aber da es sich kaum geändert hat, besteht kein Grund zur Sorge. (Kann gelöscht werden)

    #Anfangswert der Positionsinformationen
    self.x = 0.2
    self.y = 10
    self.z  = 0.2

    #HRTF-Lesung (akustisch/spacialSound.py)
    #Sie können den Prozess der Rückgabe von HRTF für die Positionsinformationen ausführen.
    self.hrft = spacialSound()
    
    #Bei der Aufnahme von stereophonem Ton
    if Conf.Record:
      #test/listOrNumpy.Geschwindigkeitsvergleich mit py
      #Für das Array-Format von numpy ist es schneller, numpy in eine Liste zu konvertieren und eine Liste zu erweitern, als Array-Formate zu kombinieren.
      self.recordList = []

  def spacialSoundConvering(self, freqData):
    #Gibt HRTF für Position zurück
    lhrtf, rhrtf = self.hrft.getHRTF(self.x, self.y, self.z)
   
    #Die Eingangsdaten des HRTF-Mikrofons werden wie unten gezeigt gefaltet, um stereophonen Klang zu erzeugen.
    freqData[self.left] = freqData[self.left] * lhrtf 
    freqData[self.right] = freqData[self.right] * rhrtf 
    return freqData * self.Aweight

  def callback(self, in_data, frame_count, time_info, status):
    #Eine Funktion, die Sounddaten bei der Stream-Verarbeitung von pyAudio verarbeitet.
    #in_Daten werden eingegeben, Rückgabe erfolgt nicht_Tondaten werden als Daten ausgegeben.

    if time.time() - self.startTime > Conf.SysCutTime:
      #Konvertieren der Eingabe im pyAudio-Format in das Numpy-Format.
      self.npData[Conf.StreamChunk:] = convPa2np(np.fromstring(in_data, self.dtype), channelNum=self.micInfo.micChannelNum)[0, :] #ch1 input
      
      #Überlappen Sie die Breite der Daten unten(128)Erzeugen Sie dreidimensionalen Klang, während Sie ihn nacheinander verschieben.
      for i in range(self.overlapNum):
        #512 Punkte(SysChunk)FFT wird mit der Breite von durchgeführt.
        self.freqData[i, :, :] = self.fft.spacializeFFT(self.npData[Conf.SysFFToverlap * i : Conf.SysChunk + Conf.SysFFToverlap * i])
        
        #Der HRTF- und der Mikrofoneingang sind gefaltet.
        self.freqData[i, :, :] = self.spacialSoundConvering(self.freqData[i]) 
        
        #Der Frequenzbereich wird durch inverse Fourier-Transformation in den Zeitbereich umgewandelt.
        self.convFreqData[:, Conf.SysFFToverlap * i  : Conf.SysChunk * 2 + Conf.SysFFToverlap * i] += self.fft.ifft(self.freqData[i]).real.astype(self.dtype)#[:,:Conf.SysChunk]

      #Konvertieren vom Numpy-Format in das pyAudio-Ausgabeformat.
      self.outData[:] = convNp2pa(self.convFreqData[:,:Conf.StreamChunk]) 

      #Die Entfernungsdämpfung des Schalls wird berechnet. Außerdem ist der Ton zu laut, daher teile ich ihn durch SysAttenuation.
      self.outData[:] = self.hrft.disanceAtenuation(self.outData[:], self.x, self.y, self.z) / Conf.SysAttenuation
      
      if Conf.Record:
        self.recordList += self.outData.tolist()
      
      #Initialisieren Sie für den nächsten Mikrofoneingang
      self.npData[:Conf.StreamChunk] = self.npData[Conf.StreamChunk:]
      self.convFreqData[:, :Conf.StreamChunk*2] = self.convFreqData[:, Conf.StreamChunk:]
      self.convFreqData[:,Conf.StreamChunk*2:] = 0
      
    #In das Datenausgabeformat im pyAudio-Format konvertieren
    out_data = self.outData.tostring()
    
    return (out_data, pyaudio.paContinue)
  

  
  def start(self):
    #Stellen Sie das Eingabe- / Ausgabegerät und das Format auf das folgende Format ein und starten Sie die Verarbeitung.
    """
    rate – Sampling rate
    channels – Number of channels
    format – Sampling size and format. See PortAudio Sample Format.
    input – Specifies whether this is an input stream. Defaults to False.
    output – Specifies whether this is an output stream. Defaults to False.
    input_device_index – Index of Input Device to use. Unspecified (or None) uses default device. Ignored if input is False.
    output_device_index – Index of Output Device to use. Unspecified (or None) uses the default device. Ignored if output is False.
    frames_per_buffer – Specifies the number of frames per buffer.
    start – Start the stream running immediately. Defaults to True. In general, there is no reason to set this to False.
    input_host_api_specific_stream_info – Specifies a host API specific stream information data structure for input.
    output_host_api_specific_stream_info – Specifies a host API specific stream information data structure for output.
    stream_callback –Specifies a callback function for non-blocking (callback) operation. Default is None, which indicates blocking operation (i.e., Stream.read() and Stream.write()). To use non-blocking operation, specify a callback that conforms to the following signature:
    callback(in_data,      # recorded data if input=True; else None
            frame_count,  # number of frames
            time_info,    # dictionary
            status_flags) # PaCallbackFlags
    time_info is a dictionary with the following keys: input_buffer_adc_time, current_time, and output_buffer_dac_time; see the PortAudio documentation for their meanings. status_flags is one of PortAutio Callback Flag.
    The callback must return a tuple:
    (out_data, flag)
    out_data is a byte array whose length should be the (frame_count * channels * bytes-per-channel) if output=True or None if output=False. flag must be either paContinue, paComplete or paAbort (one of PortAudio Callback Return Code). When output=True and out_data does not contain at least frame_count frames, paComplete is assumed for flag.
    """
    self.stream = self.pAudio.open(
      format = self.format,
      rate = Conf.SamplingRate,#self.micInfo.samplingRate,
      channels = self.micInfo.micChannelNum,
      input = True,
      output = True,
      input_device_index = Conf.MicID,
      output_device_index = Conf.OutpuID,
      stream_callback = self.callback,
      frames_per_buffer = Conf.StreamChunk
    )

    self.stream.start_stream()

  def stop(self):
    #Die notwendige Verarbeitung wird getrennt von der Tonverarbeitung ausgeführt. Schließlich wird der Schließvorgang auch ausgeführt, wenn das System heruntergefahren wird.
    #Hier wird gRPC verwendet, um die Positionsinformationen der Schallquelle zu aktualisieren.

    from proto.client import posClient
    
    grpcPosGetter = posClient()
    grpcPosGetter.open()

    while self.stream.is_active():
      time.sleep(0.1)
      try:
        ok = grpcPosGetter.posRequest()
        if ok:
          self.x, self.y, self.z = grpcPosGetter.getPos()
      except Exception as e:
        logger.error("pos getter error {0}".format(e))

      if time.time() - self.startTime > Conf.RecordTime + Conf.SysCutTime:
        break

    if Conf.Record:
      record = WaveProcessing()
      record.SaveFlatteData(self.recordList, channelNum=self.outInfo.micOutChannelNum)


    self.stream.start_stream()
    self.stream.close()
    self.close()
    grpcPosGetter.close()
    

  
  def close(self):
    self.pAudio.terminate()
    logger.debug("Close proc")
    exit(0)

if __name__ == "__main__":
  st = MicAudioStream()
  st.start()
  try:
    pass
  finally:
    st.stop()
  

Überprüfen Sie die Ein- und Ausgabegeräte

Um die Tonverarbeitung tatsächlich zu testen, muss die ID des Eingabe- / Ausgabegeräts bestätigt werden.

Beispiel für Geräteinformationen

2020-01-16 03:46:49,436 [acousticSignalProc.py:34] INFO     Index: 0 | Name: Built-in Microphone | ChannelNum: in 2 out 0 | SampleRate: 44100.0
2020-01-16 03:46:49,436 [acousticSignalProc.py:34] INFO     Index: 1 | Name: Built-in Output | ChannelNum: in 0 out 2 | SampleRate: 44100.0
2020-01-16 03:46:49,436 [acousticSignalProc.py:34] INFO     Index: 2 | Name: DisplayPort | ChannelNum: in 0 out 2 | SampleRate: 48000.0
...

Das folgende Beispiel zeigt ein Programm, das Informationen zu Eingabe- / Ausgabegeräten mit PyAudio ausgibt.

acoustic/acousticSignalProc.py


...

import pyaudio
import numpy as np

class AudioDevice():
  def __init__(self, devId = Conf.MicID):
    self.pAudio = pyaudio.PyAudio()

    self.setAudioDeviceInfo(devId)
    self.samplingRate = Conf.SamplingRate
    

  def getAudioDeviceInfo(self):
    #Geräteinformationen mit PyAudio ausgeben.
    for i in range(self.pAudio.get_device_count()):
      tempDic = self.pAudio.get_device_info_by_index(i)
      text = 'Index: {0} | Name: {1} | ChannelNum: in {2} out {3} | SampleRate: {4}'.format(tempDic['index'], tempDic['name'], tempDic['maxInputChannels'], tempDic['maxOutputChannels'], tempDic['defaultSampleRate'])
      logger.info(text)

  def setAudioDeviceInfo(self, micId = 0):
    #Überprüfen Sie, ob die eingestellte Geräte-ID vorhanden ist, und behalten Sie die Informationen dieser ID bei
    micInfoDic = {}
    for i in range(self.pAudio.get_device_count()):
      micInfoDic = self.pAudio.get_device_info_by_index(i)
      if micInfoDic['index'] == micId:

        self.micName = micInfoDic['name']
        self.micChannelNum = micInfoDic['maxInputChannels']
        self.micOutChannelNum = micInfoDic['maxOutputChannels'] 
        self.micSamplingRate = int(micInfoDic['defaultSampleRate'])
        text = 'Set Audio Device Info || Index: {0} | Name: {1} | ChannelNum: {2}, {3} | SampleRate: {4}'.format(micId, self.micName, self.micChannelNum,self.micOutChannelNum, self.micSamplingRate)
        logger.info(text)

        if self.micChannelNum > 2:
          logger.critical("Es werden 3 oder mehr Mikrofoneingänge nicht unterstützt.")
          exit(-1)

        break

      if self.pAudio.get_device_count() == i + 1:
        logger.critical("Es gibt kein entsprechendes ID-Mikrofon.")

Zusammenfassung

Das Obige ist die Erklärung des dreidimensionalen Soundsystems mit Python. Es kann kompliziert sein, weil einige Teile weggelassen wurden und auf andere Artikel verwiesen werden muss, aber ich hoffe, dass es hilfreich sein wird. Es wird gesagt, dass Python langsam ist, aber wenn Sie numpy effizient verwenden, z. B. indem Sie Speicher im Voraus zuweisen, kann es häufig mit ausreichender Geschwindigkeit ausgeführt werden. Ich habe verschiedene andere Artikel geschrieben, bitte beziehen Sie sich auf sie.

Recommended Posts

Akustische Signalverarbeitung beginnend mit Python-Lassen Sie uns ein dreidimensionales akustisches System erstellen
Akustische Signalverarbeitung mit Python (2)
Erstellen Sie ein Empfehlungssystem mit Python
Machen Sie eine Lotterie mit Python
Machen Sie ein Feuer mit kdeplot
Lassen Sie uns eine GUI mit Python erstellen.
Machen Sie einen Sound mit Jupyter Notebook
Probieren Sie die Audiosignalverarbeitung mit librosa-Beginner aus
Machen wir einen Blockbruch mit wxPython
Machen Sie einen Filter mit einer Django-Vorlage
Lassen Sie uns ein Diagramm mit Python erstellen! !!
Machen wir mit xCAT einen Spacon
Erstellen Sie mit PySide einen Modelliterator
Machen Sie eine schöne Grafik mit Plotly
Akustisches Signalverarbeitungsmodul, das mit Python-Sounddevice ASIO [Anwendung] verwendet werden kann
Python-Sound Gerät ASIO akustisches Signalverarbeitungsmodul [Basic]
Systemhandel ab Python3: langfristige Investition
Lassen Sie uns mit Python ein Shiritori-Spiel machen
Erstellen Sie einen Videoplayer mit PySimpleGUI + OpenCV
"Systemhandel beginnt mit Python3" Lesememo
Machen Sie einen seltenen Gacha-Simulator mit Flask
Machen Sie mit matplotlib eine teilweise gezoomte Figur
Machen Sie ein Zeichnungsquiz mit kivy + PyTorch
Lassen Sie uns mit Python langsam sprechen
Erstellen Sie ein Sternensystem mit Blender 2.80-Skript
Erstellen Sie einen Kaskadenklassifizierer mit Google Colaboratory
Lassen Sie uns mit PLY 1 eine einfache Sprache erstellen
Machen Sie eine Logikschaltung mit Perceptron (Multilayer Perceptron)
Machen Sie Ja Nein Popup mit Kivy
Machen Sie einen Waschtrocknungs-Timer mit Raspberry Pi
Erstellen Sie eine GIF-Animation mit Ordnerüberwachung
Erstellen Sie ein Webframework mit Python! (1)
"Erste elastische Suche" beginnend mit einem Python-Client
Machen wir mit Pylearn 2 eine dreiäugige KI
Erstellen Sie eine Desktop-App mit Python mit Electron
Machen wir einen Twitter-Bot mit Python!
Erstellen Sie ein Webframework mit Python! (2)
Hochauflösende akustische Signalverarbeitung (1) - Lesen einer 24-Bit-WAV-Datei mit Python