challenge Tiny MML

文字列の入力をとり、音を鳴らすプログラムを作ってください。

入力はcがド、dがレ、eがミ、fがファ、gがソ、aがラ、bがシ、rが休符とします。この8文字以外の文字は入力に含まれていないと仮定して構いません。おのおのの音符・休符は八分音符・八分休符とします。

オクターブや音の長さの変更、同時発音などの機能は不要です。

サンプル入力(カエルの歌)

cdefedcrefgagfercrcrcrcrcdefedcr

Posted feedbacks - Python

とりあえずbeepで。win専用。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import winsound
import time

def play(mmf):
  toi = lambda x: int(ord(x))
  for n in mmf:
    if n == 'r': time.sleep(0.5)
    else : winsound.Beep(play.fq[toi(n)-toi('a')], 500)
play.fq = [440, 494, 262, 294, 330, 349, 392]

play("cdefedcrefgagfercrcrcrcrcdefedcr")

上のと同じコードをPython+ctypesを使って記述。音の長さは他の人のコードを参考にして0.25秒に変更しました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import ctypes
import time
import sys

MIDI_MAPPER = -1
MMSYSERR_NOERROR = 0
CALLBACK_NULL = 0

class Midi:
    def __init__(self):
        self._dll = ctypes.windll.winmm
        self._h = ctypes.c_void_p()
        self._call("midiOutOpen", ctypes.byref(self._h), MIDI_MAPPER, 0, 0, CALLBACK_NULL)

    def __del__(self):
        self._call("midiOutClose", self._h)

    def play(self, note):
        self._call("midiOutShortMsg", self._h, self._msg(0x9, 0, note, 100))
        self.wait()
        self._call("midiOutReset", self._h)

    def wait(self):
        time.sleep(0.25)

    def _call(self, name, *args):
        ret = getattr(self._dll, name)(*args)
        if ret != MMSYSERR_NOERROR:
            raise RuntimeError("mmsystem error (%s)" % hex(ret))

    def _msg(self, status, channel, data1, data2):
        return (status<<4) | channel | (data1<<8) | (data2<<16)

def play(s):
    m = Midi()
    notes = {'c': 60, 'd': 62, 'e': 64, 'f': 65,
             'g': 67, 'a': 69, 'b': 71}
    for c in s:
        if c == 'r':
            m.wait()
        else:
            m.play(notes[c])

def main():
    if len(sys.argv) == 2:
        play(sys.argv[1])
    else:
        play("cdefedcrefgagfercrcrcrcrcdefedcr")

if __name__ == '__main__':
    main()

ordの返り値は元からintなのでtoiを定義する必要はないですね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import winsound
import time

PLAY_FQ = [440, 494, 262, 294, 330, 349, 392]

def play(mmf):
    for n in mmf:
        if n == 'r':
            time.sleep(0.5)
        else:
            winsound.Beep(
                PLAY_FQ[ord(n) - ord('a')], 500)

play("cdefedcrefgagfercrcrcrcrcdefedcr")

#1433をヒントにして、自前で正弦波を生成しました。
式は適当ですが、一応それっぽい音はします。

利用パッケージの都合で、Linuxと*BSD(?)のみ対応です。

8分音符は0.5秒にしました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import math
import struct
import ossaudiodev

def sw(r, f, t):
  return struct.pack('h', int(math.sin((t/(float(r)/f))*2*math.pi)*0x7fff))

wav = {
  'c': ''.join([sw(8000, 262, i) for i in range(4000)]),
  'd': ''.join([sw(8000, 294, i) for i in range(4000)]),
  'e': ''.join([sw(8000, 330, i) for i in range(4000)]),
  'f': ''.join([sw(8000, 349, i) for i in range(4000)]),
  'g': ''.join([sw(8000, 392, i) for i in range(4000)]),
  'a': ''.join([sw(8000, 440, i) for i in range(4000)]),
  'b': ''.join([sw(8000, 494, i) for i in range(4000)]),
  'r': '\x00\x00' * 4000
}

dsp = ossaudiodev.open('w')
dsp.setparameters(ossaudiodev.AFMT_S16_LE, 1, 8000)
dsp.writeall(''.join([wav[c] for c in 'cdefedcrefgagfercrcrcrcrcdefedcr']))
dsp.flush()
dsp.close()

Index

Feed

Other

Link

Pathtraq

loading...