search
LoginSignup
6

More than 3 years have passed since last update.

posted at

updated at

音声データを1/100秒単位で分割する

wavファイルを等間隔に分割

【Python】WAVファイルを等間隔に分割するプログラム【サウンドプログラミング】を参考にして以下のコードを書きました。

pywave.py

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秒未満でも分割できるようにします。

pywave.py

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分割、とかやってもあまり意味は無いんでしょう。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
6