view test/uk/ac/qmul/eecs/depic/daw/test/SoundWaveChunkTest.java @ 0:3074a84ef81e

first import
author Fiore Martin <f.martin@qmul.ac.uk>
date Wed, 26 Aug 2015 16:16:53 +0100
parents
children
line wrap: on
line source
/*  
 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.

 Copyright (C) 2015  Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
	
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.depic.daw.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.swing.SwingUtilities;

import org.junit.Before;
import org.junit.Test;

import uk.ac.qmul.eecs.depic.daw.SoundWave;
import uk.ac.qmul.eecs.depic.daw.beads.BeadsSoundEngineFactory;

@SuppressWarnings("unused")
public class SoundWaveChunkTest {
	BeadsSoundEngineFactory factory;
	SoundWave wave;
	boolean swingIsDone;

	@Before
	public void setUp() throws Exception {
		swingIsDone = false;
		factory = new BeadsSoundEngineFactory();
	}

	@Test
	public void testConstructor(){
		int[] scaleFactors = new int[] {-1,0};
		for(int scaleFactor : scaleFactors)
			try {
				
				SoundWave w1 = factory
						.setSoundWaveParameters(SoundWave.MIN_SUPPORTED_CHUNK_SIZE,scaleFactor,scaleFactor)
						.createSoundWave();
				fail();
			}catch(RuntimeException e){
				assertTrue(true);
			}
		
		/* test chunks size < MIN_SUPPORTED_CHUNK_SIZE and not a power of 2*/
		int[] chunkSizes = new int[] {-1,-16,0,10,100,SoundWave.MIN_SUPPORTED_CHUNK_SIZE+2};
		for(int size : chunkSizes)
			try {
				SoundWave w2 = factory
						.setSoundWaveParameters(size,1,1)
						.createSoundWave();
				fail("Size "+size+" allowed");
			}catch(RuntimeException e){
				assertTrue(true);
			}
		
		/* check correct chunk size > MIN_SUPPORTED_CHUNK_SIZE and power of 2*/
		chunkSizes = new int[] {SoundWave.MIN_SUPPORTED_CHUNK_SIZE,
				SoundWave.MIN_SUPPORTED_CHUNK_SIZE*2,
				SoundWave.MIN_SUPPORTED_CHUNK_SIZE*4};
		for(int size : chunkSizes)
			try {
				factory.setSoundWaveParameters(size,1,1).createSoundWave();
			}catch(RuntimeException e){
				e.printStackTrace();
				assertTrue(false);
			}
	}

	@Test
	public void testGetFrameAtChunk() {
		/* 128 samples per chunk, scale factor = 1 and 2 */
		wave = factory.setSoundWaveParameters(128,3,1).createSoundWave();
		/* by-pass the final constrain using an array */
		final AssertionError [] swingError = {null};
		try {
			SwingUtilities.invokeAndWait(new Runnable(){
				@Override
				public void run() {
					URI fileURI = null;
					try {
						fileURI = getClass().getResource("./audio/sound1.wav").toURI();
					} catch (URISyntaxException e) {
						new RuntimeException(e.getMessage()).printStackTrace();
						System.exit(-1);
					}
					wave.loadAudioData(new File(fileURI), new PropertyChangeListener(){
						@Override
						public void propertyChange(PropertyChangeEvent evt) {
							if("progress".equals(evt.getPropertyName())){
								/* only test when the file is fully loaded */
								if((Integer)evt.getNewValue() == SoundWave.FILE_LOAD_TOTAL_PROGRESS){
									try {
										/* sound1.wav file is  44100Hz, 2 bytes per frame, mono   *
										 * 0-1 and 7-8 seconds are silenced                 */
										
										byte[] audioData = AudioFileLoader.getAudioBuffer(getClass().getResource("./audio/sound1.wav")); 
										/* first second @ 8000Hz is silence */
										for(int i = 0; i * 128 < 8000; i++){
											assertEquals("chunk "+i,0,audioData[(int)wave.getFramesPositionAt(i).get(0)]);
											assertEquals("chunk "+i+" (scale = 2)",0,audioData[(int)wave.getFramesPositionAt(i).get(0)/2]);
											assertEquals("chunk "+i+" (scale = 2)",0,audioData[(int)wave.getFramesPositionAt(i).get(0)/4]);
										}
										
										/* (16min *44100)/128 = 5512.5             */
										/* 1min * 44100 = 344 chunks and 68 frames */
										/* 7th seconds @ 8000Hz is at (7 * 8000)/128 = 437 chunks + 64 frames */
										/* check a neighbourhood of 10 samples  */
										for(int i=10; i<20;i++){
											wave.setScaleFactor(1);
											assertEquals("chunk at second 7",0,audioData[(int)wave.getFramesPositionAt(437).get(0)+64+i]);
											wave.setScaleFactor(2);
											assertEquals("chunk at second 7 (scale = 2)",0,audioData[((int)wave.getFramesPositionAt(437).get(0)+64+i)/2]);
											wave.setScaleFactor(3);
											assertEquals("chunk at second 7 (scale = 3)",0,audioData[((int)wave.getFramesPositionAt(437).get(0)+64+i)/4]);
										}
										
									}catch(AssertionError e){
										swingError[0] = e;
									}finally{ //System.out.println("just after assert Equals");
										synchronized(wave){
											swingIsDone = true;
											wave.notify();
										}
									}
								}
							}else if(SoundWave.FILE_ERROR_PROPERTY.equals(evt.getPropertyName())){
								new RuntimeException("could not open file:"+evt.getNewValue()).printStackTrace();
								System.exit(-1);
							}
						}
					});
				}
			});
		} catch (InvocationTargetException | InterruptedException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		
		/* wait for the swing thread to finish. The swing thread will be finished when propertyChange with progress =  *
		 * SoundWave.FILE_LOAD_TOTAL_PROGRESS will be scheduled for execution in the EDT, by the swing worker          */
		synchronized(wave){
			while(!swingIsDone)
				try {
					wave.wait();
					/* throw the error in the JUnit thread so that it's counted */
					if(swingError[0] != null){
						assertTrue(swingError[0].getMessage(),false);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.exit(-1);
				}
		}
		
		
	}

	

}