Skip to content

Commit d5d6583

Browse files
authored
Merge pull request #153 from readbeyond/devel
aeneas v1.5.1
2 parents d33b92a + 702eb2b commit d5d6583

37 files changed

+109
-64
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# aeneas
1+
# aeneas
22

33
**aeneas** is a Python/C library and a set of tools to automagically synchronize audio and text (aka forced alignment).
44

5-
* Version: 1.7.0
6-
* Date: 2016-12-07
5+
* Version: 1.7.1
6+
* Date: 2016-12-21
77
* Developed by: [ReadBeyond](http://www.readbeyond.it/)
88
* Lead Developer: [Alberto Pettarin](http://www.albertopettarin.it/)
99
* License: the GNU Affero General Public License Version 3 (AGPL v3)
1010
1111
* Quick Links: [Home](http://www.readbeyond.it/aeneas/) - [GitHub](https://github.com/readbeyond/aeneas/) - [PyPI](https://pypi.python.org/pypi/aeneas/) - [Docs](http://www.readbeyond.it/aeneas/docs/) - [Tutorial](http://www.readbeyond.it/aeneas/docs/clitutorial.html) - [Benchmark](https://readbeyond.github.io/aeneas-benchmark/) - [Mailing List](https://groups.google.com/d/forum/aeneas-forced-alignment) - [Web App](http://aeneasweb.org)
1212

13-
13+
1414
## Goal
1515

1616
**aeneas** automatically generates a **synchronization map**
@@ -109,7 +109,7 @@ The generic OS-independent procedure is simple:
109109
`espeak`, `ffmpeg`, `ffprobe`, `pip`, and `python`
110110

111111
3. First install `numpy` with `pip` and then `aeneas` (this order is important):
112-
112+
113113
```bash
114114
pip install numpy
115115
pip install aeneas
@@ -185,7 +185,7 @@ The generic OS-independent procedure is simple:
185185
```bash
186186
python -m aeneas.tools.execute_job job.zip output_directory
187187
```
188-
188+
189189
File `job.zip` should contain a `config.txt` or `config.xml`
190190
configuration file, providing **aeneas**
191191
with all the information needed to parse the input assets
@@ -251,7 +251,7 @@ which explains how to use the built-in command line tools.
251251
* Extensive test suite including 1,200+ unit/integration/performance tests, that run and must pass before each release
252252
253253
254-
## Limitations and Missing Features
254+
## Limitations and Missing Features
255255
256256
* Audio should match the text: large portions of spurious text or audio might produce a wrong sync map
257257
* Audio is assumed to be spoken: not suitable for song captioning, YMMV for CC applications
@@ -304,7 +304,7 @@ No copy rights were harmed in the making of this project.
304304
305305
## Supporting and Contributing
306306
307-
### Sponsors
307+
### Sponsors
308308
309309
* **July 2015**: [Michele Gianella](https://plus.google.com/+michelegianella/about) generously supported the development of the boundary adjustment code (v1.0.4)
310310

README.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ aeneas
44
**aeneas** is a Python/C library and a set of tools to automagically
55
synchronize audio and text (aka forced alignment).
66

7-
- Version: 1.7.0
8-
- Date: 2016-12-07
7+
- Version: 1.7.1
8+
- Date: 2016-12-21
99
- Developed by: `ReadBeyond <http://www.readbeyond.it/>`__
1010
- Lead Developer: `Alberto Pettarin <http://www.albertopettarin.it/>`__
1111
- License: the GNU Affero General Public License Version 3 (AGPL v3)

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.0
1+
1.7.1

aeneas/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@
3535
"""
3636
__license__ = "GNU AGPL v3"
3737
__status__ = "Production"
38-
__version__ = "1.7.0"
38+
__version__ = "1.7.1"

aeneas/cdtw/cdtw_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
setup(
5151
name="cdtw",
52-
version="1.7.0",
52+
version="1.7.1",
5353
description="Python C Extension for computing the DTW as fast as your bare metal allows.",
5454
ext_modules=[CMODULE],
5555
include_dirs=[misc_util.get_numpy_include_dirs()]

aeneas/cew/cew_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747

4848
setup(
4949
name="cew",
50-
version="1.7.0",
50+
version="1.7.1",
5151
description="Python C Extension for synthesizing text with eSpeak.",
5252
ext_modules=[CMODULE]
5353
)

aeneas/cfw/cfw_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454

5555
setup(
5656
name="cfw",
57-
version="1.7.0",
57+
version="1.7.1",
5858
description="Python C Extension for synthesizing text with Festival.",
5959
ext_modules=[CMODULE]
6060
)

aeneas/cmfcc/cmfcc_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
setup(
5252
name="cmfcc",
53-
version="1.7.0",
53+
version="1.7.1",
5454
description="Python C Extension for computing the MFCCs as fast as your bare metal allows.",
5555
ext_modules=[CMODULE],
5656
include_dirs=[misc_util.get_numpy_include_dirs()]

aeneas/cwave/cwave_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
setup(
5151
name="cwave",
52-
version="1.7.0",
52+
version="1.7.1",
5353
description="Python C Extension for for reading WAVE files.",
5454
ext_modules=[CMODULE],
5555
include_dirs=[misc_util.get_numpy_include_dirs()]

aeneas/globalfunctions.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -1005,18 +1005,27 @@ def delete_directory(path):
10051005
pass
10061006

10071007

1008-
def delete_file(handler, path):
1008+
def close_file_handler(handler):
10091009
"""
1010-
Safely delete file.
1010+
Safely close the given file handler.
10111011
10121012
:param object handler: the file handler (as returned by tempfile)
1013-
:param string path: the file path
10141013
"""
10151014
if handler is not None:
10161015
try:
10171016
os.close(handler)
10181017
except:
10191018
pass
1019+
1020+
1021+
def delete_file(handler, path):
1022+
"""
1023+
Safely delete file.
1024+
1025+
:param object handler: the file handler (as returned by tempfile)
1026+
:param string path: the file path
1027+
"""
1028+
close_file_handler(handler)
10201029
if path is not None:
10211030
try:
10221031
os.remove(path)

aeneas/tests/test_globalfunctions.py

+8
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,14 @@ def test_delete_directory_not_existing(self):
562562
gf.delete_directory(orig)
563563
self.assertFalse(gf.directory_exists(orig))
564564

565+
def test_close_file_handler(self):
566+
handler, path = gf.tmp_file()
567+
self.assertTrue(gf.file_exists(path))
568+
gf.close_file_handler(handler)
569+
self.assertTrue(gf.file_exists(path))
570+
gf.delete_file(handler, path)
571+
self.assertFalse(gf.file_exists(path))
572+
565573
def test_delete_file_existing(self):
566574
handler, path = gf.tmp_file()
567575
self.assertTrue(gf.file_exists(path))

aeneas/tools/abstract_cli_program.py

+1
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ def run(self, arguments, show_help=True):
366366

367367
# create logger
368368
self.logger = Logger(tee=self.verbose, tee_show_datetime=self.very_verbose)
369+
self.log([u"Running aeneas %s", aeneas_version])
369370
self.log([u"Formal arguments: %s", self.formal_arguments])
370371
self.log([u"Actual arguments: %s", self.actual_arguments])
371372
self.log([u"Runtime configuration: '%s'", self.rconf.config_string])

aeneas/tools/execute_task.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class ExecuteTaskCLI(AbstractCLIProgram):
133133
u"description": u"input: plain text, output: TSV, tts engine: Festival",
134134
u"audio": AUDIO_FILE,
135135
u"text": gf.relative_path("res/plain.txt", __file__),
136-
u"config": u"task_language=eng|is_text_type=plain|os_task_file_format=tsv",
136+
u"config": u"task_language=eng-USA|is_text_type=plain|os_task_file_format=tsv",
137137
u"syncmap": "output/sonnet.festival.tsv",
138138
u"options": u"-r=\"tts=festival\"",
139139
u"show": False
@@ -205,7 +205,7 @@ class ExecuteTaskCLI(AbstractCLIProgram):
205205
u"description": u"input: multilevel plain text (mplain), different TTS engines, output: JSON",
206206
u"audio": AUDIO_FILE,
207207
u"text": gf.relative_path("res/mplain.txt", __file__),
208-
u"config": u"task_language=eng|is_text_type=mplain|os_task_file_format=json",
208+
u"config": u"task_language=eng-USA|is_text_type=mplain|os_task_file_format=json",
209209
u"syncmap": "output/sonnet.mplain.json",
210210
u"options": u"-r=\"tts_l1=festival|tts_l2=festival|tts_l3=espeak\"",
211211
u"show": False
@@ -376,7 +376,7 @@ class ExecuteTaskCLI(AbstractCLIProgram):
376376
u"description": u"input: single word granularity plain text, output: AUD, tts engine: Festival, TTS cache on",
377377
u"audio": AUDIO_FILE,
378378
u"text": gf.relative_path("res/words.txt", __file__),
379-
u"config": u"task_language=eng|is_text_type=plain|os_task_file_format=aud",
379+
u"config": u"task_language=eng-USA|is_text_type=plain|os_task_file_format=aud",
380380
u"syncmap": "output/sonnet.words.aud",
381381
u"options": u"-r=\"tts=festival|tts_cache=True\"",
382382
u"show": False

aeneas/ttswrappers/basettswrapper.py

+28-18
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ def _synthesize_single_python_helper(self, text, voice_code, output_file_path=No
470470
return the audio data at the end of the function call;
471471
if ``False``, just return ``(True, None)`` in case of success.
472472
473-
:rtype: tuple (result, (duration, sample_rate, encoding, data)) or (result, None)
473+
:rtype: tuple (result, (duration, sample_rate, codec, data)) or (result, None)
474474
"""
475475
raise NotImplementedError(u"This function must be implemented in concrete subclasses supporting Python call")
476476

@@ -489,7 +489,7 @@ def _synthesize_single_c_extension_helper(self, text, voice_code, output_file_pa
489489
If ``output_file_path`` is ``None``,
490490
the audio data will not persist to file at the end of the method.
491491
492-
:rtype: tuple (result, (duration, sample_rate, encoding, data))
492+
:rtype: tuple (result, (duration, sample_rate, codec, data))
493493
"""
494494
raise NotImplementedError(u"This function might be implemented in concrete subclasses supporting C extension call")
495495

@@ -521,12 +521,12 @@ def _synthesize_single_subprocess_helper(self, text, voice_code, output_file_pat
521521
return the audio data at the end of the function call;
522522
if ``False``, just return ``(True, None)`` in case of success.
523523
524-
:rtype: tuple (result, (duration, sample_rate, encoding, data)) or (result, None)
524+
:rtype: tuple (result, (duration, sample_rate, codec, data)) or (result, None)
525525
"""
526526
# return zero if text is the empty string
527527
if len(text) == 0:
528528
#
529-
# NOTE sample_rate, encoding, data do not matter
529+
# NOTE sample_rate, codec, data do not matter
530530
# if the duration is 0.000 => set them to None
531531
#
532532
self.log(u"len(text) is zero: returning 0.000")
@@ -640,7 +640,7 @@ def _read_audio_data(self, file_path):
640640
"""
641641
Read audio data from file.
642642
643-
:rtype: tuple (True, (duration, sample_rate, encoding, data)) or (False, None) on exception
643+
:rtype: tuple (True, (duration, sample_rate, codec, data)) or (False, None) on exception
644644
"""
645645
try:
646646
self.log(u"Reading audio data...")
@@ -680,22 +680,30 @@ def _synthesize_multiple_generic(self, helper_function, text_file, output_file_p
680680
"""
681681
self.log(u"Calling TTS engine using multiple generic function...")
682682

683-
# get sample rate and encoding
684-
self.log(u"Determining codec and sample rate with dummy text...")
685-
succeeded, data = helper_function(
686-
text=u"Dummy text to get sample_rate",
687-
voice_code=self._language_to_voice_code(self.DEFAULT_LANGUAGE),
688-
output_file_path=None
689-
)
690-
if not succeeded:
691-
self.log_crit(u"An unexpected error occurred in helper_function")
692-
return (False, None)
693-
du_nu, sample_rate, encoding, da_nu = data
694-
self.log(u"Determining codec and sample rate with dummy text... done")
683+
# get sample rate and codec
684+
self.log(u"Determining codec and sample rate...")
685+
if (self.OUTPUT_AUDIO_FORMAT is None) or (len(self.OUTPUT_AUDIO_FORMAT) != 3):
686+
self.log(u"Determining codec and sample rate with dummy text...")
687+
succeeded, data = helper_function(
688+
text=u"Dummy text to get sample_rate",
689+
voice_code=self._language_to_voice_code(self.DEFAULT_LANGUAGE),
690+
output_file_path=None
691+
)
692+
if not succeeded:
693+
self.log_crit(u"An unexpected error occurred in helper_function")
694+
return (False, None)
695+
du_nu, sample_rate, codec, da_nu = data
696+
self.log(u"Determining codec and sample rate with dummy text... done")
697+
else:
698+
self.log(u"Reading codec and sample rate from OUTPUT_AUDIO_FORMAT")
699+
codec, channels_nu, sample_rate = self.OUTPUT_AUDIO_FORMAT
700+
self.log(u"Determining codec and sample rate... done")
701+
self.log([u" codec: %s", codec])
702+
self.log([u" sample rate: %d", sample_rate])
695703

696704
# open output file
697705
output_file = AudioFile(rconf=self.rconf, logger=self.logger)
698-
output_file.audio_format = encoding
706+
output_file.audio_format = codec
699707
output_file.audio_channels = 1
700708
output_file.audio_sample_rate = sample_rate
701709

@@ -821,5 +829,7 @@ def _loop_use_cache(self, helper_function, num, fragment):
821829
self.log(u"Added fragment to cache")
822830
else:
823831
self.log(u"Fragment has zero duration, not adding it to cache")
832+
self.log([u"Closing file handler for cached output file path '%s'", file_path])
833+
gf.close_file_handler(file_handler)
824834
self.log([u"Examining fragment %d (cache)... done", num])
825835
return (True, data)

aeneas/ttswrappers/festivalttswrapper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class FESTIVALTTSWrapper(BaseTTSWrapper):
118118
ENG_SCT: ENG_SCT,
119119
ENG_USA: ENG_USA,
120120
}
121-
DEFAULT_LANGUAGE = ENG
121+
DEFAULT_LANGUAGE = ENG_USA
122122

123123
CODE_TO_HUMAN = {
124124
CES: u"Czech",

aeneas_check_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"""
4545
__license__ = "GNU AGPL 3"
4646
__status__ = "Production"
47-
__version__ = "1.7.0"
47+
__version__ = "1.7.1"
4848

4949
ANSI_ERROR = u"\033[91m"
5050
ANSI_OK = u"\033[92m"

bin/aeneas_check_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"""
4545
__license__ = "GNU AGPL 3"
4646
__status__ = "Production"
47-
__version__ = "1.7.0"
47+
__version__ = "1.7.1"
4848

4949
ANSI_ERROR = u"\033[91m"
5050
ANSI_OK = u"\033[92m"

bin/aeneas_convert_syncmap.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"""
4141
__license__ = "GNU AGPL 3"
4242
__status__ = "Production"
43-
__version__ = "1.7.0"
43+
__version__ = "1.7.1"
4444

4545

4646
def main():

bin/aeneas_download.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"""
4141
__license__ = "GNU AGPL 3"
4242
__status__ = "Production"
43-
__version__ = "1.7.0"
43+
__version__ = "1.7.1"
4444

4545

4646
def main():

bin/aeneas_execute_job.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"""
4343
__license__ = "GNU AGPL 3"
4444
__status__ = "Production"
45-
__version__ = "1.7.0"
45+
__version__ = "1.7.1"
4646

4747

4848
def main():

bin/aeneas_execute_task.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"""
4242
__license__ = "GNU AGPL 3"
4343
__status__ = "Production"
44-
__version__ = "1.7.0"
44+
__version__ = "1.7.1"
4545

4646

4747
def main():

bin/aeneas_plot_waveform.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"""
4141
__license__ = "GNU AGPL 3"
4242
__status__ = "Production"
43-
__version__ = "1.7.0"
43+
__version__ = "1.7.1"
4444

4545

4646
def main():

bin/aeneas_synthesize_text.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"""
4242
__license__ = "GNU AGPL 3"
4343
__status__ = "Production"
44-
__version__ = "1.7.0"
44+
__version__ = "1.7.1"
4545

4646

4747
def main():

bin/aeneas_validate.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"""
4848
__license__ = "GNU AGPL 3"
4949
__status__ = "Production"
50-
__version__ = "1.7.0"
50+
__version__ = "1.7.1"
5151

5252

5353
def main():

check_dependencies.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"""
4545
__license__ = "GNU AGPL 3"
4646
__status__ = "Production"
47-
__version__ = "1.7.0"
47+
__version__ = "1.7.1"
4848

4949
ANSI_ERROR = u"\033[91m"
5050
ANSI_OK = u"\033[92m"

0 commit comments

Comments
 (0)