1/*
2 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/**
17 * @file picokpdf.c
18 *
19 *  knowledge handling for pdf
20 *
21 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
22 * All rights reserved.
23 *
24 * History:
25 * - 2009-04-20 -- initial version
26 *
27 */
28
29#include "picoos.h"
30#include "picodbg.h"
31#include "picoknow.h"
32#include "picokpdf.h"
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37#if 0
38}
39#endif
40
41
42/* ************************************************************/
43/* pdf */
44/* ************************************************************/
45
46/*
47 * @addtogroup picokpdf
48 *
49  overview: format of knowledge base pdf file
50
51  This is the format for the dur pdf file:
52    - Numframes:     1             uint16
53    - Vecsize:       1             uint8
54    - sampperframe:  1             uint8
55    - Phonquantlen:  1             uint8
56    - Phonquant:     Phonquantlen  uint8
57    - Statequantlen: 1             uint8
58    - Statequantlen: Statequantlen uint8
59    - And then numframes x vecsize uint8
60
61  This is the format for mul (mgc and lfz) pdf files:
62    - numframes:         1         uint16
63    - vecsize:           1         uint8
64    - numstates:         1         uint8
65    - numframesperstate: numstates uint16
66    - ceporder:          1         uint8
67    - numvuv             1         uint8
68    - numdeltas:         1         uint8
69    - scmeanpow:         1         uint8
70    - maxbigpow:         1         uint8
71    - scmeanpowum  KPDF_NUMSTREAMS * ceporder uint8
72    - scivarpow    KPDF_NUMSTREAMS * ceporder uint8
73
74    And then numframes x vecsize uint8
75
76*/
77
78
79/* ************************************************************/
80/* pdf data defines */
81/* may not be changed with current implementation */
82/* ************************************************************/
83
84
85#define KPDF_NUMSTREAMS  3 /* coeff, delta, deltadelta */
86
87
88/* ************************************************************/
89/* pdf loading */
90/* ************************************************************/
91
92static pico_status_t kpdfDURInitialize(register picoknow_KnowledgeBase this,
93                                       picoos_Common common) {
94    picokpdf_pdfdur_t *pdfdur;
95    picoos_uint16 pos;
96
97    if (NULL == this || NULL == this->subObj) {
98        return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
99                                       NULL, NULL);
100    }
101    pdfdur = (picokpdf_pdfdur_t *)this->subObj;
102
103    pos = 0;
104
105    pdfdur->numframes = ((picoos_uint16)(this->base[pos+1])) << 8 |
106        this->base[pos];
107    pos += 2;
108    pdfdur->vecsize = this->base[pos++];
109    pdfdur->sampperframe = this->base[pos++];
110    pdfdur->phonquantlen = this->base[pos++];
111    pdfdur->phonquant = &(this->base[pos]);
112    pos += pdfdur->phonquantlen;
113    pdfdur->statequantlen = this->base[pos++];
114    pdfdur->statequant = &(this->base[pos]);
115    pos += pdfdur->statequantlen;
116    pdfdur->content = &(this->base[pos]);
117    PICODBG_DEBUG(("numframes %d, vecsize %d, phonquantlen %d, "
118                   "statequantlen %d", pdfdur->numframes, pdfdur->vecsize,
119                   pdfdur->phonquantlen, pdfdur->statequantlen));
120    if ((picoos_uint32)(pos + (pdfdur->numframes * pdfdur->vecsize)) != this->size) {
121        PICODBG_DEBUG(("header-spec size %d, kb-size %d",
122                       pos + (pdfdur->numframes * pdfdur->vecsize),
123                       this->size));
124        return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT,
125                                       NULL, NULL);
126    }
127    PICODBG_DEBUG(("dur pdf initialized"));
128    return PICO_OK;
129}
130
131static picoos_uint8 convScaleFactorToBig(picoos_uint8 pow, picoos_uint8 bigpow)
132{
133    if (pow > 0x0F) {
134        pow = bigpow + (0xFF - pow + 1);  /* take 2's complement of negative pow */
135    } else if (bigpow >= pow) {
136        pow = bigpow - pow;
137    } else {
138        /* error: bigpow is smaller than input pow */
139        return 0;
140    }
141    return pow;
142}
143
144static pico_status_t kpdfMULInitialize(register picoknow_KnowledgeBase this,
145                                       picoos_Common common) {
146    picokpdf_pdfmul_t *pdfmul;
147    picoos_uint16 pos;
148    picoos_uint8 scmeanpow, maxbigpow, nummean;
149    picoos_uint8 i;
150
151    if (NULL == this || NULL == this->subObj) {
152        return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
153                                       NULL, NULL);
154    }
155    pdfmul = (picokpdf_pdfmul_t *)this->subObj;
156
157    pos = 0;
158
159    pdfmul->numframes = ((picoos_uint16)(this->base[pos+1])) << 8 |
160        this->base[pos];
161    pos += 2;
162    pdfmul->vecsize = this->base[pos++];
163    pdfmul->numstates = this->base[pos++];
164    {
165        pdfmul->stateoffset[0] = (picoos_uint16) 0;
166        for (i=1; i<pdfmul->numstates; i++) {
167            pdfmul->stateoffset[i] = pdfmul->stateoffset[i-1] + (this->base[pos] | ((picoos_uint16) this->base[pos+1] << 8));
168            pos += 2;
169        }
170        pos += 2; /* we don't need the last number if we only need the offset (i.e. how to get to the vector start) */
171    }
172
173    pdfmul->ceporder = this->base[pos++];
174    pdfmul->numvuv = this->base[pos++];
175    pdfmul->numdeltas = this->base[pos++];
176    scmeanpow = this->base[pos++];
177    maxbigpow = this->base[pos++];
178    if (maxbigpow < PICOKPDF_BIG_POW) {
179        PICODBG_ERROR(("bigpow %i is larger than maxbigpow %i defined in pdf lingware", PICOKPDF_BIG_POW, maxbigpow));
180        return picoos_emRaiseException(common->em, PICO_EXC_MAX_NUM_EXCEED,NULL,NULL);
181    }
182    pdfmul->bigpow = PICOKPDF_BIG_POW; /* what we have to use is the smaller number! */
183
184    pdfmul->amplif = this->base[pos++];
185
186    /* bigpow corrected by scmeanpow, multiply means by 2^meanpow to obtain fixed point representation */
187    pdfmul->meanpow = convScaleFactorToBig(scmeanpow, pdfmul->bigpow);
188    if (0 == pdfmul->meanpow) {
189        PICODBG_ERROR(("error in convScaleFactorToBig"));
190        return picoos_emRaiseException(common->em, PICO_EXC_MAX_NUM_EXCEED,NULL,NULL);
191    }
192    nummean = 3*pdfmul->ceporder;
193
194    pdfmul->meanpowUm = picoos_allocate(common->mm,nummean*sizeof(picoos_uint8));
195    pdfmul->ivarpow = picoos_allocate(common->mm,nummean*sizeof(picoos_uint8));
196    if ((NULL == pdfmul->meanpowUm) || (NULL == pdfmul->ivarpow)) {
197        picoos_deallocate(common->mm,(void *) &(pdfmul->meanpowUm));
198        picoos_deallocate(common->mm,(void *) &(pdfmul->ivarpow));
199        return picoos_emRaiseException(common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL);
200    }
201
202    /*     read meanpowUm and convert on the fly */
203    /*     meaning of meanpowUm becomes: multiply means from pdf stream by 2^meanpowUm
204     * to achieve fixed point scaling by big
205     */
206    for (i=0; i<nummean; i++) {
207        pdfmul->meanpowUm[i] = convScaleFactorToBig(this->base[pos++], pdfmul->bigpow);
208    }
209
210   /*read ivarpow  and convert on the fly */
211    for (i=0; i<nummean; i++) {
212        pdfmul->ivarpow[i] = convScaleFactorToBig(this->base[pos++], pdfmul->bigpow);
213    }
214
215    /* check numdeltas */
216    if ((pdfmul->numdeltas == 0xFF) && (pdfmul->vecsize != (pdfmul->numvuv + pdfmul->ceporder * 3 * (2+1)))) {
217        PICODBG_ERROR(("header has inconsistent values for vecsize, ceporder, numvuv, and numdeltas"));
218        return picoos_emRaiseException(common->em,PICO_EXC_FILE_CORRUPT,NULL,NULL);
219     }
220
221/*     vecsize: 1 uint8 for vuv
222         + ceporder short for static means
223         + numdeltas uint8 and short for sparse delta means
224         + ceporder*3 uint8 for static and delta inverse variances
225*/
226    if ((pdfmul->numdeltas != 0xFF) && (pdfmul->vecsize != pdfmul->numvuv+pdfmul->ceporder*2+pdfmul->numdeltas*3+pdfmul->ceporder*3)) {
227        PICODBG_ERROR(("header has inconsistent values for vecsize, ceporder, numvuv, and numdeltas\n"
228                "vecsize = %i while numvuv+ceporder*2 + numdeltas*3 + ceporder*3 = %i",
229                pdfmul->vecsize, pdfmul->numvuv + pdfmul->ceporder*2 + pdfmul->numdeltas * 3 + pdfmul->ceporder * 3));
230        return picoos_emRaiseException(common->em,PICO_EXC_FILE_CORRUPT,NULL,NULL);
231    }
232    pdfmul->content = &(this->base[pos]);
233    PICODBG_DEBUG(("numframes %d, vecsize %d, numstates %d, ceporder %d, "
234                   "numvuv %d, numdeltas %d, meanpow %d, bigpow %d",
235                   pdfmul->numframes, pdfmul->vecsize, pdfmul->numstates,
236                   pdfmul->ceporder, pdfmul->numvuv, pdfmul->numdeltas,
237                   pdfmul->meanpow, pdfmul->bigpow));
238    if ((picoos_uint32)(pos + (pdfmul->numframes * pdfmul->vecsize)) != this->size) {
239        PICODBG_DEBUG(("header-spec size %d, kb-size %d",
240                       pos + (pdfmul->numframes * pdfmul->vecsize),
241                       this->size));
242        return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT,
243                                       NULL, NULL);
244    }
245    PICODBG_DEBUG(("mul pdf initialized"));
246    return PICO_OK;
247}
248
249static pico_status_t kpdfPHSInitialize(register picoknow_KnowledgeBase this,
250                                       picoos_Common common) {
251    picokpdf_pdfphs_t *pdfphs;
252    picoos_uint16 pos;
253
254    if (NULL == this || NULL == this->subObj) {
255        return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
256                                       NULL, NULL);
257    }
258    pdfphs = (picokpdf_pdfphs_t *)this->subObj;
259
260    pos = 0;
261
262    pdfphs->numvectors = ((picoos_uint16)(this->base[pos+1])) << 8 |
263        this->base[pos];
264    pos += 2;
265    pdfphs->indexBase = &(this->base[pos]);
266    pdfphs->contentBase = pdfphs->indexBase + pdfphs->numvectors * sizeof(picoos_uint32);
267    PICODBG_DEBUG(("phs pdf initialized"));
268    return PICO_OK;
269}
270
271
272
273static pico_status_t kpdfMULSubObjDeallocate(register picoknow_KnowledgeBase this,
274                                          picoos_MemoryManager mm) {
275
276
277    picokpdf_pdfmul_t *pdfmul;
278
279    if ((NULL != this) && (NULL != this->subObj)) {
280        pdfmul = (picokpdf_pdfmul_t *)this->subObj;
281        picoos_deallocate(mm,(void *) &(pdfmul->meanpowUm));
282        picoos_deallocate(mm,(void *) &(pdfmul->ivarpow));
283        picoos_deallocate(mm, (void *) &(this->subObj));
284    }
285    return PICO_OK;
286}
287
288static pico_status_t kpdfDURSubObjDeallocate(register picoknow_KnowledgeBase this,
289                                          picoos_MemoryManager mm) {
290    if (NULL != this) {
291        picoos_deallocate(mm, (void *) &this->subObj);
292    }
293    return PICO_OK;
294}
295
296static pico_status_t kpdfPHSSubObjDeallocate(register picoknow_KnowledgeBase this,
297                                          picoos_MemoryManager mm) {
298    if (NULL != this) {
299        picoos_deallocate(mm, (void *) &this->subObj);
300    }
301    return PICO_OK;
302}
303
304/* we don't offer a specialized constructor for a *KnowledgeBase but
305 * instead a "specializer" of an allready existing generic
306 * picoknow_KnowledgeBase */
307
308pico_status_t picokpdf_specializePdfKnowledgeBase(picoknow_KnowledgeBase this,
309                                          picoos_Common common,
310                                          const picokpdf_kpdftype_t kpdftype) {
311    pico_status_t status;
312
313    if (NULL == this) {
314        return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
315                                       NULL, NULL);
316    }
317    switch (kpdftype) {
318        case PICOKPDF_KPDFTYPE_DUR:
319            this->subDeallocate = kpdfDURSubObjDeallocate;
320            this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfdur_t));
321            if (NULL == this->subObj) {
322                return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
323                                               NULL, NULL);
324            }
325            status = kpdfDURInitialize(this, common);
326            break;
327        case PICOKPDF_KPDFTYPE_MUL:
328            this->subDeallocate = kpdfMULSubObjDeallocate;
329            this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfmul_t));
330            if (NULL == this->subObj) {
331                return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
332                                               NULL, NULL);
333            }
334            status = kpdfMULInitialize(this, common);
335            break;
336        case PICOKPDF_KPDFTYPE_PHS:
337            this->subDeallocate = kpdfPHSSubObjDeallocate;
338            this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfphs_t));
339            if (NULL == this->subObj) {
340                return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
341                                               NULL, NULL);
342            }
343            status = kpdfPHSInitialize(this, common);
344            break;
345
346        default:
347            return picoos_emRaiseException(common->em, PICO_ERR_OTHER,
348                                           NULL, NULL);
349    }
350
351    if (status != PICO_OK) {
352        picoos_deallocate(common->mm, (void *) &this->subObj);
353        return picoos_emRaiseException(common->em, status, NULL, NULL);
354    }
355    return PICO_OK;
356}
357
358
359/* ************************************************************/
360/* pdf getPdf* */
361/* ************************************************************/
362
363picokpdf_PdfDUR picokpdf_getPdfDUR(picoknow_KnowledgeBase this) {
364    return ((NULL == this) ? NULL : ((picokpdf_PdfDUR) this->subObj));
365}
366
367picokpdf_PdfMUL picokpdf_getPdfMUL(picoknow_KnowledgeBase this) {
368    return ((NULL == this) ? NULL : ((picokpdf_PdfMUL) this->subObj));
369}
370
371picokpdf_PdfPHS picokpdf_getPdfPHS(picoknow_KnowledgeBase this) {
372    return ((NULL == this) ? NULL : ((picokpdf_PdfPHS) this->subObj));
373}
374
375
376#ifdef __cplusplus
377}
378#endif
379
380
381/* end */
382