LoginSignup
5
6

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-10-29

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

5
6
0

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
  3. You can use dark theme
What you can do with signing up
5
6