【第9回MMD杯本選】シャオシャオ通りの物語はぜんぶほんとだよ? 【MMDFes】


あと4ヶ月でクリスマスですね。

www.py - WAVEファイルから MMD の首振り回転モーション作成 - つちのこ、のこのこ。(はてな番外地) で配布しているスクリプト貼っておきます。

付属のモデルと説明が無いと使いようがないと思いますが参考として。

u'''www - WAVEファイルから MMD の首振り回転モーション作成

Python 2.6.6
'''
from __future__ import division
import math
import wave
import struct
import os

__author__ = 'kadotanimitsuru'
__credits__ = ''
__date__ = '2012-07-25'
__version__ = '1.0.0'

#################### ここを書き換える ####################

VOICELIST = (  # 変換する音声ファイル名, 秒あたりの回転速度
    (u'sora.WAV', 1/3),
    (u'yukari.WAV', 1/3),
    (u'iroha.WAV', 1/3),
    (u'kiyoteru.WAV', 1),
    (u'yuki.WAV', 1),
    )

########################################################

FPS = 30  # 秒間フレーム数
AMPLITUDE = 40  # 振幅の倍率
INTERPOLATION_CURVE = (
    u'20,20,107,107,20,20,107,107,20,20,107,107,20,20,107,107')  # 補完曲線


class Wavedata(object):

    def __init__(self, filename):
        self.file = wave.open(filename, 'rb')
        (self.nchannels,
         sampwidth,
         self.framerate,
         self.nframes,
         comptype, compname) = self.file.getparams()
        if sampwidth != 2:
            raise ValueError('Not corresponded to the sample size %d bit.'
                             % sampwidth * 8)
        self.ended = False

    def waves(self, ms, l):
        p = self.framerate * ms // 1000
        if p < 0 or p >= self.nframes:
            f = []
            if p >= self.nframes:
                self.ended = True
        else:
            rl = min(l, self.nframes - p)
            self.file.setpos(p)
            f = list(struct.unpack(
                '<%dh' % (rl * self.nchannels), self.file.readframes(rl)))
        if self.nchannels == 1:
            return (f + [0] * (l - len(f)),)
        elif self.nchannels == 2:
            L = [f[i] for i in xrange(0, len(f), 2)]
            R = [f[i] for i in xrange(1, len(f), 2)]
            return (L + [0] * (l - len(L)),
                    R + [0] * (l - len(R)))
        else:
            raise ValueError('Not corresponded to the channels size %d.'
                             % self.nchannels)

    def volume(self, ms):
        f = self.waves(ms, self.framerate // FPS)
        return max((sum(abs(x) for x in i) // len(i) for i in f))


def www(filename, speed=1):
        w = Wavedata(filename)
        datalist = []
        ms = 0
        while not w.ended:
            v = w.volume(ms)
            ang = (speed * math.pi * 2 * ms / 1000)
            datalist.append((
                (v / 0x8000), (math.degrees(ang) % 360 - 180)))
            ms += 1000 / FPS
        return datalist


def main(voicelist):
    for filename, speed in voicelist:
        datalist = www(filename, speed)
        savename = filename.split('.')[0] + '.csv'
        print u'"%s" (%d flames)' % (savename, len(datalist))
        data = []
        for n, (v, r) in enumerate(datalist):
            if n % 2:
                v = -v
            data.append(
                (u'%d,首,0,0,0,%.3f,%.3f,0,' %
                 (n, v * AMPLITUDE, r))
                + INTERPOLATION_CURVE)
        fulldata = u'''Vocaloid Motion Data 0002
アクセ回転補助
Motion,bone,x,y,z,rx,ry,rz,x_p1x,x_p1y,x_p2x,x_p2y,y_p1x,y_p1y,y_p2x,y_p2y,z_p1x,z_p1y,z_p2x,z_p2y,r_p1x,r_p1y,r_p2x,r_p2y
%s
Expression,name,fact
Camera,d,a,x,y,z,rx,ry,rz,x_p1x,x_p1y,x_p2x,x_p2y,y_p1x,y_p1y,y_p2x,y_p2y,z_p1x,z_p1y,z_p2x,z_p2y,r_p1x,r_p1y,r_p2x,r_p2y,d_p1x,d_p1y,d_p2x,d_p2y,a_p1x,a_p1y,a_p2x,a_p2y
Light,r,g,b,x,y,z
''' % '\n'.join(data)
        with open(savename, 'w') as f:
            f.write(fulldata.encode('cp932'))
            

if __name__=='__main__':
    main(VOICELIST)

# Copyright: This module has been placed in the public domain.
# パブリックドメイン。好きに流用してください。