#wavファイルを等間隔に分割
【Python】WAVファイルを等間隔に分割するプログラム【サウンドプログラミング】を参考にして以下のコードを書きました。
import wave
import struct
from scipy import fromstring,int16
import numpy as np
import os
import math
# 一応既に同じ名前のディレクトリがないか確認。
file = os.path.exists("output")
print(file)
if file == False:
#保存先のディレクトリの作成
os.mkdir("output")
#filenameに読み込むファイル、timeにカットする間隔
def cut_wav(filename,time):
# timeの単位は[sec]
# ファイルを読み出し
wavf = filename + '.wav'
wr = wave.open(wavf, 'r')
# waveファイルが持つ性質を取得
ch = wr.getnchannels()
width = wr.getsampwidth()
fr = wr.getframerate()
fn = wr.getnframes()
total_time = 1.0 * fn / fr
integer = math.floor(total_time) # 小数点以下切り捨て
t = int(time) # 秒数[sec]
frames = int(ch * fr * t)
num_cut = int(integer//t)
# waveの実データを取得し、数値化
data = wr.readframes(wr.getnframes())
wr.close()
X = np.frombuffer(data, dtype=int16)
for i in range(num_cut):
print(i)
# 出力データを生成
outf = 'output/' + str(i) + '.wav'
start_cut = int(i*frames)
end_cut = int(i*frames + frames)
print(start_cut)
print(end_cut)
Y = X[start_cut:end_cut]
outd = struct.pack("h" * len(Y), *Y)
# 書き出し
ww = wave.open(outf, 'w')
ww.setnchannels(ch)
ww.setsampwidth(width)
ww.setframerate(fr)
ww.writeframes(outd)
ww.close()
print("input filename = ")
f_name = "test"
print("cut time = ")
cut_time = input()
cut_wav(f_name,cut_time)
実行結果
True
input filename =
cut time =
1
0
0
88200
1
88200
176400
2
176400
264600
3
264600
352800
4
352800
441000
5
441000
529200
6
529200
617400
7
617400
705600
8
705600
793800
上手くいきました。が、このプログラムは整数でしか分割が出来ません。
ちょこちょこ書き換えて、1秒未満でも分割できるようにします。
import wave
import struct
from scipy import fromstring,int16
import numpy as np
import os
import math
# 一応既に同じ名前のディレクトリがないか確認。
file = os.path.exists("output")
print(file)
if file == False:
#保存先のディレクトリの作成
os.mkdir("output")
#filenameに読み込むファイル、timeにカットする間隔
def cut_wav(filename,time):
# timeの単位は[sec]
# ファイルを読み出し
wavf = filename + '.wav'
wr = wave.open(wavf, 'r')
# waveファイルが持つ性質を取得
ch = wr.getnchannels()
width = wr.getsampwidth()
fr = wr.getframerate()
fn = wr.getnframes()
total_time = 1.0 * fn / fr
integer = math.floor(total_time*100) # 小数点以下切り捨て
t = int(time*100) # 秒数[sec]
frames = int(ch * fr * t /100)
num_cut = int(integer//t)
# waveの実データを取得し、数値化
data = wr.readframes(wr.getnframes())
wr.close()
X = np.frombuffer(data, dtype=int16)
for i in range(num_cut):
print(i)
# 出力データを生成
outf = 'output/' + str(i) + '.wav'
start_cut = int(i*frames)
end_cut = int(i*frames + frames)
print(start_cut)
print(end_cut)
Y = X[start_cut:end_cut]
outd = struct.pack("h" * len(Y), *Y)
# 書き出し
ww = wave.open(outf, 'w')
ww.setnchannels(ch)
ww.setsampwidth(width)
ww.setframerate(fr)
ww.writeframes(outd)
ww.close()
print("input filename = ")
f_name = "test"
print("cut time = ")
cut_time = input()
cut_wav(f_name,float(cut_time))
変えた所は、最後の行のcut_timeをfloat(cut_time)にして、float型を扱えるようにしたのと、
integer = math.floor(total_time*100) # 小数点以下切り捨て
t = int(time*100) # 秒数[sec]
frames = int(ch * fr * t /100)
ここの3行(30~32行)です。
timeを100倍にする事で、100倍して整数になる数字ならば使えるようになり、それによる計算のずれを修正しています。思ったより少ない修正で済みました。
cut _timeに1を入力して、最初のコードと同じ結果が出るか試してみます。
True
input filename =
cut time =
1
0
0
88200
1
88200
176400
2
176400
264600
3
264600
352800
4
352800
441000
5
441000
529200
6
529200
617400
7
617400
705600
8
705600
793800
上手くいったっぽいです。
#終わりに
サンプリングレートが44100なら、1秒に取得しているフレーム数は44100はあるはずです。だったら1秒単位ではなく、1/44100秒単位で音を切れるんじゃないか、と思ってコードの書き換えを始めました。
しかし、最後に出来上がったものを見ると違うようです。これ、ちょっと書き換えれば0.001でも扱えてしまいます。
まあ、あまり刻んでも実際には1フレームを更に分割する事は出来ない…と思うので、10000分割、とかやってもあまり意味は無いんでしょう。