Je veux savoir comment obtenir des échantillons d'un fichier .wav afin d'effectuer une jointure fenêtrée de deux fichiers .wav.comment obtenir des échantillons wav à partir d'un fichier wav?
Quelqu'un peut-il dire comment faire?
Je veux savoir comment obtenir des échantillons d'un fichier .wav afin d'effectuer une jointure fenêtrée de deux fichiers .wav.comment obtenir des échantillons wav à partir d'un fichier wav?
Quelqu'un peut-il dire comment faire?
Le module wave de la bibliothèque standard est la clé: après bien sûr import wave
en haut de votre code, wave.open('the.wav', 'r')
retourne un objet « vague lire » à partir de laquelle vous pouvez lire des cadres avec la méthode .readframes
, qui renvoie une chaîne de octets qui sont les échantillons ... quel que soit le format du fichier wave (vous pouvez déterminer les deux paramètres pertinents pour décomposer les images en échantillons avec la méthode .getnchannels
pour le nombre de canaux, et .getsampwidth
pour le nombre d'octets par échantillon).
La meilleure façon de tourner la chaîne d'octets en une séquence de valeurs numériques est avec le module array
, et un type de (respectivement) 'B'
, 'H'
, 'L'
pour 1, 2, 4 octets par échantillon (sur une 32 -bit build de Python, vous pouvez utiliser la valeur itemsize
de votre objet tableau pour vérifier cela). Si vous avez des largeurs d'échantillons différentes de celles que array
peut vous fournir, vous devrez découper la chaîne d'octets (en remplissant chaque petite tranche avec des octets valant 0) et utiliser le module struct à la place (mais plus clunkieur et plus lent, utilisez array
à la place si tu peux).
Vous pouvez utiliser le module wave
. Vous devez d'abord lire les métadonnées, telles que la taille de l'échantillon ou le nombre de chaînes. En utilisant la méthode readframes()
, vous pouvez lire des échantillons, mais uniquement sous la forme d'une chaîne d'octets. Basé sur le format de l'échantillon, vous devez les convertir en échantillons en utilisant struct.unpack()
. Vous pouvez également utiliser le module io.wavfile
de SciPy si vous souhaitez que les échantillons soient un tableau de nombres à virgule flottante.
pouvez-vous me dire comment obtenir l'échantillon comme un tableau de nombres point flottant sans utiliser scipy – kaki
est ici une fonction pour lire les échantillons d'un fichier wave (testé avec stéréo mono &):
def read_samples(wave_file, nb_frames):
frame_data = wave_file.readframes(nb_frames)
if frame_data:
sample_width = wave_file.getsampwidth()
nb_samples = len(frame_data) // sample_width
format = {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
return struct.unpack(format, frame_data)
else:
return()
Et voici le script complet qui ne mélange ou de plusieurs concaténation fenêtré fichiers .wav
. Tous les fichiers d'entrée doivent avoir les mêmes paramètres (nombre de canaux et largeur d'échantillon).
import argparse
import itertools
import struct
import sys
import wave
def _struct_format(sample_width, nb_samples):
return {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
def _mix_samples(samples):
return sum(samples)//len(samples)
def read_samples(wave_file, nb_frames):
frame_data = wave_file.readframes(nb_frames)
if frame_data:
sample_width = wave_file.getsampwidth()
nb_samples = len(frame_data) // sample_width
format = _struct_format(sample_width, nb_samples)
return struct.unpack(format, frame_data)
else:
return()
def write_samples(wave_file, samples, sample_width):
format = _struct_format(sample_width, len(samples))
frame_data = struct.pack(format, *samples)
wave_file.writeframes(frame_data)
def compatible_input_wave_files(input_wave_files):
nchannels, sampwidth, framerate, nframes, comptype, compname = input_wave_files[0].getparams()
for input_wave_file in input_wave_files[1:]:
nc,sw,fr,nf,ct,cn = input_wave_file.getparams()
if (nc,sw,fr,ct,cn) != (nchannels, sampwidth, framerate, comptype, compname):
return False
return True
def mix_wave_files(output_wave_file, input_wave_files, buffer_size):
output_wave_file.setparams(input_wave_files[0].getparams())
sampwidth = input_wave_files[0].getsampwidth()
max_nb_frames = max([input_wave_file.getnframes() for input_wave_file in input_wave_files])
for frame_window in xrange(max_nb_frames // buffer_size + 1):
all_samples = [read_samples(wave_file, buffer_size) for wave_file in input_wave_files]
mixed_samples = [_mix_samples(samples) for samples in itertools.izip_longest(*all_samples, fillvalue=0)]
write_samples(output_wave_file, mixed_samples, sampwidth)
def concatenate_wave_files(output_wave_file, input_wave_files, buffer_size):
output_wave_file.setparams(input_wave_files[0].getparams())
sampwidth = input_wave_files[0].getsampwidth()
for input_wave_file in input_wave_files:
nb_frames = input_wave_file.getnframes()
for frame_window in xrange(nb_frames // buffer_size + 1):
samples = read_samples(input_wave_file, buffer_size)
if samples:
write_samples(output_wave_file, samples, sampwidth)
def argument_parser():
parser = argparse.ArgumentParser(description='Mix or concatenate multiple .wav files')
parser.add_argument('command', choices = ("mix", "concat"), help='command')
parser.add_argument('output_file', help='ouput .wav file')
parser.add_argument('input_files', metavar="input_file", help='input .wav files', nargs="+")
parser.add_argument('--buffer_size', type=int, help='nb of frames to read per iteration', default=1000)
return parser
if __name__ == '__main__':
args = argument_parser().parse_args()
input_wave_files = [wave.open(name,"rb") for name in args.input_files]
if not compatible_input_wave_files(input_wave_files):
print "ERROR: mixed wave files must have the same params."
sys.exit(2)
output_wave_file = wave.open(args.output_file, "wb")
if args.command == "mix":
mix_wave_files(output_wave_file, input_wave_files, args.buffer_size)
elif args.command == "concat":
concatenate_wave_files(output_wave_file, input_wave_files, args.buffer_size)
output_wave_file.close()
for input_wave_file in input_wave_files:
input_wave_file.close()
Après avoir lu les échantillons (par exemple avec le module d'onde, plus de détails here), vous pouvez avoir les valeurs échelles entre -1 et 1 (ce qui est la convention pour les signaux audio).
Dans ce cas, vous pouvez ajouter:
# scale to -1.0 -- 1.0
max_nb_bit = float(2**(nb_bits-1))
samples = signal_int/(max_nb_bit + 1.0)
avec nb_bits
la profondeur de bits et signal_int
les valeurs des nombres entiers.
quand j'essaye .getsamplewidth il m'a donné une valeur 2 signifiant que 2 octets .. quand j'essaye .readframes (1) devrait retourner 1 image puis il est retourné pour moi comme "/ x03/x16" qui je suppose est de 2 octets, donc cela signifie que 1 trame a seulement 1 échantillon .. ce qui est l'utilisation getnchannels ?? je veux prendre des échantillons de chaque image séparement et les représenter dans les intergers, comment puis-je ?? – kaki
@kaki, dans chaque trame, il y a le premier échantillon de chaque canal, puis le deuxième échantillon de chaque canal, puis ainsi de suite. Donc, à moins que votre son soit mono, c'est-à-dire juste un canal, vous devez décider quoi faire avec les canaux (passez tous sauf un, faites la moyenne, peu importe). Disons que c'est 1 canal (mono), le plus simple, puis 'x = array.array ('h', w.getframes (1))' vous donne dans 'x' un tableau avec tous les samples de la première image (next, si dans une boucle) comme des entiers, tout comme vous dites que vous voulez ('h', pas' H': ils sont signés). Si stéréo, 2 canaux, même les indices de «x» ont par exemple. échantillons de canal gauche. Little-endian btw. –
BTW, le format docs à https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ n'utilise pas le concept de "cadres" mais plutôt "morceaux" et "sous-morceaux", mais à la fin, il vient à peu près la même chose bien sûr ;-). –