1
0

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 3 years have passed since last update.

『pythonで音を鳴らす方法を詳しめに解説』を外部ライブラリなしで実装してみた

Last updated at Posted at 2021-12-21

はじめに

この記事は @ShijiMi-Soup 様の pythonで音を鳴らす方法を詳しめに解説 を参考にしつつ外部ライブラリ、つまりnumpypyaudioを用いないで音を鳴らすことに成功したので共有する記事です。環境や宗教上の理由で外部のライブラリ(pipでインストールするようなもの)を用いることが出来ない場合などにご活用ください。
本家様の記事は音ってなんだ的な所から解説していますが、そのような解説は本家様の記事に任せて、この記事では実装例と相違点について取り上げようと思います。それでは参りましょう。

環境

Python 3.9.0

音を鳴らす機構はそれぞれの環境に依存するので後々解説します。

プログラムの実装

まずはプログラムを見ていただきます。

import wave
import struct
import math
import os

def arrange(start, end):
    l = []
    x = start
    while(x < end):
        l.append(x)
        x += 1.0
    return l

def mul(x, l):
    return [x * e for e in l]

def div(x, l):
    return [(lambda a, b: a / b if b != 0 else 0)(e, x) for e in l]

def sin(l):
    return [math.sin(e) for e in l]

sec = 1.0 #1秒
note_hz = 440 #ラの音の周波数
sample_hz = 44100 #サンプリング周波数

t = arrange(0, sample_hz * sec)
wv = sin(div(sample_hz, mul(2 * math.pi * note_hz, t)))

max_num = 32767.0 / max(wv)
wv16 = [int(x * max_num) for x in wv]
bi_wv = struct.pack("h" * len(wv16), *wv16)

name_file = "sound.wav"

file = wave.open(name_file, mode='wb')
param = (1,2,sample_hz,len(bi_wv),'NONE','not compressed')
file.setparams(param)
file.writeframes(bi_wv)
file.close()

if os.name == "nt":
    import winsound
    winsound.PlaySound(name_file, winsound.SND_FILENAME)

以降は解説です。

外部ライブラリに頼らないとどうなるか

外部ライブラリに頼らないとどうなるかという話ですが、まずはnumpyから、元の記事を見ていただければ何となくわかると思いますが、音声ファイルはたくさんの数値の集まりで出来ています、配列ですね。numpyでは便利な関数や配列クラスを定義されています。例えばarrange関数を使えば浮動小数点数を含む数列を生成できたり、配列に対して掛け算や割り算を行うことが出来ます。それがnumpyの素晴らしい所なのですが今回はその恩恵にあずかることはできないので自前で実装します。それがソースコード上部の関数群です。

# 始まりと終わりを指定して等差数列の生成する関数
def arrange(start, end):
    l = []
    x = start
    while(x < end):
        l.append(x)
        x += 1.0
    return l

# リスト型に対して掛け算を行う関数
def mul(x, l):
    return [x * e for e in l]

# リスト型に対して割り算を行う関数
def div(x, l):
    return [(lambda a, b: a / b if b != 0 else 0)(e, x) for e in l]

# リスト型に対してそれぞれの値を`math.sin`関数に入れる関数
def sin(l):
    return [math.sin(e) for e in l]

若干お行儀悪い気がしますが許してください。

次にpyaudioが使えないとという話ですが、何らかの音声再生機能をかわりに選ばなくてはいけません。実装例ではwindows環境向けに記述されています。

if os.name == "nt":
    import winsound
    winsound.PlaySound(name_file, winsound.SND_FILENAME)

ここはPythonで鳴らすことを考えずwavファイルをコマンドから再生することを考えましょうか。例えばpaplayがインストールされている環境ならこのように記述することが出来ます。

import subprocess
subprocess.run(["paplay", name_file])

使えるかはターミナルでpaplay --versionと入力してみてください。

他にもMacならafplayというコマンドが使えるはずなのでそれを使います。

import subprocess
subprocess.run(["afplay", name_file])

音声再生はこのようにします。これで大抵のデスクトップ環境はカバーできるのでは?と思うのですが、何か良いwavの再生方法があったらコメントで共有してくれると助かります。

おわりに

今回は以上です。ショートな記事でしたが忘備録としてまとめられる程度には自分の中でまとまったので記事に起こしました。役に立つことがあれば幸いです。
ここまで読んでくださってありがとうございました。次は何しようかな…思いついたらまたやるのでもしよろしかったら次も読んでくださるとありがたいです。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?