LoginSignup
9

More than 5 years have passed since last update.

wavファイル分割プログラムの作成

Posted at

説明

pythonを使ってwav音声ファイルの分割プログラムを作ってみました。ググってみると、いろんなプログラムがヒットされますが、一応完全に動けるプログラムは見つかれなかったので、ポスティングしておきます。 

機能として、以下の二つを実装してみました。

  • 音声ファイルの等分割
  • 各分割ファイルの最低時間長さを指定し、無言ポイントで自動的に分割

プログラムコード

split.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
import wave
import sys
import os
import argparse

class Audio:
    def __init__(self, filename):
        self.filename = filename
        self.nframe = 0 #sample数
        self.rframe = 1 #sample rate数
        self.channels = 0 #チャンネル
        self.sampwidth = 0 #sample size

    #return audio file as array of integer
    def read(self):
        #read wav file
        wav = wave.open(self.filename, "r")

        #move to head of the audio file
        wav.rewind()

        self.nframe = wav.getnframes()
        self.rframe = wav.getframerate()
        self.channels = wav.getnchannels()
        self.sampwidth = wav.getsampwidth()

        # read to buffer as binary format
        buf = wav.readframes(self.nframe)
        wav.close()

        if(self.channels == 1):
            audio_data = np.frombuffer(buf, dtype="int16")
        elif(self.channels == 2):
            audio_data = np.frombuffer(buf, dtype="int32")

        return audio_data 

    def is_split(self, y, size):
        if (len(y) > size):
            return True
        return False

    def is_silence(self, iterable):
        if max(iterable)<4096:
            return True
        else:
            return False

    def split_equal(self, y, split_num): 
        segment_points = list()
        size = len(y) / split_num;

        count=1
        while True: 
            if(count==(split_num)):
                break
            segment_points.append(size*count)
            count = count + 1

        segment_points.append(len(y))
        return segment_points

    def split(self, y, time_term, slience_time_term): 
        size = self.rframe*time_term #分割サイズ
        silence_size = self.rframe*slience_time_term #0.1s 無音の場合切る

        segment_points = list()

        count = 1
        count_silence = 0
        start = 0
        offset = 0 #segmentポイントから時間を図り始める

        while True: 
            start = offset + int(count*size + count_silence*silence_size)
            end = offset +   int(count*size + (count_silence+1)*silence_size)
            # end = start + (count_silence+1)*silence_size

            if not self.is_split(y[start+silence_size/2: ], size):
                break

            z = np.absolute(y[start:end])

            if self.is_silence(z):
                if self.is_split(y[start+end/2: ], size):
                    segment_points.append(start+end/2)
                    count = count + 1
                    count_silence = 0
                    offset += start+end/2
                else:
                    break
            else:
                count_silence = count_silence + 1       

        segment_points.append(len(y))
        return segment_points

    #audioの時間、単位: s
    def audio_time(self):
        return float(self.nframe/self.rframe)

    def write(self, filename, segment_points, audio_data):
        count = 0
        start = 0 
        for end in segment_points:
            version = "{:03d}".format(count)
            w = wave.Wave_write(filename+"/"+ filename+"-"+version+".wav")
            w.setnchannels(self.channels)
            w.setsampwidth(self.sampwidth)
            w.setframerate(self.rframe)
            w.writeframes(audio_data[start:end])
            start = end 
            w.close()
            count = count+1 

def parse_args():
    parser = argparse.ArgumentParser(description='WAV ファイル分割プログラム')
    parser.add_argument('-i', action='store', dest='file_name',
                help='wavファイルを指定', required=True, type=str)

    parser.add_argument('-type', action='store', type=str, dest='type', default="equal",
                help='分割種類の選択: 等分割、無音分割(equal | optional), デフォルト: euqal')
    parser.add_argument('-n', action='store', type=int, dest='split_num', default=2,
                help='等分割の場合, 分割数を設定, デフィルト: 2')

    parser.add_argument('-t', action='store', type=int, dest='time', default=300,
                help='各分割ファイルの最低サイズ, 単位: 秒, デフォルト: 300s')
    parser.add_argument('-st', action='store', type=float, dest='slience_time', default=1,
                help='無音ターム, 単位: 秒, デフォルト: 1s')

    parser.add_argument('--version', action='version', version='%(prog)s 1.0')

    results = parser.parse_args()
    return results

try:
    #引数の解析
    args = parse_args()

    #add progress bar, time_term, 無音term
    audio = Audio(args.file_name)
    audio_data  = audio.read()
    # time = audio.audio_time()
    if args.type=="equal": 
        segment_points = audio.split_equal(audio_data, args.split_num)
    elif args.type=="optional": 
        segment_points = audio.split(audio_data, args.time, args.slience_time)


    output = os.path.splitext(os.path.basename(args.file_name))
    os.system("sh check.sh " + output[0])
    audio.write(output[0], segment_points, audio_data)
except:
    print("FALSE")
    raise

テスト用Webサービス

上のプログラムを使って、AWSのサーバーにテスト用Webサーバを作ってみました。数十MBぐらいのファイルならテストできると思います。

音声ファイル分割サービズ

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
9