| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- ###########################################
- # Project: CMSIS DSP Library
- # Title: mfccdata.py
- # Description: Generation of MFCC arays for the MFCC C init function
- #
- # $Date: 07 September 2021
- # $Revision: V1.10.0
- #
- # Target Processor: Cortex-M and Cortex-A cores
- # -------------------------------------------------------------------- */
- #
- # Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
- #
- # SPDX-License-Identifier: Apache-2.0
- #
- # Licensed under the Apache License, Version 2.0 (the License); you may
- # not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an AS IS BASIS, WITHOUT
- # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- ############################################
- import numpy as np
- from jinja2 import Environment, PackageLoader, select_autoescape,FileSystemLoader
- import os.path
- import struct
- import scipy.signal as sig
- def to_q31(v):
- r = int(round(v * 2**31))
- if (r > 0x07FFFFFFF):
- r = 0x07FFFFFFF
- if (r < -0x080000000):
- r = -0x080000000
- return ("0x%s" % format(struct.unpack('<I', struct.pack('<i', r))[0],'08X'))
- def to_q15(v):
- r = int(round(v * 2**15))
- if (r > 0x07FFF):
- r = 0x07FFF
- if (r < -0x08000):
- r = -0x08000
- return ("0x%s" % format(struct.unpack('<H', struct.pack('<h', r))[0],'04X'))
- def to_f16(v):
- return("(float16_t)%ff" % struct.unpack('<f',struct.pack('<f',v)))
- def to_f32(v):
- return("%ff" % struct.unpack('<f',struct.pack('<f',v)))
- class ConvertArray:
- def __init__(self,theType):
- self._cvt = lambda x : x
- if theType=="f32":
- self._cvt = to_f32
- if theType=="f16":
- self._cvt = to_f16
- if theType=="q31":
- self._cvt = to_q31
- if theType=="q15":
- self._cvt = to_q15
- def getArrayContent(self,samples):
- nb = 0
- res=""
- res += "{\n"
- for sample in samples:
- res += str(self._cvt(sample))
- res += ","
- nb = nb + 1
- if nb == 10:
- res += "\n"
- nb = 0
- res += "}"
- return(res)
- def frequencyToMelSpace(freq):
- return 1127.0 * np.log(1.0 + freq / 700.0)
- def melSpaceToFrequency(mels):
- return 700.0 * (np.exp(mels / 1127.0) - 1.0)
- def melFilterMatrix(fmin, fmax, numOfMelFilters,fs,FFTSize):
- filters = np.zeros((numOfMelFilters,int(FFTSize/2+1)))
- zeros = np.zeros(int(FFTSize // 2 ))
- fmin_mel = frequencyToMelSpace(fmin)
- fmax_mel = frequencyToMelSpace(fmax)
- mels = np.linspace(fmin_mel, fmax_mel, num=numOfMelFilters+2)
- linearfreqs = np.linspace( 0, fs/2.0, int(FFTSize // 2 + 1) )
- spectrogrammels = frequencyToMelSpace(linearfreqs)[1:]
- filtPos=[]
- filtLen=[]
- totalLen = 0
- packedFilters = []
- for n in range(numOfMelFilters):
-
- upper = (spectrogrammels - mels[n])/(mels[n+1]-mels[n])
- lower = (mels[n+2] - spectrogrammels)/(mels[n+2]-mels[n+1])
- filters[n, :] = np.hstack([0,np.maximum(zeros,np.minimum(upper,lower))])
- nb = 0
- startFound = False
- for sample in filters[n, :]:
- if not startFound and sample != 0.0:
- startFound = True
- startPos = nb
- if startFound and sample == 0.0:
- endPos = nb - 1
- break
- nb = nb + 1
- filtLen.append(endPos - startPos+1)
- totalLen += endPos - startPos + 1
- filtPos.append(startPos)
- packedFilters += list(filters[n, startPos:endPos+1])
- return filtLen,filtPos,totalLen,packedFilters,filters
- def dctMatrix(numOfDctOutputs, numOfMelFilters):
-
- result = np.zeros((numOfDctOutputs,numOfMelFilters))
- s=(np.linspace(1,numOfMelFilters,numOfMelFilters) - 0.5)/numOfMelFilters
- for i in range(0, numOfDctOutputs):
- result[i,:]=np.cos(i * np.pi*s) * np.sqrt(2.0/numOfMelFilters)
-
- return result
- def ctype(s):
- if s == "f64":
- return("float64_t")
- if s == "f32":
- return("float32_t")
- if s == "f16":
- return("float16_t")
- if s == "q31":
- return("q31_t")
- if s == "q15":
- return("q15_t")
- def typeext(s):
- if s == "f64":
- return("_f64")
- if s == "f32":
- return("_f32")
- if s == "f16":
- return("_f16")
- if s == "q31":
- return("_q31")
- if s == "q15":
- return("_q15")
- def prepareWindowConfig(configs):
- # sig.hamming(FFTSize, sym=False)
- for config in configs:
- c=configs[config]
- if c["win"] == "hamming":
- win = sig.hamming(c["fftlength"], sym=False)
- if c["win"] == "hanning":
- win = sig.hann(c["fftlength"], sym=False)
- cvt=ConvertArray(c["type"])
- c["ctype"]=ctype(c["type"])
- c["ext"]=typeext(c["type"])
- c["winSamples"] = cvt.getArrayContent(win)
- def prepareMelconfig(configs):
- for config in configs:
- c=configs[config]
- cvt=ConvertArray(c["type"])
- cvtInt=ConvertArray(None)
- c["ctype"]=ctype(c["type"])
- c["ext"]=typeext(c["type"])
- filtLen,filtPos,totalLen,packedFilters,filters = melFilterMatrix(c["fmin"], c["fmax"], c["melFilters"],c["samplingRate"],c["fftlength"])
-
- c["filtLenArray"]=cvtInt.getArrayContent(filtLen)
- c["filtPosArray"]=cvtInt.getArrayContent(filtPos)
- c["totalLen"]=totalLen
- c["filters"]=cvt.getArrayContent(packedFilters)
- def prepareDctconfig(configs):
- for config in configs:
- c=configs[config]
- cvt=ConvertArray(c["type"])
- c["ctype"]=ctype(c["type"])
- c["ext"]=typeext(c["type"])
- c["dctMatrixLength"]=c["dctOutputs"] * c["melFilters"]
- dctMat = dctMatrix(c["dctOutputs"],c["melFilters"])
- dctMat=dctMat.reshape(c["dctMatrixLength"])
- c["dctMatrix"]=cvt.getArrayContent(dctMat)
- #print(configs)
- def checkF16(configs):
- hasF16 = False
- for config in configs["dct"]:
- c=configs["dct"][config]
- if c["type"]=="f16":
- hasF16 = True
- c["hasF16"]=True
- for config in configs["melfilter"]:
- c=configs["melfilter"][config]
- if c["type"]=="f16":
- hasF16 = True
- c["hasF16"]=True
- for config in configs["window"]:
- c=configs["window"][config]
- if c["type"]=="f16":
- hasF16 = True
- c["hasF16"]=True
- configs["hasF16"]=hasF16
- env = Environment(
- # For 3.0 version of jinja2, replace with
- # loader=PackageLoader("mfcctemplates",""),
- loader=PackageLoader("mfccdata","mfcctemplates"),
- autoescape=select_autoescape(),
- trim_blocks=True
- )
-
- ctemplate = env.get_template("mfccdata.c")
- htemplate = env.get_template("mfccdata.h")
- def genMfccHeader(f,configs,filename):
- print(htemplate.render(configs=configs,filename=filename),file=f)
- def genMfccInit(f,configs,filename):
- print(ctemplate.render(configs=configs,filename=filename),file=f)
|