sphinx4 FrontEnd流程分析
回顧一下sphinx4的整體架構(gòu):
從上面我們看到,應(yīng)用程序的輸入Input(一般是錄音數(shù)據(jù)),首先經(jīng)過(guò)前端(FrontEnd)處理。前端處理有一序列的步驟,最后會(huì)得到聲音對(duì)應(yīng)的特征值,也就是所謂的Feature。然后將得到的feature傳給×××Decoder中的Scorer模塊進(jìn)行處理。今天我們從整體上分析一下FrontEnd的處理流程。
我們還是以HelloWorld這個(gè)為例,先來(lái)看一下它的配置文件:
<component name="threadedScorer"
type="edu.cmu.sphinx.decoder.scorer.ThreadedAcousticScorer">
? ? ? ?<propertyname="frontend"value="${frontend}"/>
</component>
threadedScorer有FrontEnd這個(gè)屬性,在看一下FrontEnd的配置:
<component name="frontEnd" type="edu.cmu.sphinx.frontend.FrontEnd">
? ? ? ?<propertylist name="pipeline">
? ? ? ? ? ? ? ?<item>microphone </item>
? ? ? ? ? ? ? ?<item>preemphasizer </item>
? ? ? ? ? ? ? ?<item>windower </item>
? ? ? ? ? ? ? ?<item>fft </item>
? ? ? ? ? ? ? ?<item>melFilterBank </item>
? ? ? ? ? ? ? ?<item>dct </item>
? ? ? ? ? ? ? ?<item>liveCMN </item>
? ? ? ? ? ? ? ?<item>featureExtraction </item>
? ? ? ?</propertylist>
</component>
從配置文件可以看到,FrontEnd有一個(gè)屬性列表,列表中的每一個(gè)item都是前段處理的一個(gè)模塊。熟悉設(shè)計(jì)模式的應(yīng)該知道,這里顯然用到了責(zé)任鏈設(shè)計(jì)模式。首先從microphone開(kāi)始,錄音數(shù)據(jù)處理完后再沿著這條管道線交給下一個(gè)處理,最后到達(dá)featureExtraction,進(jìn)行最后的特征提取,提取完特征再傳遞給Scorer處理。
下面這個(gè)是 FrontEnd 的處理流程:
上面的那些item對(duì)應(yīng)的java類,實(shí)際上都是一個(gè)DataProcessor,即它們都繼承了BaseDataProcessor這個(gè)類,DataProcessor有一個(gè)方法getData(),可以得到DataProcessor處理完后的數(shù)據(jù)。
我們?cè)賮?lái)看一下FrontEnd的相關(guān)定義。在FrontEnd定義了一個(gè)DataProcessor的List,用來(lái)存放上面配置文件中的那些item對(duì)應(yīng)的實(shí)例對(duì)象,還定義了兩個(gè)DataProcessor,first表示第一個(gè)DataProcessor,last表示下一個(gè)DataProcessor:
private List<DataProcessor> frontEndList;
private DataProcessor first;
private DataProcessor last;
而得到這些示例對(duì)象是通過(guò)它的newProperties回調(diào)方法,有關(guān)解析和屬性相關(guān)的內(nèi)容前面已經(jīng)介紹過(guò)了。
@Override
public void newProperties(PropertySheet ps) throws PropertyException {
? ? ? ?super.newProperties(ps);
? ? ? ?frontEndList = ps.getComponentList(PROP_PIPELINE, DataProcessor.class);
? ? ? ?init();
}
獲取完屬性列表后,接著調(diào)用了init方法:
private void init() {
? ? ? ?last = null;
? ? ? ?for (DataProcessor dp : frontEndList) {
? ? ? ? ? ? ? ?assert dp != null;
? ? ? ? ? ? ? ?if (last != null)
? ? ? ? ? ? ? ? ? ? ? ?dp.setPredecessor(last);
? ? ? ? ? ? ? ?if (first == null) {
? ? ? ? ? ? ? ? ? ? ? ?first = dp;
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?last = dp;
? ? ? ?}
? ? ? ?initialize();
? ?}
這個(gè)方法的作用就是遍歷整個(gè)DataProcessor List,按順序依次設(shè)置下一個(gè)DataProcessor,這樣整個(gè)List就串起來(lái)了,接著又調(diào)用了initialize方法:
@Override
public void initialize() {
? ? ? ?super.initialize();
? ? ? ?for (DataProcessor dp : frontEndList) {
? ? ? ? ? ? ? ?dp.initialize();
? ? ? ?}
? ?}
initialize這個(gè)是接口DataProcessor定義的一個(gè)抽象方法,每個(gè)子類必須實(shí)現(xiàn)自己的版本。這個(gè)方法遍歷了所有的DataProcessor,然后調(diào)用它們自己的initialize,完成自己的初始化工作。
FontEnd還有一個(gè) getData方法,用來(lái)獲取整個(gè)流程處理完后最終的數(shù)據(jù):
@Override
public Data getData() throws DataProcessingException {
? ? ? ?Data data = last.getData();
? ? ? ?// fire the signal listeners if its a signal
? ? ? ?if (data instanceof Signal) {
? ? ? ? ? ? ? ?fireSignalListeners((Signal) data);
? ? ? ?}
? ?return data;
}
以上就是FrontEnd的大致的處理流程,本質(zhì)上就是使用了責(zé)任鏈設(shè)計(jì)模式,將所有需要對(duì)語(yǔ)音進(jìn)行處理的DataProcessor串成一個(gè)鏈條,然后沿著這個(gè)鏈條逐一處理,處理完后通過(guò)getData獲取最終的數(shù)據(jù)。
轉(zhuǎn)載于:https://blog.51cto.com/ikinglai/1251156
總結(jié)
以上是生活随笔為你收集整理的sphinx4 FrontEnd流程分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ubuntu12.10下arm-linu
- 下一篇: vim的巧用---对比操作