/** * Copyright 2004-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 <http://www.gnu.org/licenses/>. * */ package marytts.unitselection.concat; import marytts.signalproc.window.DynamicTwoHalvesWindow; import marytts.signalproc.window.Window; import marytts.util.data.BufferedDoubleDataSource; import marytts.util.data.Datagram; import marytts.util.data.DoubleDataSource; public class DatagramOverlapDoubleDataSource extends BufferedDoubleDataSource { protected Datagram[][] datagrams; protected Datagram[] rightContexts; protected int p; // point to current datagrams/rightContext protected int q; // point to current datagram within datagrams[p] protected int totalRead; // count samples read from datagrams /** * Construct an double data source from the given array of datagram arrays and right contexts. * * @param datagrams * datagrams * @param rightContexts * rightContexts */ public DatagramOverlapDoubleDataSource(Datagram[][] datagrams, Datagram[] rightContexts) { super((DoubleDataSource) null); this.datagrams = datagrams; this.rightContexts = rightContexts; dataLength = 0; for (int i = 0; i < datagrams.length; i++) { for (int j = 0; j < datagrams[i].length; j++) { dataLength += datagrams[i][j].getDuration(); } } p = 0; q = 0; } /** * Whether or not any more data can be read from this data source. * * @return true if another call to getData() will return data, false otherwise. */ public boolean hasMoreData() { if (currentlyInBuffer() > 0 || totalRead < dataLength) return true; return false; } /** * The number of doubles that can currently be read from this double data source without blocking. This number can change over * time. * * @return the number of doubles that can currently be read without blocking */ public int available() { int available = (int) (currentlyInBuffer() + dataLength - totalRead); return available; } /** * Attempt to get more data from the input source. If less than this can be read, the possible amount will be read, but * canReadMore() will return false afterwards. * * @param minLength * the amount of data to get from the input source * @return true if the requested amount could be read, false if none or less data could be read. */ protected boolean readIntoBuffer(int minLength) { if (bufferSpaceLeft() < minLength) { // current buffer cannot hold the data requested; // need to make it larger increaseBufferSize(minLength + currentlyInBuffer()); } else if (buf.length - writePos < minLength) { compact(); // create a contiguous space for the new data } // Now we have a buffer that can hold at least minLength new data points int readSum = 0; // read blocks: while (readSum < minLength && p < datagrams.length) { if (q >= datagrams[p].length) { p++; q = 0; } else { Datagram next = datagrams[p][q]; int length = (int) next.getDuration(); // System.out.println("Unit duration = " + String.valueOf(length)); if (buf.length < writePos + length) { increaseBufferSize(writePos + length); } int read = readDatagram(next, buf, writePos); if (q == 0 && p > 0 && rightContexts[p - 1] != null) { // overlap-add situation // window the data that we have just read with the left half of a HANN window: new DynamicTwoHalvesWindow(Window.HANNING).applyInlineLeftHalf(buf, writePos, read); // and overlap-add the previous right context, windowed with the right half of a HANN window: double[] context = new double[(int) rightContexts[p - 1].getDuration()]; readDatagram(rightContexts[p - 1], context, 0); new DynamicTwoHalvesWindow(Window.HANNING).applyInlineRightHalf(context, 0, context.length); for (int i = 0, iMax = Math.min(read, context.length); i < iMax; i++) { buf[writePos + i] += context[i]; } } writePos += read; readSum += read; totalRead += read; q++; } } if (dataProcessor != null) { dataProcessor.applyInline(buf, writePos - readSum, readSum); } return readSum >= minLength; } protected int readDatagram(Datagram d, double[] target, int pos) { int dur = (int) d.getDuration(); byte[] frameAudio = d.getData(); assert frameAudio.length / 2 == dur : "expected datagram data length to be " + (dur * 2) + ", found " + frameAudio.length; for (int i = 0; i < frameAudio.length; i += 2, pos++) { int sample; byte lobyte; byte hibyte; // big endian: lobyte = frameAudio[i + 1]; hibyte = frameAudio[i]; sample = hibyte << 8 | lobyte & 0xFF; target[pos] = sample / 32768.0;// normalise to range [-1, 1]; } return dur; } }