📄 clusterunitselector.java
字号:
// be stored in p.next? addPaths(p.next, np); } } } } else { System.err.println( "Viterbi.decode: general beam search not implemented"); } } } /** * Try to add paths to the given point. * * @param point the point to add the paths to * @param paths the path */ void addPaths(ViterbiPoint point, ViterbiPath path) { ViterbiPath nextPath; for (ViterbiPath p = path; p != null; p = nextPath) { nextPath = p.next; addPath(point, p); } } /** * Add the new path to the state path if it is * better than the current path. In this, state means * the position of the candidate associated with this * path in the candidate queue * for the corresponding segment item. In other words, * this method uses newPath as the one path leading to * the candidate newPath.candidate, if it has a better * score than the previously best path leading to that candidate. * * @param point where the path is added * @param newPath the path to add if its score is best */ void addPath(ViterbiPoint point, ViterbiPath newPath) { if (point.statePaths[newPath.state] == null) { // we don't have one yet, so this is best point.statePaths[newPath.state] = newPath; } else if (isBetterThan(newPath.score, point.statePaths[newPath.state].score)) { // its better than what we already have point.statePaths[newPath.state] = newPath; } else { // its not better that what we already have // so we just forget about it. } } /** * See if a is better than b. Goodness is defined * by 'bigIsGood'. * * @param a value to check * @param b value to check. * * return true if a is better than b. */ private boolean isBetterThan(int a, int b) { if (bigIsGood) { return a > b; } else { return a < b; } } /** * Find the best path through the decoder, adding the feature * name to the candidate. * * @param feature the feature to add * @return true if a best path was found */ boolean result(String feature) { ViterbiPath path; if (timeline == null || timeline.next == null) { return true; // null case succeeds } path = findBestPath(); if (path == null) { return false; } for (; path != null; path = path.from) { if (path.candidate != null) { path.candidate.item.getFeatures().setObject(feature, path.candidate.value); } } return true; } /** * Given a feature, copy the value associated with feature * name from the path to each item in the path. * * @param feature the name of the feature. */ void copyFeature(String feature) { ViterbiPath path = findBestPath(); if (path == null) { return; // nothing to copy, empty stream or no solution } for (; path != null; path = path.from) { if (path.candidate != null && path.isPresent(feature)) { path.candidate.item.getFeatures().setObject(feature, path.getFeature(feature)); } } } /** * Finds the best (queue of) candidate(s) for a given (segment) item. * This traverses a CART tree for target cluster selection as described in * the paper introducing the clunits algorithm. This corresponds to the * "target costs" described for general unit selection. * @return the first candidate in the queue of candidate units for this item. */ private ViterbiCandidate getCandidate(Item item) { // TODO: This should better be called getCandidates() (plural form), // because what it does is find all the candidates for the item // and return the head of the queue. String unitType = item.getFeatures().getString("clunit_name"); CART cart = clunitDB.getTree(unitType); // Here, the unit candidates are selected. int[] clist = (int[]) cart.interpret(item); // Now, clist is an array of instance numbers for the units of type // unitType that belong to the best cluster according to the CART. ViterbiCandidate p; ViterbiCandidate all; ViterbiCandidate gt; all = null; for (int i = 0; i < clist.length; i++) { p = new ViterbiCandidate(); p.next = all; // link them reversely: the first in clist will be at the end of the queue p.item = item; // The item is the same for all these candidates in the queue. p.score = 0; // remember the absolute unit index: p.setInt(clunitDB.getUnitIndex(unitType, clist[i])); all = p; // this is OK if (DEBUG) { debug(" gc adding " + clist[i]); } } // Take into account candidates for previous item? // Depending on the setting of EXTEND_SELECTIONS in the database, // look the first candidates for the preceding item, // and add the units following these (which are not yet candidates) // as candidates. EXTEND_SELECTIONS indicates how many of these // are added. A high setting will add candidates which don't fit the // target well, but which can be smoothly concatenated with the context. // In a sense, this means trading target costs against join costs. if (clunitDB.getExtendSelections() > 0 && item.getPrevious() != null) { // Get the candidates for the preceding (segment) item ViterbiCandidate lc = (ViterbiCandidate) (item. getPrevious().getFeatures().getObject("clunit_cands")); if (DEBUG) { debug(" lc " + lc); } for (int e = 0; lc != null && (e < clunitDB.getExtendSelections()); lc = lc.next) { int nu = clunitDB.getNextUnit(lc.ival); if (DEBUG) { debug(" e: " + e + " nu: " + nu); } if (nu == ClusterUnitDatabase.CLUNIT_NONE) { continue; } // Look through the list of candidates for the current item: for (gt = all; gt != null; gt = gt.next) { if (DEBUG) { debug(" gt " + gt.ival + " nu " + nu); } if (nu == gt.ival) { // The unit following one of the candidates for the preceding // item already is a candidate for the current item. break; } } if (DEBUG) { debug("nu " + clunitDB.getUnit(nu).getName() + " all " + clunitDB.getUnit(all.ival).getName() + " " + all.ival); } if ((gt == null)&&clunitDB.isUnitTypeEqual(nu, all.ival)) { // nu is of the right unit type and is not yet one of the candidates. // add it to the queue of candidates for the current item: p = new ViterbiCandidate(); p.next = all; p.item = item; p.score = 0; p.setInt(nu); all = p; e++; } } } item.getFeatures().setObject("clunit_cands", all); return all; } /** * Construct a new path element linking a previous path to the given candidate. * The (penalty) score associated with the new path is calculated as the sum of * the score of the old path plus the score of the candidate itself plus the * join cost of appending the candidate to the nearest candidate in the given path. * This join cost takes into account optimal coupling if the database has * OPTIMAL_COUPLING set to 1. The join position is saved in the new path, as * the features "unit_prev_move" and "unit_this_move". * * @param path the previous path, or null if this candidate starts a new path * @param candiate the candidate to add to the path * * @return a new path, consisting of this candidate appended to the previous path, and * with the cumulative (penalty) score calculated. */ private ViterbiPath getPath(ViterbiPath path, ViterbiCandidate candidate) { int cost; ViterbiPath newPath = new ViterbiPath(); newPath.candidate = candidate; newPath.from = path; // // Flite 1.1 has some logic here to test to see // if the unit database is fully populated or not and if not // load fixed residuals and calculate distance with a // different distance algorithm that is designed for fixed // point. FreeTTS doesn't really need to do that. // if (path == null || path.candidate == null) { cost = 0; } else { int u0 = path.candidate.ival; int u1 = candidate.ival; if (clunitDB.getOptimalCoupling() == 1) { Cost oCost = getOptimalCouple(u0, u1); if (oCost.u0Move != -1) { newPath.setFeature("unit_prev_move", new Integer(oCost.u0Move)); } if (oCost.u1Move != -1) { newPath.setFeature("unit_this_move", new Integer(oCost.u1Move)); } cost = oCost.cost; } else if (clunitDB.getOptimalCoupling() == 2) { cost = getOptimalCoupleFrame(u0, u1); } else { cost = 0; } } // cost *= clunitDB.getContinuityWeight(); cost *= 5; // magic number ("continuity weight") from flite // TODO: remove the state attribute from ViterbiPath, as it is simply path.candidate.pos! newPath.state = candidate.pos; if (path == null) { newPath.score = cost + candidate.score; } else { newPath.score = cost + candidate.score + path.score; } return newPath; } /** * Find the best path. This requires decode() to have been run. * * @return the best path. */ private ViterbiPath findBestPath() { ViterbiPoint t; int best; int worst; ViterbiPath bestPath = null; if (bigIsGood) { worst = Integer.MIN_VALUE; } else { worst = Integer.MAX_VALUE; } best = worst; // TODO: do not need t, can use lastPoint throughout t = lastPoint; if (numStates != 0) { if (DEBUG) { debug("fbp ns " + numStates + " t " + t.numStates + " best " + best); } // All paths end in lastPoint, and take into account // previous path segment's scores. Therefore, it is // sufficient to find the best path from among the // paths for lastPoint. for (int i = 0; i < t.numStates; i++) { if (t.statePaths[i] != null && (isBetterThan(t.statePaths[i].score, best))) { best = t.statePaths[i].score; bestPath = t.statePaths[i]; } } } return bestPath; } /** * Find the optimal coupling frame for a pair of units. * * @param u0 first unit to try * @param u1 second unit to try * * @return the cost for this coupling, including the best coupling frame */ Cost getOptimalCouple(int u0, int u1) { int a,b; int u1_p; int i, fcount; int u0_st, u1_p_st, u0_end, u1_p_end; int best_u0, best_u1_p; int dist, best_val; Cost cost = new Cost(); u1_p = clunitDB.getPrevUnit(u1); // If u0 precedes u1, the cost is 0, and we're finished. if (u1_p == u0) { return cost; } // If u1 does not have a previous unit, or that previous // unit does not belong to the same phone, the optimal // couple frame must be found between u0 and u1. if (u1_p == ClusterUnitDatabase.CLUNIT_NONE || clunitDB.getPhone(u0) != clunitDB.getPhone(u1_p)) { cost.cost = 10 * getOptimalCoupleFrame(u0, u1); return cost; } // If u1 has a valid previous unit, try to find the optimal // couple point between u0 and that previous unit, u1_p. // Find out which of u1_p and u0 is shorter. // In both units, we plan to start from one third of the unit length, // and to compare frame coupling frame by frame until the end of the // shorter unit is reached. u0_end = clunitDB.getEnd(u0) - clunitDB.getStart(u0); u1_p_end = clunitDB.getEnd(u1_p) - clunitDB.getStart(u1_p); u0_st = u0_end / 3; u1_p_st = u1_p_end / 3; if ((u0_end - u0_st) < (u1_p_end - u1_p_st)) { fcount = u0_end - u0_st; // We could now shift the starting point for coupling in the longer unit // so that the distance from the end is the same in both units: /* u1_p_st = u1_p_end - fcount; */ } else { fcount = u1_p_end - u1_p_st; // We could now shift the starting point for coupling in the longer unit // so that the distance from the end is the same in both units: /* u0_st = u0_end - fcount; */ } // Now go through the two units, and search for the frame pair where // the acoustic distance is smallest. best_u0 = u0_end; best_u1_p = u1_p_end; best_val = Integer.MAX_VALUE; for (i = 0; i < fcount; ++i) { a = clunitDB.getStart(u0)+ u0_st + i; b = clunitDB.getStart(u1_p) + u1_p_st + i; dist = getFrameDistance(a, b, clunitDB.getJoinWeights(),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -