blob: ed0a81bed4162e4c3df334822501af11c3a5c1c1 [file] [log] [blame]
Christophe Favergeone7de2432021-09-07 13:28:35 +02001###########################################
2# Project: CMSIS DSP Library
3# Title: mfccdata.py
4# Description: Generation of MFCC arays for the MFCC C init function
5#
6# $Date: 07 September 2021
7# $Revision: V1.10.0
8#
9# Target Processor: Cortex-M and Cortex-A cores
10# -------------------------------------------------------------------- */
11#
12# Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13#
14# SPDX-License-Identifier: Apache-2.0
15#
16# Licensed under the Apache License, Version 2.0 (the License); you may
17# not use this file except in compliance with the License.
18# You may obtain a copy of the License at
19#
20# www.apache.org/licenses/LICENSE-2.0
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an AS IS BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25# See the License for the specific language governing permissions and
26# limitations under the License.
27############################################
28import numpy as np
29from jinja2 import Environment, PackageLoader, select_autoescape,FileSystemLoader
30import os.path
31import struct
32import scipy.signal as sig
33
34def to_q31(v):
35 r = int(round(v * 2**31))
36 if (r > 0x07FFFFFFF):
37 r = 0x07FFFFFFF
38 if (r < -0x080000000):
39 r = -0x080000000
40 return ("0x%s" % format(struct.unpack('<I', struct.pack('<i', r))[0],'08X'))
41
42def to_q15(v):
43 r = int(round(v * 2**15))
44 if (r > 0x07FFF):
45 r = 0x07FFF
46 if (r < -0x08000):
47 r = -0x08000
48 return ("0x%s" % format(struct.unpack('<H', struct.pack('<h', r))[0],'04X'))
49
50def to_f16(v):
Christophe Favergeon285816e2021-09-09 09:11:23 +020051 return("(float16_t)%ff" % struct.unpack('<f',struct.pack('<f',v)))
Christophe Favergeone7de2432021-09-07 13:28:35 +020052
53def to_f32(v):
54 return("%ff" % struct.unpack('<f',struct.pack('<f',v)))
55
56class ConvertArray:
57 def __init__(self,theType):
58 self._cvt = lambda x : x
59 if theType=="f32":
60 self._cvt = to_f32
61 if theType=="f16":
62 self._cvt = to_f16
63 if theType=="q31":
64 self._cvt = to_q31
65 if theType=="q15":
66 self._cvt = to_q15
67
68 def getArrayContent(self,samples):
69 nb = 0
70 res=""
71 res += "{\n"
72 for sample in samples:
73 res += str(self._cvt(sample))
74 res += ","
75 nb = nb + 1
76 if nb == 10:
77 res += "\n"
78 nb = 0
79 res += "}"
80 return(res)
81
82
83
84def frequencyToMelSpace(freq):
85 return 1127.0 * np.log(1.0 + freq / 700.0)
86
87def melSpaceToFrequency(mels):
88 return 700.0 * (np.exp(mels / 1127.0) - 1.0)
89
90def melFilterMatrix(fmin, fmax, numOfMelFilters,fs,FFTSize):
91
92 filters = np.zeros((numOfMelFilters,int(FFTSize/2+1)))
93 zeros = np.zeros(int(FFTSize // 2 ))
94
95
96 fmin_mel = frequencyToMelSpace(fmin)
97 fmax_mel = frequencyToMelSpace(fmax)
98 mels = np.linspace(fmin_mel, fmax_mel, num=numOfMelFilters+2)
99
100
101 linearfreqs = np.linspace( 0, fs/2.0, int(FFTSize // 2 + 1) )
102 spectrogrammels = frequencyToMelSpace(linearfreqs)[1:]
103
104
105 filtPos=[]
106 filtLen=[]
107 totalLen = 0
108 packedFilters = []
109 for n in range(numOfMelFilters):
110
111
112 upper = (spectrogrammels - mels[n])/(mels[n+1]-mels[n])
113 lower = (mels[n+2] - spectrogrammels)/(mels[n+2]-mels[n+1])
114
115
116 filters[n, :] = np.hstack([0,np.maximum(zeros,np.minimum(upper,lower))])
117 nb = 0
118 startFound = False
119 for sample in filters[n, :]:
120 if not startFound and sample != 0.0:
121 startFound = True
122 startPos = nb
123
124 if startFound and sample == 0.0:
125 endPos = nb - 1
126 break
127 nb = nb + 1
128 filtLen.append(endPos - startPos+1)
129 totalLen += endPos - startPos + 1
130 filtPos.append(startPos)
131 packedFilters += list(filters[n, startPos:endPos+1])
132
133 return filtLen,filtPos,totalLen,packedFilters,filters
134
135
136def dctMatrix(numOfDctOutputs, numOfMelFilters):
137
138 result = np.zeros((numOfDctOutputs,numOfMelFilters))
139 s=(np.linspace(1,numOfMelFilters,numOfMelFilters) - 0.5)/numOfMelFilters
140
141 for i in range(0, numOfDctOutputs):
142 result[i,:]=np.cos(i * np.pi*s) * np.sqrt(2.0/numOfMelFilters)
143
144 return result
145
146
147def ctype(s):
148 if s == "f64":
149 return("float64_t")
150 if s == "f32":
151 return("float32_t")
152 if s == "f16":
153 return("float16_t")
154 if s == "q31":
155 return("q31_t")
156 if s == "q15":
157 return("q15_t")
158
159def typeext(s):
160 if s == "f64":
161 return("_f64")
162 if s == "f32":
163 return("_f32")
164 if s == "f16":
165 return("_f16")
166 if s == "q31":
167 return("_q31")
168 if s == "q15":
169 return("_q15")
170
171def prepareWindowConfig(configs):
172 # sig.hamming(FFTSize, sym=False)
173 for config in configs:
174 c=configs[config]
175 if c["win"] == "hamming":
176 win = sig.hamming(c["fftlength"], sym=False)
177 if c["win"] == "hanning":
178 win = sig.hann(c["fftlength"], sym=False)
179
180 cvt=ConvertArray(c["type"])
181 c["ctype"]=ctype(c["type"])
182 c["ext"]=typeext(c["type"])
183
184 c["winSamples"] = cvt.getArrayContent(win)
185
186def prepareMelconfig(configs):
187 for config in configs:
188 c=configs[config]
189
190 cvt=ConvertArray(c["type"])
191 cvtInt=ConvertArray(None)
192 c["ctype"]=ctype(c["type"])
193 c["ext"]=typeext(c["type"])
194
195 filtLen,filtPos,totalLen,packedFilters,filters = melFilterMatrix(c["fmin"], c["fmax"], c["melFilters"],c["samplingRate"],c["fftlength"])
196
197 c["filtLenArray"]=cvtInt.getArrayContent(filtLen)
198 c["filtPosArray"]=cvtInt.getArrayContent(filtPos)
199 c["totalLen"]=totalLen
200 c["filters"]=cvt.getArrayContent(packedFilters)
201
202def prepareDctconfig(configs):
203 for config in configs:
204 c=configs[config]
205
206 cvt=ConvertArray(c["type"])
207 c["ctype"]=ctype(c["type"])
208 c["ext"]=typeext(c["type"])
209 c["dctMatrixLength"]=c["dctOutputs"] * c["melFilters"]
210
211 dctMat = dctMatrix(c["dctOutputs"],c["melFilters"])
212 dctMat=dctMat.reshape(c["dctMatrixLength"])
213 c["dctMatrix"]=cvt.getArrayContent(dctMat)
214
215 #print(configs)
216
Christophe Favergeon285816e2021-09-09 09:11:23 +0200217def checkF16(configs):
218 hasF16 = False
219 for config in configs["dct"]:
220 c=configs["dct"][config]
221 if c["type"]=="f16":
222 hasF16 = True
223 c["hasF16"]=True
224
225 for config in configs["melfilter"]:
226 c=configs["melfilter"][config]
227 if c["type"]=="f16":
228 hasF16 = True
229 c["hasF16"]=True
230
231 for config in configs["window"]:
232 c=configs["window"][config]
233 if c["type"]=="f16":
234 hasF16 = True
235 c["hasF16"]=True
236
237 configs["hasF16"]=hasF16
238
Christophe Favergeone7de2432021-09-07 13:28:35 +0200239env = Environment(
Christophe Favergeondca56052021-10-15 09:54:05 +0200240 # For 3.0 version of jinja2, replace with
241 # loader=PackageLoader("mfcctemplates",""),
Christophe Favergeone7de2432021-09-07 13:28:35 +0200242 loader=PackageLoader("mfccdata","mfcctemplates"),
243 autoescape=select_autoescape(),
244 trim_blocks=True
245 )
246
247ctemplate = env.get_template("mfccdata.c")
248htemplate = env.get_template("mfccdata.h")
249
250
251def genMfccHeader(f,configs,filename):
252 print(htemplate.render(configs=configs,filename=filename),file=f)
253
254def genMfccInit(f,configs,filename):
255 print(ctemplate.render(configs=configs,filename=filename),file=f)