1/*
2 * Copyright (C) 2015 The Android Open Source Project
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
17package com.android.cts.verifier.audio.wavelib;
18
19public class DspWindow {
20    public DspBufferDouble mBuffer;
21    private int mWindowType = WINDOW_RECTANGULAR;
22    private int mSize;
23    private int mOverlap;
24
25    private static final double TWOPI = Math.PI * 2;
26
27    public static final int WINDOW_RECTANGULAR = 0;
28    public static final int WINDOW_TRIANGULAR = 1;
29    public static final int WINDOW_TRIANGULAR_FLAT_TOP = 2;
30    public static final int WINDOW_HAMMING = 3;
31    public static final int WINDOW_HAMMING_FLAT_TOP = 4;
32    public static final int WINDOW_HANNING = 5;
33    public static final int WINDOW_HANNING_FLAT_TOP = 6;
34
35    public DspWindow(int windowType, int size, int overlap) {
36        init(windowType, size, overlap);
37    }
38
39    public DspWindow(int windowType, int size)  {
40        init(windowType, size, size / 2);
41    }
42
43    public void init(int windowType, int size, int overlap) {
44        if (size > 0 && overlap > 0) {
45            mSize = size;
46            mOverlap = overlap;
47            if (mOverlap > mSize / 2) {
48                mOverlap = mSize / 2;
49            }
50
51            mBuffer = new DspBufferDouble(mSize);
52            if (fillWindow(mBuffer, windowType, mOverlap)) {
53                mWindowType = windowType;
54            }
55        }
56    }
57
58    public void scale(double scale) {
59        DspBufferMath.mult(mBuffer, mBuffer, scale);
60    }
61
62    public static boolean fillWindow(DspBufferDouble r, int type, int overlap) {
63        boolean status = false;
64        int size = r.getSize();
65        if (overlap > size / 2) {
66            overlap = size / 2;
67        }
68
69        switch(type) {
70            case WINDOW_RECTANGULAR:
71                status = fillRectangular(r);
72                break;
73            case WINDOW_TRIANGULAR:
74                status = fillTriangular(r, size / 2);
75                break;
76            case WINDOW_TRIANGULAR_FLAT_TOP:
77                status = fillTriangular(r, overlap);
78                break;
79            case WINDOW_HAMMING:
80                status = fillHamming(r, size / 2);
81                break;
82            case WINDOW_HAMMING_FLAT_TOP:
83                status = fillHamming(r, overlap);
84                break;
85            case WINDOW_HANNING:
86                status = fillHanning(r, size / 2);
87                break;
88            case WINDOW_HANNING_FLAT_TOP:
89                status = fillHanning(r, overlap);
90                break;
91        }
92        return status;
93    }
94
95    private static boolean fillRectangular(DspBufferDouble r) {
96        if (DspBufferMath.set(r, 1.0) == DspBufferMath.MATH_RESULT_SUCCESS) {
97            return true;
98        }
99        return false;
100    }
101
102    private static boolean fillTriangular(DspBufferDouble b, int overlap) {
103        int size = b.getSize();
104        if (overlap > size / 2) {
105            overlap = size / 2;
106        }
107
108        double value;
109        //ramp up
110        int i = 0;
111        if (overlap > 0) {
112            for (i = 0; i < overlap; i++) {
113                value = (2.0 * i + 1) / (2 * overlap);
114                b.mData[i] = value;
115            }
116        }
117
118        //flat top
119        for (; i < size - overlap; i++) {
120            b.mData[i] = 1.0;
121        }
122
123        //ramp down
124        if (overlap > 0) {
125            for (; i < size; i++) {
126                value = (2.0 * (size - i) - 1) / (2 * overlap);
127                b.mData[i] = value;
128            }
129        }
130        return true;
131    }
132
133    private static boolean fillHamming(DspBufferDouble b, int overlap) {
134        int size = b.getSize();
135        if (overlap > size / 2)
136            overlap = size / 2;
137
138        //create window, then copy
139        double value;
140
141        int twoOverlap = 2 * overlap;
142        //ramp up
143        int i = 0;
144        if (overlap > 0) {
145            for (i = 0; i < overlap; i++) {
146                value = 0.54 - 0.46 * Math.cos(TWOPI * i / (twoOverlap - 1));
147                b.mData[i] = value;
148            }
149        }
150
151        //flat top
152        for (; i < size - overlap; i++) {
153            b.mData[i] = 1.0;
154        }
155
156        //ramp down
157        int k;
158        if (overlap > 0) {
159            for (; i < size; i++) {
160                k = i - (size - 2 * overlap);
161                value = 0.54 - 0.46 * Math.cos(TWOPI * k / (twoOverlap - 1));
162                b.mData[i] = value;
163            }
164        }
165        return true;
166    }
167
168    private static boolean fillHanning(DspBufferDouble b, int overlap) {
169        int size = b.getSize();
170        if (overlap > size / 2)
171            overlap = size / 2;
172
173        //create window, then copy
174        double value;
175
176        int twoOverlap = 2*overlap;
177        //ramp up
178        int i = 0;
179        if (overlap > 0) {
180            for (i = 0; i < overlap; i++) {
181                value = 0.5 * (1.0 - Math.cos(TWOPI * i / (twoOverlap - 1)));
182                b.mData[i] = value;
183            }
184        }
185
186        //flat top
187        for (; i < size - overlap; i++) {
188            b.mData[i] = 1.0;
189        }
190
191        //ramp down
192        if (overlap > 0) {
193            for (; i < size; i++) {
194                int k = i - (size - 2 * overlap);
195                value = 0.5 * (1.0 - Math.cos(TWOPI * k / (twoOverlap - 1)));
196                b.mData[i] = value;
197            }
198        }
199        return true;
200    }
201}
202