All Downloads are FREE. Search and download functionalities are using the official Maven repository.

marytts.modules.SynthesisCallerBase Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2000-2006 DFKI GmbH.
 * All Rights Reserved.  Use is subject to license terms.
 *
 * This file is part of MARY TTS.
 *
 * MARY TTS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 */
package marytts.modules;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Locale;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

import marytts.datatypes.MaryData;
import marytts.datatypes.MaryDataType;
import marytts.modules.synthesis.Voice;
import marytts.util.data.audio.AppendableSequenceAudioInputStream;

import org.xml.sax.SAXException;

/**
 * A base class for a synthesis caller. This can work as a normal MARY module, converting synthesis markup data into audio, or it
 * can be indirectly called from the corresponding Synthesizer.
 * 
 * @author Marc Schröder
 */

public abstract class SynthesisCallerBase extends InternalModule {
	protected SynthesisCallerBase(String name, MaryDataType inputType, MaryDataType outputType) {
		super(name, inputType, outputType, null);
	}

	public synchronized void startup() throws Exception {
		super.startup();
	}

	/**
	 * Perform a power-on self test by processing some example input data. This implementation does nothing; instead, the module
	 * test is carried out via Synthesis in the WaveformSynthesizer associated with this Caller.
	 */
	public synchronized void powerOnSelfTest() {
	}

	/**
	 * From synthesis markup input d, create audio output of the type specified by a preceding call to
	 * setAudioType(). Returns a MaryData structure whose data is an input stream from which audio data of the
	 * specified type can be read.
	 * 
	 * @param d
	 *            d
	 * @throws TransformerConfigurationException
	 *             TransformerConfigurationException
	 * @throws TransformerException
	 *             TransformerException
	 * @throws FileNotFoundException
	 *             FileNotFoundException
	 * @throws IOException
	 *             IOException
	 * @throws ParserConfigurationException
	 *             ParserConfigurationException
	 * @throws SAXException
	 *             SAXException
	 * @throws Exception
	 *             Exception
	 */
	public MaryData process(MaryData d) throws TransformerConfigurationException, TransformerException, FileNotFoundException,
			IOException, ParserConfigurationException, SAXException, Exception {
		assert d.getAudioFileFormat() != null;
		assert getState() == MODULE_RUNNING;

		// As the input may contain multipe voice sections,
		// the challenge in this method is to join the audio data
		// resulting from individual synthesis calls with the respective
		// voice into one audio stream of the specified type.
		// Overall strategy:
		// * In input, identify the sections to be spoken by different voices
		// * For each of these sections,
		// - synthesise the section in the voice's native audio format
		// - convert to the common audio format if necessary / possible
		// * Join the audio input streams
		// * Return a MaryData structure containing a single audio input stream
		// from which the audio data in the desired format can be read.

		String input = (String) d.getData();
		Voice defaultVoice = d.getDefaultVoice();
		if (defaultVoice == null) {
			defaultVoice = Voice.getDefaultVoice(Locale.GERMAN);
			assert defaultVoice != null;
			logger.info("No default voice associated with data. Assuming global default " + defaultVoice.getName());
		}

		MaryData result = new MaryData(outputType(), d.getLocale());
		result.setAudioFileFormat(d.getAudioFileFormat());
		AudioFormat targetFormat = d.getAudioFileFormat().getFormat();
		if (d.getAudio() != null) {
			// This (empty) AppendableSequenceAudioInputStream object allows a
			// thread reading the audio data on the other "end" to get to our data as we are producing it.
			assert d.getAudio() instanceof AppendableSequenceAudioInputStream;
			result.setAudio(d.getAudio());
		}

		return result;
	}

	protected AudioInputStream convertIfNeededAndPossible(AudioInputStream input, AudioFormat format, String voiceName) {
		if (input.getFormat().equals(format)) {
			return input;
		}
		// Attempt conversion; if not supported, log a warning
		// and provide the non-converted stream.
		logger.info("Conversion required for voice " + voiceName);
		if (AudioSystem.isConversionSupported(format, input.getFormat())) {
			return AudioSystem.getAudioInputStream(format, input);
		}
		// conversion not supported
		logger.warn("Conversion to audio format " + format + " not supported. Providing voice default instead: "
				+ input.getFormat());
		return input;
	}

	/**
	 * Synthesise one chunk of synthesis markup with a given voice.
	 * 
	 * @param synthesisMarkup
	 *            the input data in the native format expected by the synthesis engine
	 * @param voice
	 *            the voice with which to synthesise the data
	 * @throws IOException
	 *             IOException
	 * @return an AudioInputStream in the native audio format of the voice
	 */
	public abstract AudioInputStream synthesiseOneSection(String synthesisMarkup, Voice voice) throws IOException;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy