こんにちは。
wavファイルやmp3ファイルといったオーディオファイルをデータベースに格納したいと考えました。
また、データベースで格納されたオーディオ情報を取り出して、オーディオファイルに復元したいと思いました。
今回のブログでは、『Pythonによってオーディオファイルからオーディオ情報を作成し、SQLを用いてデータベースに格納する
』、『データベースからSQLを用いてオーディオ情報を取り出し、それをオーディオファイルに復元する
』、この二点について述べていきます。
この記事で得られるサブ情報は以下の通りです。
・Pythonスクリプト上でSqlite3を用いたデータベースの接続方法
・Pythonスクリプト上でSqlite3を用いたテーブルの操作
・バイナリデータをBLOB型として直接データベースに格納する方法
・Pydubを用いたオーディオ情報の取得方法、オーディオファイルの作成方法
それでは早速手順を追っていきましょう。
#0. 作成したスクリプトの概要
今回作成したスクリプトの概要は以下のようになります。
audio_to_db.py
では、オーディオファイルをオーディオ情報に変換したのちに、オーディオ情報をデータベースに格納しています。
audio_to_db.py
の解説をセクション1で行っています。
また、db_to_audio.py
では、データベースからオーディオ情報を取り出し、オーディオファイルに復元しています。
db_to_audio.py
の解説をセクション2で行っています。
オーディオファイルとオーディオ情報のやり取りをPydub
モジュールを用いて行いました。
また、データベースとのやりとりをSqlite3
モジュールを用いて行いました。
#1. オーディオファイルからオーディオ情報を作成し、データベースに格納する
オーディオファイルをデータベースに格納していきます。
データベース格納までの手順としては、次のような概要になります。
1.1. オーディオファイルをPydubモジュールを用いてオーディオ情報に変換
1.2. Sqlite3モジュールを用いてテーブルを作成し、オーディオ情報を格納
オーディオファイルを変換するのにPythonのPydubモジュールを用います。
それに合わせて、今回はPythonスクリプトでSQLを記述することで、ファイルの変換からデータベース格納の流れをPythonスクリプト一個でまとめたいと思います。
PythonでSQLを記述するにはSqlite3モジュールを用います。
##1.0. 全体のソースコード
オーディオファイルをデータベースに格納するソースコードは以下の通りです。
import sqlite3
from contextlib import closing
from pydub import AudioSegment
import re
import sys
filepath = sys.argv[1] #データベースに格納するオーディオファイルのパスをコマンドライン引数で指定
extension = re.sub(r'.*[.]', '', filepath) #オーディオファイルの拡張子
#AudioSegmentオブジェクトとしてオーディオファイルを読み込む
#拡張子によって読み込み方法を指定(WAV, MP3)
audio = AudioSegment.from_wav(filepath) if extension == 'wav'\
else AudioSegment.from_mp3(filepath)
#オーディオ情報を取得
#バイナリデータ, ビット数(16bit->2, 24bit->3, ...)
#サンプリング周波数(44100Hzになりがち), チャネル(1ch, 2ch)
audio_data = AudioSegment.get_array_of_samples(audio)
audio_sample_width = audio.sample_width
audio_frame_rate = audio.frame_rate
audio_channels = audio.channels
# print(type(audio_data), audio_sample_width, audio_frame_rate, audio_channels)
#データベースと接続
dbname = 'sample_audio.db' #DB名
with closing(sqlite3.connect(dbname)) as connection: #closing書いておくといいとのこと。
cursor = connection.cursor() #データベースとの接続で、作業スペースcursorを確保
#audioテーブルが無い場合に新たに作成する。
#オーディオ情報のバイナリデータdataはblob型で格納する。
sql = '''
CREATE TABLE IF NOT EXISTS audio (id integer primary key autoincrement, filepath text, data blob, sample_width integer, frame_rate integer, channels integer)
'''
cursor.execute(sql) #sql構文をcursorに反映
#audioテーブルにオーディオ情報のレコードを追加する。
#sql内で(?,?,?,?,?)とすることで、cursor.execute()の第二引数が?の変数になる。
sql = '''
INSERT INTO audio (filepath, data, sample_width, frame_rate, channels) values (?,?,?,?,?)
'''
data = [filepath, audio_data, audio_sample_width, audio_frame_rate, audio_channels]
cursor.execute(sql, data)
#データベースに変更を保存->接続を閉じる。
connection.commit()
connection.close()
以降では、ソースコードの詳細について解説していきます。
##1.1. オーディオファイルをPydubモジュールを用いてオーディオ情報に変換
ソースコードを元に、ここではオーディオファイルをオーディオ情報に変換する方法について、詳細を記述していきます。
###1.1.1. Pydubモジュールのインストール
まずは、必要となるモジュールをインストールしましょう。
オーディオファイルをオーディオ情報に変換するのに、今回はPydubモジュールをインストールします。
同時に、Pydubモジュールを用いるために必要な、ffmpegをインストールします。
#ffmpegをインストール
apt install ffmpeg
#Pydubをインストール
pip3 install pydub
###1.1.2. PydubでオーディオファイルからAudioSegmentオブジェクトを作成
Pydubモジュールを用いて、オーディオファイルをオーディオ情報に変換してみます。
filepath = sys.argv[1]
extension = re.sub(r'.*[.]', '', filepath)
audio = AudioSegment.from_wav(filepath) if extension == 'wav'\
else AudioSegment.from_mp3(filepath)
AudioSegmentオブジェクトとしてオーディオ情報を格納します。
audio = AudioSegment.from_wav(filepath)
では、WAVファイルfilepath
からオーディオ形成に必要となる情報を格納します。
MP3ファイルの場合はfrom_mp3(filepath)
となります。
###1.1.3. AudioSegmentオブジェクトからオーディオ情報を取得
次に、AudioSegmentからオーディオ情報を取り出しましょう。
audio_data = AudioSegment.get_array_of_samples(audio)
audio_sample_width = audio.sample_width
audio_frame_rate = audio.frame_rate
audio_channels = audio.channels
AudioSegmentから取り出すことができるオーディオ情報は以下の通りです。
data: オーディオのバイナリデータ
sample_width: ビット数, 2->16bit, 3->24bit,...
frame_rate: サンプリング周波数
channels: チャネル, ステレオ or モノラル
オーディオのバイナリデータは、AudioSegment.get_array_of_samples(audio)
で入手できます。
これらの4つの情報は、データベースからオーディオファイルを復元する際にも、必要となる情報になります。
##1.2. Sqlite3モジュールを用いてテーブルを作成し、オーディオ情報を格納
オーディオ情報を格納するためのデータベースおよびテーブルを作成し、オーディオファイルを格納していきます。
###1.2.1. Sqlite3モジュールのインストール
まずは、データベースに接続するためにSQL構文を使いたいので、今回はSqlite3モジュールをインストールします。
#Sqlite3をインストール
pip3 install sqlite3
###1.2.2. Sqlite3を用いてデータベースと接続する方法
次に、Sqlite3モジュールを用いて、オーディオ情報を格納するデータベースと接続してみます。
dbname = 'sample_audio.db' #DB名
with closing(sqlite3.connect(dbname)) as connection:
cursor = connection.cursor()
sql = '''
SQLを記述
'''
cursor.execute(sql)
sql = ''' #複数SQL構文がある場合は、cursor.execute()を繰り返す。
SQLを記述
'''
cursor.execute(sql)
connection.commit()
connection.close()
with closing(sqlite3.connect(dbname)) as connection
とすることで、データベースと接続します。
dbnameというデータベースのパスがない場合は、自動生成してくれるようです。
次に、データベースとの接続connectionを作成した後に、connection.cursor()
でcursorオブジェクトを作成します。
このcursorオブジェクトでSQLの操作を行います。
cursor.execute(sql)
で、コメントアウトした構文sqlを、cursor上で反映します。
ここで注意ですが、cursorオブジェクト上でsqlを反映させただけでは、データベース上のテーブル本体には反映されません。
connection.commit()
とすることで、初めてデータベース上のテーブルに反映されます。
最後にconnection.close()
でデータベースとの接続を切ります。
###1.2.2. SQL構文を記述してaudioテーブルを作成
次に、オーディオ情報を格納するためのテーブルを作成するSQL構文の内容を説明します。
sql = '''
CREATE TABLE IF NOT EXISTS audio (id integer primary key autoincrement, filepath text, data blob, sample_width integer, frame_rate integer, channels integer)
'''
CREATE TABLE IF NOT EXISTS audio
を記述して、audioテーブルがデータベース上に無い場合に作成するようにしています。
そのため、データベースやaudioテーブルを自ら削除しない限り、原則的にはこのSQLはスルーされます。
オーディオ情報を格納するカラムの定義は次になります。
id: 主キー, INT
filepath: オーディオファイルの名前, TEXT
data: オーディオのバイナリデータ, BLOB
sample_width: ビット数, INT
frame_rate: サンプリング周波数, INT
channels: チャネル, INT
また、メディアデータをデータベースに格納するとき、格納方法は二通り存在すると考えます。
・メディアデータのバイナリデータをBLOB型としてデータベースに直接格納する。
・メディアデータのパスをデータベースに格納し、ローカルの指定されたパスにメディアデータを配置する。
今回のテーブルでは、オーディオのバイナリデータはBLOB型を用いてデータベースの中に直接格納しています。
###1.2.3. SQL構文を記述してaudioテーブルにオーディオ情報を格納
次に、作成したaudioテーブルにオーディオ情報を格納していきます。
sql = '''
INSERT INTO audio (filepath, data, sample_width, frame_rate, channels) values (?,?,?,?,?)
'''
data = [filepath, audio_data, audio_sample_width, audio_frame_rate, audio_channels]
cursor.execute(sql, data)
INSERT INTO audio (columns) values (?)
によって、audioテーブルにレコードを挿入することができます。
また、SQLコメントアウトの中に(?)
と記述することで、cursor.execute(sql, data)
の第二引数リスト型dataが(?)
の変数になります。
これによって、audioテーブルにオーディオ情報を格納することができます。
以上によって、**オーディオファイルからオーディオ情報を作成し、データベースに格納する
**ことが出来ました。
#2. データベースからオーディオ情報を取り出し、それをオーディオファイルに復元する
次にデータベースからオーディオファイルを復元してみましょう。手順としては、次のような概要になります。
2.1. Sqlite3モジュールを用いてデータベースからオーディオ情報を取得
2.2. Pydubモジュールを用いてオーディオファイルに復元
こちらも、Pythonスクリプト一個でまとめていきます。
##2.0. 全体のソースコード
データベースからオーディオファイルに復元するソースコードは以下の通りです。
import sqlite3
from contextlib import closing
from pydub import AudioSegment
import re
import sys
dbname = 'sample_audio.db'
#データベースと接続
with closing(sqlite3.connect(dbname)) as connection:
cursor = connection.cursor()
#audioテーブルから、指定したidのオーディオデータのレコードを取り出したい。
sql = '''
SELECT id, filepath, data, sample_width, frame_rate, channels FROM audio Where id=(?)
'''
cursor.execute(sql, sys.argv[1]) #コマンドライン引数でidを指定し、sql構文をcursorに反映
output = cursor.fetchone() #取り出した1個のレコードをOUTPUTに格納
connection.close()
#オーディオ情報を取り出す。
#id, パス, バイナリデータ, ビット数, サンプリングレート, チャネルを各変数に格納
[audio_id, audio_filepath, audio_data, audio_sample_width, audio_frame_rate, audio_channels] = output
print(audio_id, audio_filepath, type(audio_data), audio_sample_width, audio_frame_rate, audio_channels)
#バイナリデータ, ビット数, サンプリングレート, チャネルからAudioSegmentを作成
audio = AudioSegment(audio_data, sample_width=audio_sample_width, frame_rate=audio_frame_rate, channels=audio_channels)
extension = re.sub(r'.*[.]', '', audio_filepath) #ファイルの拡張子
audio.export('result_'+audio_filepath, format=extension) #拡張子を指定してオーディオファイルを出力
次の見出しから、ソースコードの主要部分について解説していきます。
##2.1. Sqlite3モジュールを用いてデータベースからオーディオ情報を取得
データベースからオーディオファイルの復元に必要となるオーディオ情報を取得していきます。
sql = '''
SELECT id, filepath, data, sample_width, frame_rate, channels FROM audio Where id=(?)
'''
cursor.execute(sql, sys.argv[1])
output = cursor.fetchone()
[audio_id, audio_filepath, audio_data, audio_sample_width, audio_frame_rate, audio_channels] = output
SELECT columns FROM audio where id=(?)
と記述することによって、audioテーブルからidが変数(?)
と一致するレコードを取得し、cursorオブジェクトに格納します。
cursor.execute(sql, sys.argv[1])
によって、変数(?)
をコマンドライン引数で指定できるようにしました。
cursor.fetchone()
によって、SELECT構文によって取得したオーディオ情報を、cursorオブジェクトから取得することができます。
ちなみに、レコードを複数まとめて取得したい場合、cursor.fetchall()
によって複数取得することができます。
##2.2. Pydubモジュールを用いてオーディオファイルに復元
データベースから取得したオーディオ情報をオーディオファイルに復元していきます。
audio = AudioSegment(audio_data, sample_width=audio_sample_width, frame_rate=audio_frame_rate, channels=audio_channels)
extension = re.sub(r'.*[.]', '', audio_filepath)
audio.export('result_'+audio_filepath, format=extension)
AudioSegment(data, sample_width, frame_rate, channels)
に、データベースから取得したオーディオ情報を格納して、AudioSegmentオブジェクトを作成します。
最後に、AudioSegmentオブジェクトのexport(path, format)
メソッドを用いて、オーディオファイルを出力します。
formatにはオーディオファイルの拡張子を渡します。
以上によって、**データベースからSQLを用いてオーディオ情報を取り出し、それをオーディオファイルに復元する
**ことが出来ました。
#3.終わりに・感想
今回のブログでは、『Pythonによってオーディオファイルからオーディオ情報を作成し、SQLを用いてデータベースに格納する
』、『データベースからSQLを用いてオーディオ情報を取り出し、それをオーディオファイルに復元する
』、この二点について手順を述べてきました。
今回は、データベースをローカル上に保存する形となりましたが、AWS等クラウド上にデータベースを格納して、アクセスするのがトレンドなのでしょうね。
また、オーディオのバイナリデータをBLOB型としてデータベースに直接保存しましたが、この方法は多数派なのでしょうか。。。
実務だと、クラウド上だと、メディアデータをどうやって保存するのが現実的でしょうか。。。
さらなる勉強が必要そうです。
こちらのブログが少しでもお役に立つことが出来れば幸いです。
それでは、最後までお読みいただきありがとうございました。