annotate src/uk/ac/qmul/eecs/depic/daw/DbWave.java @ 4:473da40f3d39 tip

added html formatting to Daw/package-info.java
author Fiore Martin <f.martin@qmul.ac.uk>
date Thu, 25 Feb 2016 17:50:09 +0000
parents 629262395647
children
rev   line source
f@0 1 /*
f@0 2 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.
f@0 3
f@0 4 Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
f@0 5
f@0 6 This program is free software: you can redistribute it and/or modify
f@0 7 it under the terms of the GNU General Public License as published by
f@0 8 the Free Software Foundation, either version 3 of the License, or
f@0 9 (at your option) any later version.
f@0 10
f@0 11 This program is distributed in the hope that it will be useful,
f@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
f@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f@0 14 GNU General Public License for more details.
f@0 15
f@0 16 You should have received a copy of the GNU General Public License
f@0 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
f@0 18 */
f@0 19 package uk.ac.qmul.eecs.depic.daw;
f@0 20
f@0 21 import java.util.ArrayList;
f@0 22 import java.util.List;
f@0 23
f@0 24 import uk.ac.qmul.eecs.depic.patterns.MathUtils;
f@0 25 import uk.ac.qmul.eecs.depic.patterns.Range;
f@0 26 import uk.ac.qmul.eecs.depic.patterns.Sequence;
f@0 27 import uk.ac.qmul.eecs.depic.patterns.SequenceListener;
f@0 28
f@1 29 /**
f@1 30 *
f@1 31 * A Wave that displays chucks in DB scale
f@1 32 *
f@1 33 */
f@0 34 public class DbWave implements Wave {
f@0 35 private Wave soundWave ;
f@0 36 private Sequence peakLevelSequence;
f@0 37
f@0 38 public DbWave(Wave soundWave){
f@0 39 this.soundWave = soundWave;
f@0 40 }
f@0 41
f@0 42 @Override
f@0 43 public int getChunkNum() {
f@0 44 return soundWave.getChunkNum();
f@0 45 }
f@0 46
f@0 47 @Override
f@0 48 public Chunk getChunkAt(int i) {
f@0 49 return new DBChunk(soundWave.getChunkAt(i));
f@0 50 }
f@0 51
f@0 52 @Override
f@0 53 public void setScaleFactor(int scaleFactor) {
f@0 54 soundWave.setScaleFactor(scaleFactor);
f@0 55 }
f@0 56
f@0 57 @Override
f@0 58 public int getScaleFactor() {
f@0 59 return soundWave.getScaleFactor();
f@0 60 }
f@0 61
f@0 62 @Override
f@0 63 public int getMaxScaleFactor() {
f@0 64 return soundWave.getMaxScaleFactor();
f@0 65 }
f@0 66
f@0 67 @Override
f@0 68 public float getWaveTime() {
f@0 69 return soundWave.getWaveTime();
f@0 70 }
f@0 71
f@0 72 @Override
f@0 73 public float getMillisecPerChunk() {
f@0 74 return soundWave.getMillisecPerChunk();
f@0 75 }
f@0 76
f@0 77 /**
f@0 78 * Returns a sequence representing the peak meter line, if any
f@0 79 *
f@0 80 * @return the peak level sequence or {@code null} if this wave doesn't have a sequence
f@0 81 */
f@0 82 @Override
f@0 83 public Sequence getSequence(){
f@0 84 return peakLevelSequence;
f@0 85 }
f@0 86
f@0 87 public void createNewSequence(){
f@0 88 peakLevelSequence = new PeakMeterSequence(this);
f@0 89 }
f@0 90
f@0 91 public void deleteSequence(){
f@0 92 peakLevelSequence = null;
f@0 93 }
f@0 94
f@0 95 @Override
f@0 96 public boolean hasSequence(){
f@0 97 return (peakLevelSequence != null);
f@0 98 }
f@0 99
f@0 100
f@0 101 private static class PeakMeterSequence implements Sequence {
f@0 102 private static final float TAN_THETA = 1/5000.0f;
f@0 103 float previousPeak;
f@0 104 float previousPeakTime;
f@0 105 Range<Float> range;
f@0 106 List<Sequence.Value> values;
f@0 107 private float len;
f@0 108
f@0 109 PeakMeterSequence(Wave w){
f@0 110 previousPeak = 0.0f;
f@0 111 previousPeakTime = 0.0f;
f@0 112 values = new ArrayList<>(w.getChunkNum()/5);
f@0 113 range = new Range<Float>(0.0f,1.0f);
f@0 114 len = w.getChunkNum()*w.getMillisecPerChunk();
f@0 115
f@0 116 for(int i=0; i<w.getChunkNum();i++){
f@0 117 Chunk c = w.getChunkAt(i);
f@0 118 final float time = i*w.getMillisecPerChunk();
f@0 119
f@0 120 /* decayTime is the time where the previous peak was, plus the time *
f@0 121 * that the peak line will take, to decay to zero */
f@0 122 float decayTime = previousPeakTime +(previousPeak / TAN_THETA);
f@0 123
f@0 124 float peakLineDecayPoint = 0.0f;
f@0 125 /* if the peak line has already decayed to zero in the past, *
f@0 126 * peakLineDecayPoint will just be left to 0 */
f@0 127 if(time < decayTime || MathUtils.equal(time, decayTime,w.getMillisecPerChunk()/2)){
f@0 128 /* timeLeftToZero is always > 0, otherwise would not be in this block */
f@0 129 float timeLeftToZero = decayTime - time;
f@0 130 /* returns the y value of the peak line at timePoistion */
f@0 131 peakLineDecayPoint = timeLeftToZero * TAN_THETA;
f@0 132 }
f@0 133
f@0 134 if(c.getNormEnd() > peakLineDecayPoint) {
f@0 135 final int index = values.size();
f@0 136 final float value = c.getNormEnd();
f@0 137
f@0 138 /* this chunk was higher than the peak line at time *
f@0 139 * position therefore it becomes the new peak value */
f@0 140 previousPeak = value;
f@0 141 previousPeakTime = time;
f@0 142
f@0 143 values.add(new Sequence.Value() {
f@0 144 @Override
f@0 145 public int index() {
f@0 146 return index;
f@0 147 }
f@0 148
f@0 149 @Override
f@0 150 public float getValue() {
f@0 151 return value;
f@0 152 }
f@0 153
f@0 154 @Override
f@0 155 public float getTimePosition() {
f@0 156 return time;
f@0 157 }
f@0 158
f@0 159 @Override
f@0 160 public Sequence getSequence() {
f@0 161 return PeakMeterSequence.this;
f@0 162 }
f@0 163
f@0 164 @Override
f@0 165 public String toString(){
f@0 166 return "Peak meter sequence value. Value:"+getValue()+" time pos:"+getTimePosition();
f@0 167 }
f@0 168 });
f@0 169 }else if( MathUtils.equal(time, decayTime, w.getMillisecPerChunk())){
f@0 170 previousPeak = 0.0f;
f@0 171 previousPeakTime = time;
f@0 172 final int index = values.size();
f@0 173 values.add(new Sequence.Value() {
f@0 174 @Override
f@0 175 public int index() {
f@0 176 return index;
f@0 177 }
f@0 178
f@0 179 @Override
f@0 180 public float getValue() {
f@0 181 return 0.0f;
f@0 182 }
f@0 183
f@0 184 @Override
f@0 185 public float getTimePosition() {
f@0 186 return time;
f@0 187 }
f@0 188
f@0 189 @Override
f@0 190 public Sequence getSequence() {
f@0 191 return PeakMeterSequence.this;
f@0 192 }
f@0 193
f@0 194 @Override
f@0 195 public String toString(){
f@0 196 return "Peak meter sequence value. Value:"+getValue()+" time pos:"+getTimePosition();
f@0 197 }
f@0 198 });
f@0 199 }
f@0 200 }
f@0 201 }
f@0 202
f@0 203 /**
f@0 204 * Calculates the point on the time line (x-axis) where the peak curve will be completely decayed
f@0 205 * to zero.
f@0 206 *
f@0 207 * @param time the time of the decay point
f@0 208 * @param previousPeak the previous peak value. that is where the line has started decaying
f@0 209 * @param previousPeakTime the time of the previous peak value
f@0 210 *
f@0 211 * @return
f@0 212 */
f@0 213 float calculateDecayLineAtTime(float time,float previousPeak, float previousPeakTime){
f@0 214 /* decayTime is the time where the previous peak was plus the time *
f@0 215 * that the peak line will take to decay to zero */
f@0 216 float decayTime = previousPeakTime +(previousPeak / TAN_THETA);
f@0 217
f@0 218 /* the peak line has already decayed to zero in the past */
f@0 219 if(time > decayTime){
f@0 220 return 0.0f;
f@0 221 }
f@0 222
f@0 223 /* always > 0, otherwise would have returned already */
f@0 224 float timeLeftToZero = decayTime - time;
f@0 225 /* returns the y value of the peak line at timePoistion */
f@0 226 return timeLeftToZero * TAN_THETA;
f@0 227 }
f@0 228
f@0 229 @Override
f@0 230 public float getBegin() {
f@0 231 return 0.0f;
f@0 232 }
f@0 233
f@0 234 @Override
f@0 235 public float getEnd() {
f@0 236 return values.isEmpty() ? getBegin() : values.get(values.size()-1).getValue();
f@0 237 }
f@0 238
f@0 239 @Override
f@0 240 public int getValuesNum() {
f@0 241 return values.size();
f@0 242 }
f@0 243
f@0 244 @Override
f@0 245 public Value getValueAt(int index) {
f@0 246 return values.get(index);
f@0 247 }
f@0 248
f@0 249 @Override
f@0 250 public Range<Float> getRange() {
f@0 251 return range;
f@0 252 }
f@0 253
f@0 254 @Override
f@0 255 public void addSequenceListener(SequenceListener l) {
f@0 256 // this sequence is immutable, therefore listeners would never be notfied
f@0 257 }
f@0 258
f@0 259 @Override
f@0 260 public void removeSequenceListener(SequenceListener l) {
f@0 261 // this sequence is immutable, therefore listeners would never be notfied
f@0 262 }
f@0 263
f@0 264 @Override
f@0 265 public float getLen() {
f@0 266 return len;
f@0 267 }
f@0 268
f@0 269 }
f@0 270
f@0 271 }
f@0 272
f@0 273 class DBChunk extends Chunk {
f@0 274 float normStart;
f@0 275 float normEnd;
f@0 276
f@0 277 DBChunk(Chunk c) {
f@0 278 super((short)0,(short)0);
f@0 279 start = MathUtils.toDb(Math.abs(c.getStart()));
f@0 280 if(Float.isInfinite(start)){
f@0 281 start = 0.0f;
f@0 282 }
f@0 283 end = MathUtils.toDb(Math.abs(c.getEnd()));
f@0 284 if(Float.isInfinite(end)){
f@0 285 end = 0.0f;
f@0 286 }
f@0 287
f@0 288 normStart = 0.0f;
f@0 289
f@0 290 float max = Math.max(Math.abs(c.getStart()),Math.abs(c.getEnd()));
f@0 291 float db = MathUtils.toDb(max);
f@0 292 if(Float.isInfinite(db)){
f@0 293 normEnd = 0;
f@0 294 }else if(db < -60){
f@0 295 normEnd = 0;
f@0 296 }else{
f@0 297 normEnd = new MathUtils.Scale(-60.0f, 0.0f, 0.0f, 1.0f).linear(db);
f@0 298 }
f@0 299 }
f@0 300
f@0 301 @Override
f@0 302 public float getNormStart() {
f@0 303 return normStart;
f@0 304 }
f@0 305
f@0 306 @Override
f@0 307 public float getNormEnd() {
f@0 308 return normEnd;
f@0 309 }
f@0 310
f@0 311 }
f@0 312