10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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ぐらいのファイルならテストできると思います。

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

10
9
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
10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?