├── .travis.yml ├── License ├── MANIFEST.in ├── README.rst ├── bin ├── dtw_synth ├── get_mcd_dtw ├── get_mcd_plain └── test_cli.py ├── boring.darcs ├── dev ├── example_usage ├── mcd ├── __init__.py ├── dtw.py ├── metrics.py ├── metrics_fast.pyx ├── test_dtw.py ├── test_metrics.py └── util.py ├── requirements.txt ├── setup.py └── test_data ├── aligned-synth-examples ├── alignment │ ├── cmu_us_arctic_slt_a0003.lab │ └── cmu_us_arctic_slt_a0044.lab ├── cmu_us_arctic_slt_a0003.bap ├── cmu_us_arctic_slt_a0003.lf0 ├── cmu_us_arctic_slt_a0003.mgc ├── cmu_us_arctic_slt_a0044.bap ├── cmu_us_arctic_slt_a0044.lf0 └── cmu_us_arctic_slt_a0044.mgc ├── corpus.lst ├── out-dtw_synth ├── cmu_us_arctic_slt_a0003.bap ├── cmu_us_arctic_slt_a0003.lf0 ├── cmu_us_arctic_slt_a0003.mgc ├── cmu_us_arctic_slt_a0044.bap ├── cmu_us_arctic_slt_a0044.lf0 └── cmu_us_arctic_slt_a0044.mgc ├── ref-examples ├── cmu_us_arctic_slt_a0003.mgc └── cmu_us_arctic_slt_a0044.mgc └── synth-examples ├── cmu_us_arctic_slt_a0003.bap ├── cmu_us_arctic_slt_a0003.lf0 ├── cmu_us_arctic_slt_a0003.mgc ├── cmu_us_arctic_slt_a0044.bap ├── cmu_us_arctic_slt_a0044.lf0 └── cmu_us_arctic_slt_a0044.mgc /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "2.7" 5 | 6 | virtualenv: 7 | system_site_packages: true 8 | 9 | before_install: 10 | - sudo apt-get -qq update 11 | - sudo apt-get -qq install cython python-numpy 12 | 13 | install: 14 | - pip install -r requirements.txt 15 | - python setup.py build_ext --inplace 16 | 17 | script: 18 | - python -m unittest discover mcd 19 | - PYTHONPATH=. python bin/test_cli.py 20 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | Copyright 2014, 2015, 2016, 2017 Matt Shannon 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 3. The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 19 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 22 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 23 | OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include License 2 | include README.rst 3 | include requirements.txt 4 | include mcd/*.c 5 | include bin/test_cli.py 6 | recursive-include test_data * 7 | include example_usage 8 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | mcd 2 | === 3 | 4 | This package computes mel cepstral distortions in python. 5 | Mel cepstral distortions are used in assessing the quality of synthesized 6 | speech. 7 | 8 | Overview 9 | -------- 10 | 11 | Mel cepstral distortion (MCD) is a measure of how different two sequences of 12 | mel cepstra are. 13 | It is used in assessing the quality of parametric speech synthesis systems, 14 | including statistical parametric speech synthesis systems, the idea being that 15 | the smaller the MCD between synthesized and natural mel cepstral sequences, the 16 | closer the synthetic speech is to reproducing natural speech. 17 | It is by no means a perfect metric for assessing the quality of synthetic 18 | speech, but is often a useful indicator in conjunction with other metrics. 19 | 20 | The mcd package provides scripts to compute a variety of forms of MCD score: 21 | 22 | - plain MCD, for which it is assumed that the two sequences to be compared are 23 | already "aligned" in terms of their timing. 24 | - plain MCD excluding certain segments, for example silence segments. 25 | - MCD DTW, which uses dynamic time warping (DTW) to compute the minimum MCD 26 | obtainable by "aligning" the two sequences. 27 | This metric does not penalize differences in the timing between natural and 28 | synthetic speech, which is often desirable. 29 | 30 | It also contains general purpose dynamic time warping code. 31 | 32 | License 33 | ------- 34 | 35 | Please see the file ``License`` for details of the license and warranty for 36 | mcd. 37 | 38 | Installation 39 | ------------ 40 | 41 | For most purposes the simplest way to install mcd is to use pip. 42 | For example in Debian and Ubuntu:: 43 | 44 | sudo apt-get install python-numpy 45 | sudo pip install mcd 46 | 47 | The first command installs numpy from the system repository, since installing 48 | numpy using pip is generally not recommended. 49 | The second command installs the latest released version of 50 | `mcd on PyPI `_, together with any currently 51 | uninstalled python packages required by mcd. 52 | 53 | mcd can also be installed in a virtualenv:: 54 | 55 | sudo apt-get install python-numpy 56 | virtualenv --system-site-packages env 57 | env/bin/pip install mcd 58 | 59 | The latest development version of mcd is available from a github repository 60 | (see below). 61 | 62 | To check that mcd is installed correctly you can run the test suite:: 63 | 64 | python -m unittest discover mcd 65 | 66 | Examples 67 | -------- 68 | 69 | Examples of example usage (in unix) are given in ``example_usage``. 70 | 71 | Development 72 | ----------- 73 | 74 | The source code is hosted in the 75 | `mcd github repository `_. 76 | To obtain the latest source code using git:: 77 | 78 | git clone git://github.com/MattShannon/mcd.git 79 | 80 | Development is in fact done using `darcs `_, with the darcs 81 | repository converted to a git repository using 82 | `darcs-to-git `_. 83 | 84 | To install any currently uninstalled python packages required by mcd:: 85 | 86 | sudo apt-get install cython python-numpy 87 | sudo pip install -r requirements.txt 88 | 89 | To compile the cython part of mcd in the current directory:: 90 | 91 | python setup.py build_ext --inplace 92 | 93 | This command must be run after every modification to the source ``.pyx`` files. 94 | 95 | To run the full test suite, including tests of command-line tools, on the 96 | working copy:: 97 | 98 | python -m unittest discover mcd 99 | PYTHONPATH=. python bin/test_cli.py 100 | 101 | A note on ``setup.py`` 102 | ---------------------- 103 | 104 | The included ``setup.py`` file operates in one of two modes depending on 105 | whether or not the file ``dev`` is present in the project root directory. 106 | In development mode (``dev`` present, as for the github repository), the 107 | ``build_ext`` command uses cython to compile cython modules from their ``.pyx`` 108 | source, and the ``sdist`` command is modified to first use cython to compile 109 | cython modules from their ``.pyx`` source to ``.c`` files. 110 | In distribution mode (``dev`` absent, as for source distributions such as the 111 | code on PyPI), the ``build_ext`` command uses a C compiler to directly compile 112 | cython modules from the corresponding ``.c`` files. 113 | This approach ensures that source distributions can be installed on systems 114 | without cython or with an incompatible version of cython, while ensuring that 115 | distributed ``.c`` files are always up-to-date and that the source ``.pyx`` 116 | files are used instead of ``.c`` files during development. 117 | 118 | The author would welcome any suggestions for more elegant ways to achieve a 119 | similar effect to the approach described above! 120 | 121 | Bugs 122 | ---- 123 | 124 | Please use the 125 | `issue tracker `_ to submit bug 126 | reports. 127 | 128 | Contact 129 | ------- 130 | 131 | The author of mcd is `Matt Shannon `_. 132 | -------------------------------------------------------------------------------- /bin/dtw_synth: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -u 2 | 3 | """Time-warps a speech parameter sequence based on a reference.""" 4 | 5 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 6 | 7 | # This file is part of mcd. 8 | # See `License` for details of license and warranty. 9 | 10 | import os 11 | import sys 12 | import argparse 13 | import math 14 | import numpy as np 15 | 16 | from htk_io.base import DirReader 17 | import htk_io.vecseq as vsio 18 | 19 | from mcd import util 20 | from mcd import dtw 21 | import mcd.metrics_fast as mt 22 | 23 | def main(rawArgs): 24 | parser = argparse.ArgumentParser( 25 | description=( 26 | 'Time-warps a speech parameter sequence based on a reference.' 27 | ' Dynamic time warping (DTW) is used to compute the time warping.' 28 | ' By default a speech parameter sequence consisting of three' 29 | ' portions (mgc,lf0,bap) is warped to match the timing of the' 30 | ' reference speech parameter sequence.' 31 | ' Only the first portion is used when computing the warping.' 32 | ), 33 | formatter_class=argparse.ArgumentDefaultsHelpFormatter 34 | ) 35 | parser.add_argument( 36 | '--exts', dest='exts', default='mgc,lf0,bap', metavar='EXTLIST', 37 | help=( 38 | 'file extensions added to uttId to get file containing speech' 39 | ' parameters' 40 | ) 41 | ) 42 | parser.add_argument( 43 | '--param_orders', dest='paramOrders', default='40,1,5', 44 | metavar='ORDERLIST', 45 | help='orders of the parameter files (mgc,lf0,bap)' 46 | ) 47 | parser.add_argument( 48 | dest='natDir', metavar='NATDIR', 49 | help='directory containing natural speech parameters' 50 | ) 51 | parser.add_argument( 52 | dest='synthDir', metavar='SYNTHDIR', 53 | help='directory containing synthetic speech parameters' 54 | ) 55 | parser.add_argument( 56 | dest='outDir', metavar='OUTDIR', 57 | help='directory to output warped speech parameters to' 58 | ) 59 | parser.add_argument( 60 | dest='uttIds', metavar='UTTID', nargs='+', 61 | help='utterance ids (ext will be appended to these)' 62 | ) 63 | args = parser.parse_args(rawArgs[1:]) 64 | 65 | costFn = mt.logSpecDbDist 66 | 67 | paramOrders = [ 68 | int(paramOrderStr) 69 | for paramOrderStr in args.paramOrders.split(',') 70 | ] 71 | assert paramOrders 72 | mgcParamOrder = paramOrders[0] 73 | 74 | exts = args.exts.split(',') 75 | assert len(exts) == len(paramOrders) 76 | mgcExt = exts[0] 77 | 78 | vecSeqIo = vsio.VecSeqIo(mgcParamOrder) 79 | getNatVecSeq = DirReader(vecSeqIo, args.natDir, mgcExt) 80 | getSynthVecSeq = DirReader(vecSeqIo, args.synthDir, mgcExt) 81 | 82 | minCostTot = 0.0 83 | framesTot = 0 84 | for uttId in args.uttIds: 85 | print 'processing', uttId 86 | nat = getNatVecSeq(uttId) 87 | synth = getSynthVecSeq(uttId) 88 | # ignore 0th cepstral component 89 | nat = nat[:, 1:] 90 | synth = synth[:, 1:] 91 | 92 | minCost, path = dtw.dtw(nat, synth, costFn) 93 | frames = len(nat) 94 | 95 | minCostTot += minCost 96 | framesTot += frames 97 | 98 | print 'MCD = %f (%d frames)' % (minCost / frames, frames) 99 | 100 | pathCosts = [ costFn(nat[i], synth[j]) for i, j in path ] 101 | synthIndexSeq = dtw.projectPathBestCost(path, pathCosts) 102 | assert len(synthIndexSeq) == len(nat) 103 | 104 | uniqueFrames = len(set(synthIndexSeq)) 105 | repeatedFrames = len(synthIndexSeq) - uniqueFrames 106 | droppedFrames = len(synth) - uniqueFrames 107 | assert len(synth) - droppedFrames + repeatedFrames == len(nat) 108 | print ('warping %s frames -> %s frames (%s repeated, %s dropped)' % 109 | (len(synth), len(nat), repeatedFrames, droppedFrames)) 110 | print 111 | 112 | for paramOrder, ext in zip(paramOrders, exts): 113 | vecSeqIo = vsio.VecSeqIo(paramOrder) 114 | 115 | synthFullFile = os.path.join(args.synthDir, uttId+'.'+ext) 116 | synthFull = vecSeqIo.readFile(synthFullFile) 117 | 118 | synthFullWarped = dtw.warpGeneral(synthFull, synthIndexSeq) 119 | 120 | synthFullWarpedFile = os.path.join(args.outDir, uttId+'.'+ext) 121 | vecSeqIo.writeFile(synthFullWarpedFile, synthFullWarped) 122 | 123 | print 'overall MCD = %f (%d frames)' % (minCostTot / framesTot, framesTot) 124 | 125 | if __name__ == '__main__': 126 | main(sys.argv) 127 | -------------------------------------------------------------------------------- /bin/get_mcd_dtw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -u 2 | 3 | """Computes the MCD DTW metric for two sequences of mel cepstra.""" 4 | 5 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 6 | 7 | # This file is part of mcd. 8 | # See `License` for details of license and warranty. 9 | 10 | import os 11 | import sys 12 | import argparse 13 | import math 14 | import numpy as np 15 | 16 | from htk_io.base import DirReader 17 | import htk_io.vecseq as vsio 18 | 19 | from mcd import util 20 | from mcd import dtw 21 | import mcd.metrics_fast as mt 22 | 23 | def main(rawArgs): 24 | parser = argparse.ArgumentParser( 25 | description=( 26 | 'Computes the MCD DTW metric for two sequences of mel cepstra.' 27 | ' Mel cepstral distortion (MCD) is a measure of the difference' 28 | ' between two sequences of mel cepstra.' 29 | ' This utility computes the MCD between two sequences allowing for' 30 | ' possible differences in timing.' 31 | ' Specifically it uses dynamic time warping (DTW) to compute the' 32 | ' minimum MCD that can be obtained by "aligning" the two sequences' 33 | ' subject to certain constraints on the form of the alignment.' 34 | ), 35 | formatter_class=argparse.ArgumentDefaultsHelpFormatter 36 | ) 37 | parser.add_argument( 38 | '--ext', dest='ext', default='mgc', metavar='EXT', 39 | help=( 40 | 'file extension added to uttId to get file containing speech' 41 | ' parameters' 42 | ) 43 | ) 44 | parser.add_argument( 45 | '--param_order', dest='paramOrder', default=40, type=int, 46 | metavar='ORDER', 47 | help='parameter order of the cepstral files' 48 | ) 49 | parser.add_argument( 50 | dest='natDir', metavar='NATDIR', 51 | help='directory containing natural speech parameters' 52 | ) 53 | parser.add_argument( 54 | dest='synthDir', metavar='SYNTHDIR', 55 | help='directory containing synthetic speech parameters' 56 | ) 57 | parser.add_argument( 58 | dest='uttIds', metavar='UTTID', nargs='+', 59 | help='utterance ids (ext will be appended to these)' 60 | ) 61 | args = parser.parse_args(rawArgs[1:]) 62 | 63 | costFn = mt.logSpecDbDist 64 | 65 | vecSeqIo = vsio.VecSeqIo(args.paramOrder) 66 | getNatVecSeq = DirReader(vecSeqIo, args.natDir, args.ext) 67 | getSynthVecSeq = DirReader(vecSeqIo, args.synthDir, args.ext) 68 | 69 | minCostTot = 0.0 70 | framesTot = 0 71 | for uttId in args.uttIds: 72 | print 'processing', uttId 73 | nat = getNatVecSeq(uttId) 74 | synth = getSynthVecSeq(uttId) 75 | # ignore 0th cepstral component 76 | nat = nat[:, 1:] 77 | synth = synth[:, 1:] 78 | 79 | minCost, path = dtw.dtw(nat, synth, costFn) 80 | frames = len(nat) 81 | 82 | minCostTot += minCost 83 | framesTot += frames 84 | 85 | print 'overall MCD = %f (%d frames)' % (minCostTot / framesTot, framesTot) 86 | 87 | if __name__ == '__main__': 88 | main(sys.argv) 89 | -------------------------------------------------------------------------------- /bin/get_mcd_plain: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -u 2 | 3 | """Computes the MCD metric for two sequences of mel cepstra.""" 4 | 5 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 6 | 7 | # This file is part of mcd. 8 | # See `License` for details of license and warranty. 9 | 10 | import os 11 | import sys 12 | import argparse 13 | import re 14 | import math 15 | import numpy as np 16 | 17 | from htk_io.base import DirReader 18 | import htk_io.alignment as alio 19 | import htk_io.vecseq as vsio 20 | 21 | from mcd import util 22 | import mcd.metrics_fast as mt 23 | 24 | def main(rawArgs): 25 | parser = argparse.ArgumentParser( 26 | description=( 27 | 'Computes the MCD metric for two sequences of mel cepstra.' 28 | ' Mel cepstral distortion (MCD) is a measure of the difference' 29 | ' between two sequences of mel cepstra.' 30 | ' This utility computes the MCD between two sequences of equal' 31 | ' length that are assumed to already be "aligned" in terms of' 32 | ' their timing.' 33 | ' Optionally certain segments (e.g. silence) can be omitted from' 34 | ' the calculation.' 35 | ), 36 | formatter_class=argparse.ArgumentDefaultsHelpFormatter 37 | ) 38 | parser.add_argument( 39 | '--ext', dest='ext', default='mgc', metavar='EXT', 40 | help=( 41 | 'file extension added to uttId to get file containing speech' 42 | ' parameters' 43 | ) 44 | ) 45 | parser.add_argument( 46 | '--param_order', dest='paramOrder', default=40, type=int, 47 | metavar='ORDER', 48 | help='parameter order of the cepstral files' 49 | ) 50 | parser.add_argument( 51 | '--remove_segments', dest='removeSegments', default=None, 52 | metavar='LABELREGEX', 53 | help='regex of segment labels to remove' 54 | ) 55 | parser.add_argument( 56 | '--alignment_dir', dest='alignmentDir', default=None, 57 | metavar='ALIGNMENTDIR', 58 | help=( 59 | 'directory containing phone-level alignment files (used for' 60 | ' segment removal)' 61 | ) 62 | ) 63 | parser.add_argument( 64 | '--frame_period', dest='framePeriod', default=0.005, type=float, 65 | metavar='FRAMEPERIOD', 66 | help='frame period in seconds (used for segment removal)' 67 | ) 68 | parser.add_argument( 69 | dest='natDir', metavar='NATDIR', 70 | help='directory containing natural speech parameters' 71 | ) 72 | parser.add_argument( 73 | dest='synthDir', metavar='SYNTHDIR', 74 | help='directory containing synthetic speech parameters' 75 | ) 76 | parser.add_argument( 77 | dest='uttIds', metavar='UTTID', nargs='+', 78 | help='utterance ids (ext will be appended to these)' 79 | ) 80 | args = parser.parse_args(rawArgs[1:]) 81 | assert (args.removeSegments is None) == (args.alignmentDir is None) 82 | if args.removeSegments is not None: 83 | print ('NOTE: removing segments matching regex \'%s\' using alignments' 84 | ' in %s' % (args.removeSegments, args.alignmentDir)) 85 | reRemoveSegments = (None if args.removeSegments is None 86 | else re.compile(args.removeSegments)) 87 | 88 | costFn = mt.logSpecDbDist 89 | 90 | alignmentIo = alio.AlignmentIo(args.framePeriod) 91 | getAlignment = DirReader(alignmentIo, args.alignmentDir, 'lab') 92 | 93 | vecSeqIo = vsio.VecSeqIo(args.paramOrder) 94 | getNatVecSeq = DirReader(vecSeqIo, args.natDir, args.ext) 95 | getSynthVecSeq = DirReader(vecSeqIo, args.synthDir, args.ext) 96 | 97 | costTot = 0.0 98 | framesTot = 0 99 | for uttId in args.uttIds: 100 | print 'processing', uttId 101 | nat = getNatVecSeq(uttId) 102 | synth = getSynthVecSeq(uttId) 103 | # ignore 0th cepstral component 104 | nat = nat[:, 1:] 105 | synth = synth[:, 1:] 106 | 107 | assert len(nat) == len(synth) 108 | 109 | if reRemoveSegments is None: 110 | cost = sum([ 111 | costFn(natFrame, synthFrame) 112 | for natFrame, synthFrame in zip(nat, synth) 113 | ]) 114 | frames = len(nat) 115 | else: 116 | alignment = getAlignment(uttId) 117 | alignmentInclude = [ 118 | (startTime, endTime, not reRemoveSegments.search(label)) 119 | for startTime, endTime, label, _ in alignment 120 | ] 121 | includeFrames = list(util.expandAlignment(alignmentInclude)) 122 | assert len(includeFrames) == len(nat) 123 | costs = [ 124 | costFn(natFrame, synthFrame) 125 | for natFrame, synthFrame, includeFrame in zip(nat, synth, 126 | includeFrames) 127 | if includeFrame 128 | ] 129 | cost = sum(costs) 130 | frames = len(costs) 131 | 132 | costTot += cost 133 | framesTot += frames 134 | 135 | print 'overall MCD = %f (%d frames)' % (costTot / framesTot, framesTot) 136 | 137 | if __name__ == '__main__': 138 | main(sys.argv) 139 | -------------------------------------------------------------------------------- /bin/test_cli.py: -------------------------------------------------------------------------------- 1 | """Unit tests for command-line tools. 2 | 3 | Many of these tests take the form of characterization tests which verify that 4 | the behaviour does not change but not that it is correct. 5 | """ 6 | 7 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 8 | 9 | # This file is part of mcd. 10 | # See `License` for details of license and warranty. 11 | 12 | import unittest 13 | import os 14 | from os.path import join 15 | import sys 16 | import logging 17 | import subprocess 18 | from subprocess import PIPE 19 | import shutil 20 | import tempfile 21 | from filecmp import cmpfiles 22 | 23 | # (FIXME : bit of a hacky way to find base dir) 24 | import mcd as mcd_temp 25 | baseDir = os.path.dirname(os.path.dirname(mcd_temp.__file__)) 26 | print '(using baseDir %s)' % baseDir 27 | 28 | class TempDir(object): 29 | def __init__(self, prefix='mcd.', removeOnException=False): 30 | self.prefix = prefix 31 | self.removeOnException = removeOnException 32 | 33 | def __enter__(self): 34 | self.location = tempfile.mkdtemp(prefix=self.prefix) 35 | return self 36 | 37 | def remove(self): 38 | shutil.rmtree(self.location) 39 | 40 | def __exit__(self, exc_type, exc_value, traceback): 41 | if exc_type is None or self.removeOnException: 42 | self.remove() 43 | if os.path.isdir(self.location): 44 | logging.warning('temporary directory %s not deleted. You probably' 45 | ' want to do this manually after looking at its' 46 | ' contents.' % self.location) 47 | 48 | def readUttIds(uttIdsFile): 49 | return [ line.strip() for line in open(uttIdsFile) ] 50 | 51 | # FIXME : replace exact equality with allclose in lots of the tests below? 52 | 53 | class TestCliTools(unittest.TestCase): 54 | def test_dtw_synth(self): 55 | """Simple characterization test for dtw_synth.""" 56 | uttIds = readUttIds(join(baseDir, 'test_data', 'corpus.lst')) 57 | with TempDir() as tempDir: 58 | synthOutDir = tempDir.location 59 | p = subprocess.Popen([ 60 | sys.executable, 61 | join(baseDir, 'bin', 'dtw_synth'), 62 | '--exts', 'mgc,lf0,bap', 63 | '--param_orders', '40,1,5', 64 | join(baseDir, 'test_data', 'ref-examples'), 65 | join(baseDir, 'test_data', 'synth-examples'), 66 | synthOutDir, 67 | ] + uttIds, stdout=PIPE, stderr=PIPE) 68 | stdout, stderr = p.communicate() 69 | stdoutGood = ( 70 | 'processing cmu_us_arctic_slt_a0003\n' 71 | 'MCD = 6.175330 (641 frames)\n' 72 | 'warping 683 frames -> 641 frames (29 repeated, 71 dropped)\n' 73 | '\n' 74 | 'processing cmu_us_arctic_slt_a0044\n' 75 | 'MCD = 5.577534 (613 frames)\n' 76 | 'warping 653 frames -> 613 frames (35 repeated, 75 dropped)\n' 77 | '\n' 78 | 'overall MCD = 5.883106 (1254 frames)\n' 79 | ) 80 | self.assertEqual(stderr, '') 81 | self.assertEqual(stdout, stdoutGood) 82 | synthOutDirGood = join(baseDir, 'test_data', 'out-dtw_synth') 83 | filenames = [ '%s.mgc' % uttId for uttId in uttIds ] 84 | match, mismatch, errors = cmpfiles(synthOutDir, synthOutDirGood, 85 | filenames, shallow = False) 86 | self.assertEqual(match, filenames) 87 | self.assertFalse(mismatch) 88 | self.assertFalse(errors) 89 | 90 | def test_get_mcd_dtw(self): 91 | """Simple characterization test for get_mcd_dtw.""" 92 | uttIds = readUttIds(join(baseDir, 'test_data', 'corpus.lst')) 93 | p = subprocess.Popen([ 94 | sys.executable, 95 | join(baseDir, 'bin', 'get_mcd_dtw'), 96 | '--ext', 'mgc', 97 | '--param_order', '40', 98 | join(baseDir, 'test_data', 'ref-examples'), 99 | join(baseDir, 'test_data', 'synth-examples'), 100 | ] + uttIds, stdout=PIPE, stderr=PIPE) 101 | stdout, stderr = p.communicate() 102 | stdoutGood = ( 103 | 'processing cmu_us_arctic_slt_a0003\n' 104 | 'processing cmu_us_arctic_slt_a0044\n' 105 | 'overall MCD = 5.883106 (1254 frames)\n' 106 | ) 107 | self.assertEqual(stderr, '') 108 | self.assertEqual(stdout, stdoutGood) 109 | 110 | def test_get_mcd_plain(self): 111 | """Simple characterization test for get_mcd_plain.""" 112 | uttIds = readUttIds(join(baseDir, 'test_data', 'corpus.lst')) 113 | p = subprocess.Popen([ 114 | sys.executable, 115 | join(baseDir, 'bin', 'get_mcd_plain'), 116 | '--ext', 'mgc', 117 | '--param_order', '40', 118 | join(baseDir, 'test_data', 'ref-examples'), 119 | join(baseDir, 'test_data', 'aligned-synth-examples'), 120 | ] + uttIds, stdout=PIPE, stderr=PIPE) 121 | stdout, stderr = p.communicate() 122 | stdoutGood = ( 123 | 'processing cmu_us_arctic_slt_a0003\n' 124 | 'processing cmu_us_arctic_slt_a0044\n' 125 | 'overall MCD = 5.308880 (1254 frames)\n' 126 | ) 127 | self.assertEqual(stderr, '') 128 | self.assertEqual(stdout, stdoutGood) 129 | 130 | def test_get_mcd_plain_exc_pau(self): 131 | """Simple characterization test for get_mcd_plain excluding pau.""" 132 | uttIds = readUttIds(join(baseDir, 'test_data', 'corpus.lst')) 133 | alignmentDir = join( 134 | baseDir, 'test_data', 'aligned-synth-examples', 'alignment' 135 | ) 136 | p = subprocess.Popen([ 137 | sys.executable, 138 | join(baseDir, 'bin', 'get_mcd_plain'), 139 | '--ext', 'mgc', 140 | '--param_order', '40', 141 | '--remove_segments', '.-pau\+', 142 | '--alignment_dir', alignmentDir, 143 | '--frame_period', '0.005', 144 | join(baseDir, 'test_data', 'ref-examples'), 145 | join(baseDir, 'test_data', 'aligned-synth-examples'), 146 | ] + uttIds, stdout=PIPE, stderr=PIPE) 147 | stdout, stderr = p.communicate() 148 | stdoutGood = ( 149 | 'NOTE: removing segments matching regex \'.-pau\+\' using' 150 | ' alignments in %s\n' 151 | 'processing cmu_us_arctic_slt_a0003\n' 152 | 'processing cmu_us_arctic_slt_a0044\n' 153 | 'overall MCD = 5.389857 (1157 frames)\n' 154 | ) % alignmentDir 155 | self.assertEqual(stderr, '') 156 | self.assertEqual(stdout, stdoutGood) 157 | 158 | if __name__ == '__main__': 159 | unittest.main() 160 | -------------------------------------------------------------------------------- /boring.darcs: -------------------------------------------------------------------------------- 1 | \.pyc$ 2 | ^build($|/) 3 | ^dist($|/) 4 | \.c$ 5 | \.so$ 6 | ^MANIFEST$ 7 | ^env($|/) 8 | -------------------------------------------------------------------------------- /dev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/dev -------------------------------------------------------------------------------- /example_usage: -------------------------------------------------------------------------------- 1 | 2 | # (set-up path; only necessary if package is not installed) 3 | export PYTHONPATH=. 4 | 5 | # a basic MCD computation (no warping) 6 | cat test_data/corpus.lst | xargs bin/get_mcd_plain test_data/ref-examples test_data/aligned-synth-examples 7 | 8 | # similar to above but excluding segments marked as silence 9 | cat test_data/corpus.lst | xargs bin/get_mcd_plain --remove_segments='.-pau\+' --alignment_dir=test_data/aligned-synth-examples/alignment test_data/ref-examples test_data/aligned-synth-examples 10 | 11 | # an MCD DTW computation (computes the minimum MCD over all valid alignments) 12 | cat test_data/corpus.lst | xargs bin/get_mcd_dtw test_data/ref-examples test_data/synth-examples 13 | 14 | # warp synthesized speech to have similar timing to the reference 15 | mkdir out 16 | cat test_data/corpus.lst | xargs bin/dtw_synth test_data/ref-examples test_data/synth-examples out 17 | 18 | -------------------------------------------------------------------------------- /mcd/__init__.py: -------------------------------------------------------------------------------- 1 | """Mel cepstral distortion (MCD) computations in python.""" 2 | 3 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 4 | 5 | # This file is part of mcd. 6 | # See `License` for details of license and warranty. 7 | 8 | __version__ = '0.5.dev1' 9 | -------------------------------------------------------------------------------- /mcd/dtw.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | import numpy as np 8 | import itertools as it 9 | 10 | def getCostMatrix(xs, ys, costFn): 11 | assert len(xs) > 0 and len(ys) > 0 12 | 13 | costMat = np.array([ [ costFn(x, y) for y in ys ] for x in xs ]) 14 | assert np.shape(costMat) == (len(xs), len(ys)) 15 | return costMat 16 | 17 | def getCumCostMatrix(costMat): 18 | xSize, ySize = np.shape(costMat) 19 | 20 | cumMat = np.zeros((xSize + 1, ySize + 1)) 21 | cumMat[0, 0] = 0.0 22 | cumMat[0, 1:] = float('inf') 23 | cumMat[1:, 0] = float('inf') 24 | for i in range(xSize): 25 | for j in range(ySize): 26 | cumMat[i + 1, j + 1] = min( 27 | cumMat[i, j], 28 | cumMat[i, j + 1], 29 | cumMat[i + 1, j] 30 | ) 31 | cumMat[i + 1, j + 1] += costMat[i, j] 32 | 33 | return cumMat 34 | 35 | def getBestPath(cumMat): 36 | xSize = np.shape(cumMat)[0] - 1 37 | ySize = np.shape(cumMat)[1] - 1 38 | assert xSize > 0 and ySize > 0 39 | 40 | i, j = xSize - 1, ySize - 1 41 | path = [(i, j)] 42 | while (i, j) != (0, 0): 43 | _, (i, j) = min( 44 | (cumMat[i, j], (i - 1, j - 1)), 45 | (cumMat[i, j + 1], (i - 1, j)), 46 | (cumMat[i + 1, j], (i, j - 1)) 47 | ) 48 | path.append((i, j)) 49 | path.reverse() 50 | 51 | return path 52 | 53 | def dtw(xs, ys, costFn): 54 | """Computes an alignment of minimum cost using dynamic time warping. 55 | 56 | A path is a sequence of (x-index, y-index) pairs corresponding to a pairing 57 | of frames in xs to frames in ys. 58 | The cost of a path is the sum of costFn applied to (x[i], y[j]) for each 59 | point (i, j) in the path. 60 | A path is valid if it is: 61 | - contiguous: neighbouring points on the path are never more than 1 62 | apart in either x-index or y-index 63 | - monotone: non-decreasing x-index as we move along the path, and 64 | similarly for y-index 65 | - complete: pairs the first frame of xs to the first frame of ys (i.e. 66 | it starts at (0, 0)) and pairs the last frame of xs to the last frame 67 | of ys 68 | Contiguous and monotone amount to saying that the following changes in 69 | (x-index, y-index) are allowed: (+0, +1), (+1, +0), (+1, +1). 70 | This function computes the minimum cost a valid path can have. 71 | 72 | Returns the minimum cost and a corresponding path. 73 | If there is more than one optimal path then one is chosen arbitrarily. 74 | """ 75 | costMat = getCostMatrix(xs, ys, costFn) 76 | cumMat = getCumCostMatrix(costMat) 77 | minCost = cumMat[len(xs), len(ys)] 78 | path = getBestPath(cumMat) 79 | return minCost, path 80 | 81 | def isValidPath(path): 82 | if not path: 83 | return False 84 | if path[0] != (0, 0): 85 | return False 86 | allowedDelta = [(1, 0), (0, 1), (1, 1)] 87 | for (iPrev, jPrev), (i, j) in zip(path, path[1:]): 88 | if (i - iPrev, j - jPrev) not in allowedDelta: 89 | return False 90 | return True 91 | 92 | def swapPath(path): 93 | return [ (j, i) for i, j in path ] 94 | 95 | def projectPathAll(path): 96 | """Projects a path on to a sequence of sequences of y-indices. 97 | 98 | The resulting sequence has one element for each x-index in the path, and 99 | each element is the sequence of y-indices which are paired with the x-index 100 | in the binary relation specified by path. 101 | """ 102 | yIndicesSeq = [] 103 | for i, subPath in it.groupby(path, lambda iAndJ: iAndJ[0]): 104 | assert i == len(yIndicesSeq) 105 | js = [ j for _, j in subPath ] 106 | yIndicesSeq.append(js) 107 | return yIndicesSeq 108 | 109 | def projectPathMinIndex(path): 110 | """Projects path on to a sequence of y-indices, one for each x-index. 111 | 112 | Where the path has more than one y-index paired to a given x-index, the 113 | smallest such y-index is used. 114 | """ 115 | yIndexSeq = [ min(js) for js in projectPathAll(path) ] 116 | return yIndexSeq 117 | 118 | def projectPathBestCost(path, pathCosts): 119 | """Projects path on to a sequence of y-indices, one for each x-index. 120 | 121 | Where the path has more than one y-index paired to a given x-index, the 122 | y-index with smallest cost is used. 123 | """ 124 | assert len(pathCosts) == len(path) 125 | 126 | # (FIXME : slight abuse of projectPathMinIndex) 127 | costedYIndexSeq = projectPathMinIndex([ 128 | (i, (cost, j)) 129 | for (i, j), cost in zip(path, pathCosts) 130 | ]) 131 | yIndexSeq = [ j for _, j in costedYIndexSeq ] 132 | return yIndexSeq 133 | 134 | def findWarpingMinIndex(xs, ys, costFn): 135 | """Finds a warping of ys with same length as xs using dynamic time warping. 136 | 137 | Where the optimal path has more than one y-index paired to a given x-index, 138 | the smallest such y-index is used. 139 | """ 140 | _, path = dtw(xs, ys, costFn) 141 | yIndexSeq = projectPathMinIndex(path) 142 | assert len(yIndexSeq) == len(xs) 143 | return yIndexSeq 144 | 145 | def findWarpingBestCost(xs, ys, costFn): 146 | """Finds a warping of ys with same length as xs using dynamic time warping. 147 | 148 | Where the optimal path has more than one y-index paired to a given x-index, 149 | the y-index with smallest cost is used. 150 | """ 151 | _, path = dtw(xs, ys, costFn) 152 | pathCosts = [ costFn(xs[i], ys[j]) for i, j in path ] 153 | yIndexSeq = projectPathBestCost(path, pathCosts) 154 | assert len(yIndexSeq) == len(xs) 155 | return yIndexSeq 156 | 157 | def warpGeneral(ys, yIndexSeq): 158 | """Warps ys using yIndexSeq.""" 159 | if isinstance(ys, np.ndarray): 160 | ysWarped = ys[yIndexSeq] 161 | else: 162 | ysWarped = [ ys[j] for j in yIndexSeq ] 163 | assert len(ysWarped) == len(yIndexSeq) 164 | return ysWarped 165 | -------------------------------------------------------------------------------- /mcd/metrics.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | import math 8 | import numpy as np 9 | 10 | def sqCepDist(x, y): 11 | diff = x - y 12 | return np.inner(diff, diff) 13 | 14 | def eucCepDist(x, y): 15 | diff = x - y 16 | return math.sqrt(np.inner(diff, diff)) 17 | 18 | logSpecDbConst = 10.0 / math.log(10.0) * math.sqrt(2.0) 19 | def logSpecDbDist(x, y): 20 | diff = x - y 21 | return logSpecDbConst * math.sqrt(np.inner(diff, diff)) 22 | -------------------------------------------------------------------------------- /mcd/metrics_fast.pyx: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | 8 | import math 9 | import numpy as np 10 | 11 | from libc.math cimport log, sqrt 12 | cimport numpy as cnp 13 | cimport cython 14 | 15 | cnp.import_array() 16 | cnp.import_ufunc() 17 | 18 | @cython.boundscheck(False) 19 | def sqCepDist(cnp.ndarray[cnp.float64_t, ndim=1] x, 20 | cnp.ndarray[cnp.float64_t, ndim=1] y): 21 | cdef unsigned int k, size 22 | cdef double diff, sumSqDiff 23 | 24 | size = x.shape[0] 25 | assert y.shape[0] == size 26 | 27 | sumSqDiff = 0.0 28 | for k in range(size): 29 | diff = x[k] - y[k] 30 | sumSqDiff += diff * diff 31 | 32 | return sumSqDiff 33 | 34 | @cython.boundscheck(False) 35 | def eucCepDist(cnp.ndarray[cnp.float64_t, ndim=1] x, 36 | cnp.ndarray[cnp.float64_t, ndim=1] y): 37 | cdef unsigned int k, size 38 | cdef double diff, sumSqDiff, dist 39 | 40 | size = x.shape[0] 41 | assert y.shape[0] == size 42 | 43 | sumSqDiff = 0.0 44 | for k in range(size): 45 | diff = x[k] - y[k] 46 | sumSqDiff += diff * diff 47 | 48 | dist = sqrt(sumSqDiff) 49 | return dist 50 | 51 | cdef double logSpecDbConst = 10.0 / log(10.0) * sqrt(2.0) 52 | 53 | @cython.boundscheck(False) 54 | def logSpecDbDist(cnp.ndarray[cnp.float64_t, ndim=1] x, 55 | cnp.ndarray[cnp.float64_t, ndim=1] y): 56 | cdef unsigned int k, size 57 | cdef double diff, sumSqDiff, dist 58 | 59 | size = x.shape[0] 60 | assert y.shape[0] == size 61 | 62 | sumSqDiff = 0.0 63 | for k in range(size): 64 | diff = x[k] - y[k] 65 | sumSqDiff += diff * diff 66 | 67 | dist = sqrt(sumSqDiff) * logSpecDbConst 68 | return dist 69 | -------------------------------------------------------------------------------- /mcd/test_dtw.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | import unittest 8 | import math 9 | import numpy as np 10 | import random 11 | from numpy.random import randn, randint 12 | 13 | from mcd import dtw 14 | from mcd.util import assert_allclose 15 | 16 | def randBool(): 17 | return randint(0, 2) == 0 18 | 19 | def randSeq(dim, minLength=0, ensureShort=False): 20 | length = (randint(minLength, 4) if ensureShort or randBool() 21 | else randint(minLength, 100)) 22 | xs = randn(length, dim) 23 | return xs 24 | 25 | def getPathCost(path, xs, ys, costFn): 26 | return sum([ costFn(xs[i], ys[j]) for i, j in path ]) 27 | 28 | def sqCost(x, y): 29 | return np.inner(x - y, x - y) 30 | def eucCost(x, y): 31 | return math.sqrt(np.inner(x - y, x - y)) 32 | 33 | def getDagPathIterator(childrenDict, startNode): 34 | """Returns an iterator over full paths through a DAG starting at a node. 35 | 36 | Here DAG stands for directed acyclic graph. 37 | A full path is a path for which the last node has no children. 38 | """ 39 | def isLastChild(node, childIndex): 40 | return childIndex == len(childrenDict[node]) - 1 41 | 42 | nodeSeq = [startNode] 43 | childIndexSeq = [] 44 | while True: 45 | if childrenDict[nodeSeq[-1]]: 46 | nodeSeq.append(childrenDict[nodeSeq[-1]][0]) 47 | childIndexSeq.append(0) 48 | else: 49 | yield list(nodeSeq), list(childIndexSeq) 50 | 51 | while (childIndexSeq and 52 | isLastChild(nodeSeq[-2], childIndexSeq[-1])): 53 | nodeSeq.pop() 54 | childIndexSeq.pop() 55 | if not childIndexSeq: 56 | return 57 | else: 58 | childIndex = childIndexSeq[-1] + 1 59 | nodeSeq[-1] = childrenDict[nodeSeq[-2]][childIndex] 60 | childIndexSeq[-1] = childIndex 61 | 62 | def getRandomDagPath(childrenDict, startNode): 63 | """Returns a random full path through a directed acyclic graph. 64 | 65 | A full path is a path for which the last node has no children. 66 | N.B. the distribution used is *not* the uniform distribution over full 67 | paths. 68 | """ 69 | nodeSeq = [startNode] 70 | while childrenDict[nodeSeq[-1]]: 71 | nodeSeq.append(random.choice(childrenDict[nodeSeq[-1]])) 72 | 73 | return nodeSeq 74 | 75 | def getDtwDag(xSize, ySize): 76 | """Returns a DTW-style directed acyclic graph.""" 77 | def isValid(node): 78 | i, j = node 79 | return 0 <= i < xSize and 0 <= j < ySize 80 | 81 | def getChildren(node): 82 | i, j = node 83 | possChildren = [(i + 1, j), (i + 1, j + 1), (i, j + 1)] 84 | children = filter(isValid, possChildren) 85 | return children 86 | 87 | childrenDict = dict() 88 | for i in range(xSize): 89 | for j in range(ySize): 90 | node = (i, j) 91 | childrenDict[node] = getChildren(node) 92 | 93 | startNode = (0, 0) 94 | assert isValid(startNode) 95 | 96 | return childrenDict, startNode 97 | 98 | class TestDtw(unittest.TestCase): 99 | def test_empty_seq_raises_exception(self): 100 | self.assertRaises(AssertionError, dtw.dtw, [], [], eucCost) 101 | self.assertRaises(AssertionError, dtw.dtw, [], [0.0], eucCost) 102 | self.assertRaises(AssertionError, dtw.dtw, [0.0], [], eucCost) 103 | 104 | def test_length_one_seq(self, numPairs=100): 105 | for pair in range(numPairs): 106 | x = randn() 107 | y = randn() 108 | minCost, path = dtw.dtw([x], [y], eucCost) 109 | assert_allclose(minCost, abs(x - y)) 110 | assert path == [(0, 0)] 111 | 112 | def test_one_length_one_seq(self, numPairs=100): 113 | for pair in range(numPairs): 114 | xs = randn(randint(1, 10)) 115 | y = randn() 116 | minCost, path = dtw.dtw(xs, [y], eucCost) 117 | assert_allclose(minCost, sum([ abs(x - y) for x in xs])) 118 | assert path == [ (i, 0) for i in range(len(xs)) ] 119 | 120 | def test_brute_force_small(self, numPairs=100): 121 | for pair in range(numPairs): 122 | dim = randint(0, 3) if randBool() else randint(0, 10) 123 | xs = randSeq(dim=dim, minLength=1, ensureShort=True) 124 | ys = randSeq(dim=dim, minLength=1, ensureShort=True) 125 | 126 | childrenDict, startNode = getDtwDag(len(xs), len(ys)) 127 | minCostGood = min([ 128 | getPathCost(path, xs, ys, eucCost) 129 | for path, _ in getDagPathIterator(childrenDict, startNode) 130 | ]) 131 | 132 | minCost, _ = dtw.dtw(xs, ys, eucCost) 133 | assert_allclose(minCost, minCostGood) 134 | 135 | def test_universal_properties(self, numPairs=100, numPathsPerPair=20): 136 | for pair in range(numPairs): 137 | dim = randint(0, 3) if randBool() else randint(0, 10) 138 | xs = randSeq(dim=dim, minLength=1) 139 | ys = randSeq(dim=dim, minLength=1) 140 | minCost, path = dtw.dtw(xs, ys, eucCost) 141 | 142 | # test cost along path agrees with minimum cost 143 | assert_allclose(minCost, getPathCost(path, xs, ys, eucCost)) 144 | 145 | # test transpose 146 | minCost2, path2 = dtw.dtw(ys, xs, eucCost) 147 | assert_allclose(minCost2, minCost) 148 | # N.B. this is not a universal property but will almost always be 149 | # true for the random sequences of floats that we generate. 150 | assert path2 == dtw.swapPath(path) 151 | 152 | # test path is a valid path 153 | assert dtw.isValidPath(path) 154 | assert path[-1] == (len(xs) - 1, len(ys) - 1) 155 | 156 | # test optimal subpaths property 157 | cutIndex = randint(len(path)) 158 | iCut, jCut = path[cutIndex] 159 | pathA = path[:(cutIndex + 1)] 160 | pathB = path[cutIndex:] 161 | costA = getPathCost(pathA, xs, ys, eucCost) 162 | costB = getPathCost(pathB, xs, ys, eucCost) 163 | minCostA, _ = dtw.dtw(xs[:(iCut + 1)], ys[:(jCut + 1)], eucCost) 164 | minCostB, _ = dtw.dtw(xs[iCut:], ys[jCut:], eucCost) 165 | assert_allclose(costA, minCostA) 166 | assert_allclose(costB, minCostB) 167 | 168 | # test minCost <= cost for several randomly generated paths 169 | childrenDict, startNode = getDtwDag(len(xs), len(ys)) 170 | for _ in range(numPathsPerPair): 171 | path = getRandomDagPath(childrenDict, startNode) 172 | cost = getPathCost(path, xs, ys, eucCost) 173 | assert minCost <= cost or np.allclose(minCost, cost) 174 | 175 | # minCost to itself should be zero 176 | assert dtw.dtw(xs, xs, eucCost)[0] == 0.0 177 | 178 | def test_projectPathAll(self, numPaths=100): 179 | for _ in range(numPaths): 180 | path = [] 181 | for i in range(randint(1, 6)): 182 | for _ in range(randint(1, 4)): 183 | path.append((i, randint(20))) 184 | 185 | yIndicesSeq = dtw.projectPathAll(path) 186 | 187 | pathAgain = [ 188 | (i, j) 189 | for i, yIndices in enumerate(yIndicesSeq) 190 | for j in yIndices 191 | ] 192 | assert pathAgain == path 193 | 194 | def test_projectPathBestCost(self, numPaths=100): 195 | for _ in range(numPaths): 196 | childrenDict, startNode = getDtwDag(randint(1, 10), randint(1, 10)) 197 | path = getRandomDagPath(childrenDict, startNode) 198 | pathCosts = randn(len(path)) 199 | 200 | yIndexSeq = dtw.projectPathBestCost(path, pathCosts) 201 | 202 | # (FIXME : code below is not very transparent) 203 | yIndicesSeq = dtw.projectPathAll(path) 204 | assert len(yIndexSeq) == len(yIndicesSeq) 205 | costsSeq = dtw.projectPathAll([ 206 | (i, cost) 207 | for (i, j), cost in zip(path, pathCosts) 208 | ]) 209 | assert len(costsSeq) == len(yIndicesSeq) 210 | for j, js, costs in zip(yIndexSeq, yIndicesSeq, costsSeq): 211 | minCost = min(costs) 212 | assert j in [ 213 | j2 214 | for j2, cost in zip(js, costs) 215 | if cost == minCost 216 | ] 217 | 218 | if __name__ == '__main__': 219 | unittest.main() 220 | -------------------------------------------------------------------------------- /mcd/test_metrics.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | import unittest 8 | import math 9 | import numpy as np 10 | import random 11 | from numpy.random import randn, randint 12 | 13 | import mcd.metrics as mt 14 | import mcd.metrics_fast as mtf 15 | from mcd.util import assert_allclose 16 | 17 | def randBool(): 18 | return randint(0, 2) == 0 19 | 20 | class TestMetrics(unittest.TestCase): 21 | def test_sqCepDist(self, numPoints=100): 22 | # (FIXME : not a proper unit test: doesn't really check correctness) 23 | for _ in range(numPoints): 24 | size = random.choice([0, 1, randint(0, 10), randint(0, 100)]) 25 | x = randn(size) 26 | y = randn(size) 27 | 28 | # check fast and slow versions agree 29 | assert_allclose(mtf.sqCepDist(x, y), mt.sqCepDist(x, y)) 30 | 31 | # check both versions raise an error where appropriate 32 | y = randn(size + 1) 33 | if size > 1: 34 | self.assertRaises(ValueError, mt.sqCepDist, x, y) 35 | self.assertRaises(AssertionError, mtf.sqCepDist, x, y) 36 | 37 | def test_eucCepDist(self, numPoints=100): 38 | # (FIXME : not a proper unit test: doesn't really check correctness) 39 | for _ in range(numPoints): 40 | size = random.choice([0, 1, randint(0, 10), randint(0, 100)]) 41 | x = randn(size) 42 | y = randn(size) 43 | 44 | # check fast and slow versions agree 45 | assert_allclose(mtf.eucCepDist(x, y), mt.eucCepDist(x, y)) 46 | 47 | # check both versions raise an error where appropriate 48 | y = randn(size + 1) 49 | if size > 1: 50 | self.assertRaises(ValueError, mt.eucCepDist, x, y) 51 | self.assertRaises(AssertionError, mtf.eucCepDist, x, y) 52 | 53 | def test_logSpecDbDist(self, numPoints=100): 54 | # (FIXME : not a proper unit test: doesn't really check correctness) 55 | for _ in range(numPoints): 56 | size = random.choice([0, 1, randint(0, 10), randint(0, 100)]) 57 | x = randn(size) 58 | y = randn(size) 59 | 60 | # check fast and slow versions agree 61 | assert_allclose(mtf.logSpecDbDist(x, y), mt.logSpecDbDist(x, y)) 62 | 63 | # check both versions raise an error where appropriate 64 | y = randn(size + 1) 65 | if size > 1: 66 | self.assertRaises(ValueError, mt.logSpecDbDist, x, y) 67 | self.assertRaises(AssertionError, mtf.logSpecDbDist, x, y) 68 | 69 | if __name__ == '__main__': 70 | unittest.main() 71 | -------------------------------------------------------------------------------- /mcd/util.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 3 | 4 | # This file is part of mcd. 5 | # See `License` for details of license and warranty. 6 | 7 | import numpy as np 8 | 9 | def assert_allclose(actual, desired, rtol=1e-7, atol=1e-14, 10 | msg='items not almost equal'): 11 | if np.shape(actual) != np.shape(desired): 12 | raise AssertionError('%s (wrong shape)\n ACTUAL: %r\n DESIRED: %r' % 13 | (msg, actual, desired)) 14 | if not np.allclose(actual, desired, rtol, atol): 15 | absErr = np.abs(actual - desired) 16 | relErr = np.abs((actual - desired) / desired) 17 | raise AssertionError('%s\n ACTUAL: %r\n DESIRED: %r\n' 18 | ' ABS ERR: %r (max %s)\n REL ERR: %r (max %s)' % 19 | (msg, actual, desired, 20 | absErr, np.max(absErr), relErr, np.max(relErr))) 21 | 22 | def expandAlignment(alignment): 23 | checkedOverallStartTime = False 24 | endTimePrev = None 25 | for startTime, endTime, label in alignment: 26 | if not checkedOverallStartTime: 27 | assert startTime == 0 28 | checkedOverallStartTime = True 29 | assert endTimePrev is None or startTime == endTimePrev 30 | assert endTime >= startTime 31 | for i in range(endTime - startTime): 32 | yield label 33 | endTimePrev = endTime 34 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.6.1 2 | htk_io>=0.2 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """A setuptools-based script for distributing and installing mcd.""" 3 | 4 | # Copyright 2014, 2015, 2016, 2017 Matt Shannon 5 | 6 | # This file is part of mcd. 7 | # See `License` for details of license and warranty. 8 | 9 | import os 10 | import numpy as np 11 | from setuptools import setup 12 | from setuptools.extension import Extension 13 | from setuptools.command.sdist import sdist as _sdist 14 | 15 | cython_locs = [ 16 | ('mcd', 'metrics_fast'), 17 | ] 18 | 19 | with open('README.rst') as readme_file: 20 | long_description = readme_file.read() 21 | 22 | requires = [ line.rstrip('\n') for line in open('requirements.txt') ] 23 | 24 | # see "A note on setup.py" in README.rst for an explanation of the dev file 25 | dev_mode = os.path.exists('dev') 26 | 27 | if dev_mode: 28 | from Cython.Distutils import build_ext 29 | from Cython.Build import cythonize 30 | 31 | class sdist(_sdist): 32 | """A cythonizing sdist command. 33 | 34 | This class is a custom sdist command which ensures all cython-generated 35 | C files are up-to-date before running the conventional sdist command. 36 | """ 37 | def run(self): 38 | cythonize([ os.path.join(*loc)+'.pyx' for loc in cython_locs ]) 39 | _sdist.run(self) 40 | 41 | cmdclass = {'build_ext': build_ext, 'sdist': sdist} 42 | ext_modules = [ 43 | Extension('.'.join(loc), [os.path.join(*loc)+'.pyx'], 44 | extra_compile_args=['-Wno-unused-but-set-variable', '-O3'], 45 | include_dirs=[np.get_include()]) 46 | for loc in cython_locs 47 | ] 48 | else: 49 | cmdclass = {} 50 | ext_modules = [ 51 | Extension('.'.join(loc), [os.path.join(*loc)+'.c'], 52 | extra_compile_args=['-Wno-unused-but-set-variable', '-O3'], 53 | include_dirs=[np.get_include()]) 54 | for loc in cython_locs 55 | ] 56 | 57 | setup( 58 | name='mcd', 59 | version='0.5.dev1', 60 | description='Mel cepstral distortion (MCD) computations in python.', 61 | url='http://github.com/MattShannon/mcd', 62 | author='Matt Shannon', 63 | author_email='matt.shannon@cantab.net', 64 | license='3-clause BSD (see License file)', 65 | packages=['mcd'], 66 | install_requires=requires, 67 | scripts=[ 68 | os.path.join('bin', 'dtw_synth'), 69 | os.path.join('bin', 'get_mcd_dtw'), 70 | os.path.join('bin', 'get_mcd_plain'), 71 | ], 72 | long_description=long_description, 73 | cmdclass=cmdclass, 74 | ext_modules=ext_modules, 75 | ) 76 | -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/alignment/cmu_us_arctic_slt_a0003.lab: -------------------------------------------------------------------------------- 1 | 0 1450000 x^x-pau+f=ao@x_x/A:0_0_0/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:1+0+3/D:0_0/E:x+x@x+x&x+x#x+x/F:in_1/G:0_0/H:x=x@1=2|0/I:9=6/J:14+11-2 2 | 1450000 2150000 x^pau-f+ao=r@1_3/A:0_0_0/B:1-0-3@1-1&1-9#1-5$1-3!0-2;0-2|ao/C:0+0+2/D:0_0/E:in+1@1+6&1+3#0+2/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 3 | 2150000 2550000 pau^f-ao+r=dh@2_2/A:0_0_0/B:1-0-3@1-1&1-9#1-5$1-3!0-2;0-2|ao/C:0+0+2/D:0_0/E:in+1@1+6&1+3#0+2/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 4 | 2550000 2800000 f^ao-r+dh=ax@3_1/A:0_0_0/B:1-0-3@1-1&1-9#1-5$1-3!0-2;0-2|ao/C:0+0+2/D:0_0/E:in+1@1+6&1+3#0+2/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 5 | 2800000 3200000 ao^r-dh+ax=t@1_2/A:1_0_3/B:0-0-2@1-1&2-8#1-5$1-3!1-1;0-1|ax/C:1+1+5/D:in_1/E:det+1@2+5&1+3#0+1/F:content_3/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 6 | 3200000 3600000 r^dh-ax+t=w@2_1/A:1_0_3/B:0-0-2@1-1&2-8#1-5$1-3!1-1;0-1|ax/C:1+1+5/D:in_1/E:det+1@2+5&1+3#0+1/F:content_3/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 7 | 3600000 5100000 dh^ax-t+w=eh@1_5/A:0_0_2/B:1-1-5@1-3&3-7#1-4$1-2!2-3;0-6|eh/C:0+0+1/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 8 | 5100000 5500000 ax^t-w+eh=n@2_4/A:0_0_2/B:1-1-5@1-3&3-7#1-4$1-2!2-3;0-6|eh/C:0+0+1/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 9 | 5500000 5800000 t^w-eh+n=t@3_3/A:0_0_2/B:1-1-5@1-3&3-7#1-4$1-2!2-3;0-6|eh/C:0+0+1/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 10 | 5800000 6050000 w^eh-n+t=iy@4_2/A:0_0_2/B:1-1-5@1-3&3-7#1-4$1-2!2-3;0-6|eh/C:0+0+1/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 11 | 6050000 6300000 eh^n-t+iy=ax@5_1/A:0_0_2/B:1-1-5@1-3&3-7#1-4$1-2!2-3;0-6|eh/C:0+0+1/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 12 | 6300000 6700000 n^t-iy+ax=th@1_1/A:1_1_5/B:0-0-1@2-2&4-6#2-4$2-2!1-2;1-5|iy/C:0+0+2/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 13 | 6700000 7200000 t^iy-ax+th=t@1_2/A:0_0_1/B:0-0-2@3-1&5-5#2-4$2-2!2-1;2-4|ax/C:1+0+3/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 14 | 7200000 8250000 iy^ax-th+t=ay@2_1/A:0_0_1/B:0-0-2@3-1&5-5#2-4$2-2!2-1;2-4|ax/C:1+0+3/D:det_1/E:content+3@3+4&1+2#0+1/F:content_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 15 | 8250000 9200000 ax^th-t+ay=m@1_3/A:0_0_2/B:1-0-3@1-1&6-4#2-3$2-2!3-1;3-3|ay/C:1+0+3/D:content_3/E:content+1@4+3&2+1#1+2/F:in_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 16 | 9200000 10800000 th^t-ay+m=dh@2_2/A:0_0_2/B:1-0-3@1-1&6-4#2-3$2-2!3-1;3-3|ay/C:1+0+3/D:content_3/E:content+1@4+3&2+1#1+2/F:in_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 17 | 10800000 11500000 t^ay-m+dh=ae@3_1/A:0_0_2/B:1-0-3@1-1&6-4#2-3$2-2!3-1;3-3|ay/C:1+0+3/D:content_3/E:content+1@4+3&2+1#1+2/F:in_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 18 | 11500000 11750000 ay^m-dh+ae=t@1_3/A:1_0_3/B:1-0-3@1-1&7-3#3-2$2-2!1-1;4-2|ae/C:1+0+2/D:content_1/E:in+1@5+2&3+1#1+1/F:content_2/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 19 | 11750000 12750000 m^dh-ae+t=iy@2_2/A:1_0_3/B:1-0-3@1-1&7-3#3-2$2-2!1-1;4-2|ae/C:1+0+2/D:content_1/E:in+1@5+2&3+1#1+1/F:content_2/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 20 | 12750000 13550000 dh^ae-t+iy=v@3_1/A:1_0_3/B:1-0-3@1-1&7-3#3-2$2-2!1-1;4-2|ae/C:1+0+2/D:content_1/E:in+1@5+2&3+1#1+1/F:content_2/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 21 | 13550000 14600000 ae^t-iy+v=n@1_2/A:1_0_3/B:1-0-2@1-2&8-2#4-1$2-2!1-0;5-1|iy/C:0+1+3/D:in_1/E:content+2@6+1&3+0#2+0/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 22 | 14600000 15100000 t^iy-v+n=ih@2_1/A:1_0_3/B:1-0-2@1-2&8-2#4-1$2-2!1-0;5-1|iy/C:0+1+3/D:in_1/E:content+2@6+1&3+0#2+0/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 23 | 15100000 15750000 iy^v-n+ih=ng@1_3/A:1_0_2/B:0-1-3@2-1&9-1#5-1$2-1!1-0;6-0|ih/C:0+0+2/D:in_1/E:content+2@6+1&3+0#2+0/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 24 | 15750000 16400000 v^n-ih+ng=dh@2_2/A:1_0_2/B:0-1-3@2-1&9-1#5-1$2-1!1-0;6-0|ih/C:0+0+2/D:in_1/E:content+2@6+1&3+0#2+0/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 25 | 16400000 17250000 n^ih-ng+dh=ax@3_1/A:1_0_2/B:0-1-3@2-1&9-1#5-1$2-1!1-0;6-0|ih/C:0+0+2/D:in_1/E:content+2@6+1&3+0#2+0/F:det_1/G:0_0/H:9=6@1=2|L-L%/I:5=5/J:14+11-2 26 | 17250000 17750000 ih^ng-dh+ax=t@1_2/A:0_1_3/B:0-0-2@1-1&1-5#1-5$1-4!0-1;0-1|ax/C:1+1+2/D:content_2/E:det+1@1+5&1+4#0+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 27 | 17750000 18150000 ng^dh-ax+t=uw@2_1/A:0_1_3/B:0-0-2@1-1&1-5#1-5$1-4!0-1;0-1|ax/C:1+1+2/D:content_2/E:det+1@1+5&1+4#0+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 28 | 18150000 19900000 dh^ax-t+uw=m@1_2/A:0_0_2/B:1-1-2@1-1&2-4#1-4$1-3!0-1;0-1|uw/C:1+1+3/D:det_1/E:content+1@2+4&1+3#0+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 29 | 19900000 20650000 ax^t-uw+m=eh@2_1/A:0_0_2/B:1-1-2@1-1&2-4#1-4$1-3!0-1;0-1|uw/C:1+1+3/D:det_1/E:content+1@2+4&1+3#0+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 30 | 20650000 21550000 t^uw-m+eh=n@1_3/A:1_1_2/B:1-1-3@1-1&3-3#2-3$2-2!1-1;1-2|eh/C:1+0+3/D:content_1/E:content+1@3+3&2+2#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 31 | 21550000 22700000 uw^m-eh+n=sh@2_2/A:1_1_2/B:1-1-3@1-1&3-3#2-3$2-2!1-1;1-2|eh/C:1+0+3/D:content_1/E:content+1@3+3&2+2#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 32 | 22700000 23450000 m^eh-n+sh=uh@3_1/A:1_1_2/B:1-1-3@1-1&3-3#2-3$2-2!1-1;1-2|eh/C:1+0+3/D:content_1/E:content+1@3+3&2+2#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 33 | 23450000 24800000 eh^n-sh+uh=k@1_3/A:1_1_3/B:1-0-3@1-1&4-2#3-2$3-2!1-1;1-1|uh/C:1+1+5/D:content_1/E:content+1@4+2&3+1#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 34 | 24800000 25500000 n^sh-uh+k=hh@2_2/A:1_1_3/B:1-0-3@1-1&4-2#3-2$3-2!1-1;1-1|uh/C:1+1+5/D:content_1/E:content+1@4+2&3+1#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 35 | 25500000 26500000 sh^uh-k+hh=ae@3_1/A:1_1_3/B:1-0-3@1-1&4-2#3-2$3-2!1-1;1-1|uh/C:1+1+5/D:content_1/E:content+1@4+2&3+1#1+1/F:content_1/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 36 | 26500000 26900000 uh^k-hh+ae=n@1_5/A:1_0_3/B:1-1-5@1-1&5-1#4-1$3-1!1-0;2-0|ae/C:0+0+0/D:content_1/E:content+1@5+1&4+0#1+0/F:0_0/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 37 | 26900000 28950000 k^hh-ae+n=d@2_4/A:1_0_3/B:1-1-5@1-1&5-1#4-1$3-1!1-0;2-0|ae/C:0+0+0/D:content_1/E:content+1@5+1&4+0#1+0/F:0_0/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 38 | 28950000 29800000 hh^ae-n+d=z@3_3/A:1_0_3/B:1-1-5@1-1&5-1#4-1$3-1!1-0;2-0|ae/C:0+0+0/D:content_1/E:content+1@5+1&4+0#1+0/F:0_0/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 39 | 29800000 30150000 ae^n-d+z=pau@4_2/A:1_0_3/B:1-1-5@1-1&5-1#4-1$3-1!1-0;2-0|ae/C:0+0+0/D:content_1/E:content+1@5+1&4+0#1+0/F:0_0/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 40 | 30150000 31250000 n^d-z+pau=x@5_1/A:1_0_3/B:1-1-5@1-1&5-1#4-1$3-1!1-0;2-0|ae/C:0+0+0/D:content_1/E:content+1@5+1&4+0#1+0/F:0_0/G:9_6/H:5=5@2=1|L-L%/I:0=0/J:14+11-2 41 | 31250000 32050000 d^z-pau+x=x@x_x/A:1_1_5/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:0+0+0/D:content_1/E:x+x@x+x&x+x#x+x/F:0_0/G:5_5/H:x=x@1=2|0/I:0=0/J:14+11-2 42 | -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/alignment/cmu_us_arctic_slt_a0044.lab: -------------------------------------------------------------------------------- 1 | 0 550000 x^x-pau+pau=hh@x_x/A:0_0_0/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:0+0+0/D:0_0/E:x+x@x+x&x+x#x+x/F:0_0/G:0_0/H:x=x@1=2|0/I:0=0/J:15+10-2 2 | 550000 1800000 x^pau-pau+hh=er@x_x/A:0_0_0/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:0+0+2/D:0_0/E:x+x@x+x&x+x#x+x/F:pps_1/G:0_0/H:x=x@1=2|0/I:8=5/J:15+10-2 3 | 1800000 2500000 pau^pau-hh+er=ow@1_2/A:0_0_0/B:0-0-2@1-1&1-8#1-5$1-4!0-1;0-1|er/C:1+1+2/D:0_0/E:pps+1@1+5&1+3#0+1/F:content_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 4 | 2500000 3700000 pau^hh-er+ow=n@2_1/A:0_0_0/B:0-0-2@1-1&1-8#1-5$1-4!0-1;0-1|er/C:1+1+2/D:0_0/E:pps+1@1+5&1+3#0+1/F:content_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 5 | 3700000 5350000 hh^er-ow+n=b@1_2/A:0_0_2/B:1-1-2@1-1&2-7#1-4$1-3!0-2;0-2|ow/C:0+0+3/D:pps_1/E:content+1@2+4&1+2#0+1/F:content_3/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 6 | 5350000 6100000 er^ow-n+b=ih@2_1/A:0_0_2/B:1-1-2@1-1&2-7#1-4$1-3!0-2;0-2|ow/C:0+0+3/D:pps_1/E:content+1@2+4&1+2#0+1/F:content_3/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 7 | 6100000 6700000 ow^n-b+ih=t@1_3/A:1_1_2/B:0-0-3@1-3&3-6#2-4$2-3!1-1;1-1|ih/C:1+1+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 8 | 6700000 7350000 n^b-ih+t=r@2_2/A:1_1_2/B:0-0-3@1-3&3-6#2-4$2-3!1-1;1-1|ih/C:1+1+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 9 | 7350000 8650000 b^ih-t+r=ey@3_1/A:1_1_2/B:0-0-3@1-3&3-6#2-4$2-3!1-1;1-1|ih/C:1+1+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 10 | 8650000 9250000 ih^t-r+ey=ax@1_2/A:0_0_3/B:1-1-2@2-2&4-5#2-3$2-2!2-2;2-4|ey/C:0+0+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 11 | 9250000 10250000 t^r-ey+ax=l@2_1/A:0_0_3/B:1-1-2@2-2&4-5#2-3$2-2!2-2;2-4|ey/C:0+0+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 12 | 10250000 10600000 r^ey-ax+l=ah@1_2/A:1_1_2/B:0-0-2@3-1&5-4#3-3$3-2!1-1;1-3|ax/C:1+0+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 13 | 10600000 11750000 ey^ax-l+ah=v@2_1/A:1_1_2/B:0-0-2@3-1&5-4#3-3$3-2!1-1;1-3|ax/C:1+0+2/D:content_1/E:content+3@3+3&2+1#1+2/F:in_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 14 | 11750000 12100000 ax^l-ah+v=hh@1_2/A:0_0_2/B:1-0-2@1-1&6-3#3-2$3-2!2-2;2-2|ah/C:0+0+3/D:content_3/E:in+1@4+2&3+1#1+1/F:content_2/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 15 | 12100000 12700000 l^ah-v+hh=er@2_1/A:0_0_2/B:1-0-2@1-1&6-3#3-2$3-2!2-2;2-2|ah/C:0+0+3/D:content_3/E:in+1@4+2&3+1#1+1/F:content_2/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 16 | 12700000 13150000 ah^v-hh+er=s@1_3/A:1_0_2/B:0-0-3@1-2&7-2#4-2$3-2!1-1;3-1|er/C:1+1+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 17 | 13150000 13700000 v^hh-er+s=eh@2_2/A:1_0_2/B:0-0-3@1-2&7-2#4-2$3-2!1-1;3-1|er/C:1+1+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 18 | 13700000 14800000 hh^er-s+eh=l@3_1/A:1_0_2/B:0-0-3@1-2&7-2#4-2$3-2!1-1;3-1|er/C:1+1+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 19 | 14800000 15500000 er^s-eh+l=f@1_3/A:0_0_3/B:1-1-3@2-1&8-1#4-1$3-1!2-0;4-0|eh/C:1+0+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 20 | 15500000 16450000 s^eh-l+f=w@2_2/A:0_0_3/B:1-1-3@2-1&8-1#4-1$3-1!2-0;4-0|eh/C:1+0+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 21 | 16450000 17250000 eh^l-f+w=aa@3_1/A:0_0_3/B:1-1-3@2-1&8-1#4-1$3-1!2-0;4-0|eh/C:1+0+3/D:in_1/E:content+2@5+1&3+0#2+0/F:aux_1/G:0_0/H:8=5@1=2|L-H%/I:7=5/J:15+10-2 22 | 17250000 17750000 l^f-w+aa=z@1_3/A:1_1_3/B:1-0-3@1-1&1-7#1-4$1-4!0-1;0-1|aa/C:1+1+3/D:content_2/E:aux+1@1+5&1+3#0+1/F:content_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 23 | 17750000 18000000 f^w-aa+z=l@2_2/A:1_1_3/B:1-0-3@1-1&1-7#1-4$1-4!0-1;0-1|aa/C:1+1+3/D:content_2/E:aux+1@1+5&1+3#0+1/F:content_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 24 | 18000000 18700000 w^aa-z+l=ay@3_1/A:1_1_3/B:1-0-3@1-1&1-7#1-4$1-4!0-1;0-1|aa/C:1+1+3/D:content_2/E:aux+1@1+5&1+3#0+1/F:content_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 25 | 18700000 19300000 aa^z-l+ay=k@1_3/A:1_0_3/B:1-1-3@1-1&2-6#1-3$1-3!1-1;0-4|ay/C:1+0+3/D:aux_1/E:content+1@2+4&1+2#0+1/F:content_2/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 26 | 19300000 19850000 z^l-ay+k=t@2_2/A:1_0_3/B:1-1-3@1-1&2-6#1-3$1-3!1-1;0-4|ay/C:1+0+3/D:aux_1/E:content+1@2+4&1+2#0+1/F:content_2/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 27 | 19850000 20400000 l^ay-k+t=aa@3_1/A:1_0_3/B:1-1-3@1-1&2-6#1-3$1-3!1-1;0-4|ay/C:1+0+3/D:aux_1/E:content+1@2+4&1+2#0+1/F:content_2/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 28 | 20400000 21450000 ay^k-t+aa=n@1_3/A:1_1_3/B:1-0-3@1-2&3-5#2-2$2-3!1-3;1-3|aa/C:0+0+2/D:content_1/E:content+2@3+3&2+1#1+2/F:to_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 29 | 21450000 22500000 k^t-aa+n=ih@2_2/A:1_1_3/B:1-0-3@1-2&3-5#2-2$2-3!1-3;1-3|aa/C:0+0+2/D:content_1/E:content+2@3+3&2+1#1+2/F:to_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 30 | 22500000 22950000 t^aa-n+ih=k@3_1/A:1_1_3/B:1-0-3@1-2&3-5#2-2$2-3!1-3;1-3|aa/C:0+0+2/D:content_1/E:content+2@3+3&2+1#1+2/F:to_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 31 | 22950000 23600000 aa^n-ih+k=t@1_2/A:1_0_3/B:0-0-2@2-1&4-4#3-2$2-3!1-2;2-2|ih/C:0+0+2/D:content_1/E:content+2@3+3&2+1#1+2/F:to_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 32 | 23600000 24500000 n^ih-k+t=ax@2_1/A:1_0_3/B:0-0-2@2-1&4-4#3-2$2-3!1-2;2-2|ih/C:0+0+2/D:content_1/E:content+2@3+3&2+1#1+2/F:to_1/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 33 | 24500000 25100000 ih^k-t+ax=f@1_2/A:0_0_2/B:0-0-2@1-1&5-3#3-2$2-3!2-1;3-1|ax/C:1+1+3/D:content_2/E:to+1@4+2&3+1#1+1/F:content_2/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 34 | 25100000 25350000 k^t-ax+f=ih@2_1/A:0_0_2/B:0-0-2@1-1&5-3#3-2$2-3!2-1;3-1|ax/C:1+1+3/D:content_2/E:to+1@4+2&3+1#1+1/F:content_2/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 35 | 25350000 26550000 t^ax-f+ih=l@1_3/A:0_0_2/B:1-1-3@1-2&6-2#3-1$2-2!3-0;4-1|ih/C:0+1+2/D:to_1/E:content+2@5+1&3+0#2+0/F:0_0/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 36 | 26550000 27050000 ax^f-ih+l=ax@2_2/A:0_0_2/B:1-1-3@1-2&6-2#3-1$2-2!3-0;4-1|ih/C:0+1+2/D:to_1/E:content+2@5+1&3+0#2+0/F:0_0/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 37 | 27050000 28050000 f^ih-l+ax=p@3_1/A:0_0_2/B:1-1-3@1-2&6-2#3-1$2-2!3-0;4-1|ih/C:0+1+2/D:to_1/E:content+2@5+1&3+0#2+0/F:0_0/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 38 | 28050000 28500000 ih^l-ax+p=pau@1_2/A:1_1_3/B:0-1-2@2-1&7-1#4-1$3-1!1-0;1-0|ax/C:0+0+0/D:to_1/E:content+2@5+1&3+0#2+0/F:0_0/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 39 | 28500000 29850000 l^ax-p+pau=x@2_1/A:1_1_3/B:0-1-2@2-1&7-1#4-1$3-1!1-0;1-0|ax/C:0+0+0/D:to_1/E:content+2@5+1&3+0#2+0/F:0_0/G:8_5/H:7=5@2=1|L-L%/I:0=0/J:15+10-2 40 | 29850000 30650000 ax^p-pau+x=x@x_x/A:0_1_2/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:0+0+0/D:content_2/E:x+x@x+x&x+x#x+x/F:0_0/G:7_5/H:x=x@1=2|0/I:0=0/J:15+10-2 41 | -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.bap -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.lf0 -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0003.mgc -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.bap -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.lf0 -------------------------------------------------------------------------------- /test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/aligned-synth-examples/cmu_us_arctic_slt_a0044.mgc -------------------------------------------------------------------------------- /test_data/corpus.lst: -------------------------------------------------------------------------------- 1 | cmu_us_arctic_slt_a0003 2 | cmu_us_arctic_slt_a0044 3 | -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.bap -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.lf0 -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0003.mgc -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.bap -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.lf0 -------------------------------------------------------------------------------- /test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/out-dtw_synth/cmu_us_arctic_slt_a0044.mgc -------------------------------------------------------------------------------- /test_data/ref-examples/cmu_us_arctic_slt_a0003.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/ref-examples/cmu_us_arctic_slt_a0003.mgc -------------------------------------------------------------------------------- /test_data/ref-examples/cmu_us_arctic_slt_a0044.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/ref-examples/cmu_us_arctic_slt_a0044.mgc -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0003.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0003.bap -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0003.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0003.lf0 -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0003.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0003.mgc -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0044.bap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0044.bap -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0044.lf0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0044.lf0 -------------------------------------------------------------------------------- /test_data/synth-examples/cmu_us_arctic_slt_a0044.mgc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattShannon/mcd/c86266a2caf6a7cb248ea89ea56f90fd161a297e/test_data/synth-examples/cmu_us_arctic_slt_a0044.mgc --------------------------------------------------------------------------------