package greenfoot.importer.scratch;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Properties;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import bluej.utility.Debug;


| A sound clip, typically compressed as ADPCM. | | @author neil | public class SoundMedia extends ScratchMedia{ private static final int[] STEP_TABLE = new int[] { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; private static final int[][] INDEX_TABLE = new int[][] { null, null, new int[] {-1, 2, -1, 2 }, new int[] {-1, -1, 2, 4, -1, -1, 2, 4 }, new int[] { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }, new int[] { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 } }; private File destFile; public SoundMedia(int version, List<ScratchObject> scratchObjects) { super(SOUND_MEDIA, version, scratchObjects); } @Override public int fields() { return super.fields() + 6; } @Override public File saveInto(File destDir, Properties props, String prefix) throws IOException { if (destFile != null) return destFile; String name = getMediaName(); float sampleRate = getSampleRate(); int bitsPerSample = getBitsPerSample(); byte[] compressed = getCompressedSamples(); if (compressed == null) return null; int uncompressedSamples = (compressed.length * 8) / bitsPerSample; byte[] uncompressed = new byte[uncompressedSamples * 2]; short prev = 0; int stepIndex = 0; int step = 0; int byteIndex = 0; int bitIndex = 8 - bitsPerSample; int destSample = 0; while (byteIndex < compressed.length){ int unsignedCompressedVal; if (bitIndex > 8 - bitsPerSample) { unsignedCompressedVal = (compressed[byteIndex] >> bitIndex) & ((1 << (8 - bitIndex)) - 1); unsignedCompressedVal |= (compressed[byteIndex-1] & ((1 << (bitsPerSample - (8 - bitIndex))) - 1)) << (8 - bitIndex); } else { unsignedCompressedVal = (compressed[byteIndex] >> bitIndex) & ((1 << bitsPerSample) - 1); } if (bitIndex - bitsPerSample < 0) { byteIndex += 1; bitIndex = 8 + bitIndex - bitsPerSample; } else { bitIndex -= bitsPerSample; } stepIndex = Math.max(0,Math.min(88,stepIndex + INDEX_TABLE[bitsPerSample][unsignedCompressedVal])); int diff = 0; for (int bit = 1 << (bitsPerSample - 2); bit != 0; bit >>= 1) { if ((unsignedCompressedVal & bit) != 0) { diff += step; } step >>= 1; } if ((unsignedCompressedVal & (1 << (bitsPerSample - 1))) != 0) diff = -diff; prev = (short)Math.max(-32768, Math.min(32767, (int)prev + diff)); uncompressed[destSample * 2] = (byte)(prev >> 8); uncompressed[(destSample * 2) + 1] = (byte)(prev & 255); destSample += 1; step = STEP_TABLE[stepIndex]; } File soundsDir = new File(destDir, "sounds"); soundsDir.mkdirs(); destFile = new File(soundsDir, prefix + name + ".wav"); ByteArrayInputStream baiStream = new ByteArrayInputStream(uncompressed); AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, true); AudioInputStream aiStream = new AudioInputStream(baiStream,format,uncompressed.length); try { AudioSystem.write(aiStream,AudioFileFormat.Type.WAVE,destFile); aiStream.close(); baiStream.close(); } catch (IOException e) { Debug.reportError("Problem writing converted sound to WAV file", e); } return destFile; } private byte[] getCompressedSamples() { ScratchObject obj = scratchObjects.get(super.fields() + 5); if (obj == null) { return null; } else { return (byte[]) obj.getValue(); } } private int getBitsPerSample() { ScratchObject obj = scratchObjects.get(super.fields() + 4); if (obj == null) { return 0; } else { return ((BigDecimal)obj.getValue()).intValue(); } } private float getSampleRate() { ScratchObject obj = scratchObjects.get(super.fields() + 3); if (obj == null) { return 0; } else { return ((BigDecimal)obj.getValue()).floatValue(); } } }
top, use, map, class SoundMedia

.   SoundMedia
.   fields
.   saveInto
.   getCompressedSamples
.   getBitsPerSample
.   getSampleRate




252 neLoCode + 2 LoComm