Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package commands; | ||
|
||
import kr.ac.ajou.dv.musicfinder.analyzer.InvalidWaveFormatException; | ||
import kr.ac.ajou.dv.musicfinder.analyzer.WaveHandler; | ||
import kr.ac.ajou.dv.musicfinder.lib.DbSaveWorker; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FilenameFilter; | ||
import java.io.IOException; | ||
import java.util.Properties; | ||
|
||
public class MusicAnalyzer { | ||
public static final String TEMPORARY_WAVE = "temp.wav"; | ||
|
||
public static void main(String[] args) { | ||
Properties config = new Properties(); | ||
try { | ||
config.load(new FileInputStream("analyzer.conf")); | ||
} catch (IOException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} | ||
File mp3dir = new File(config.getProperty("mp3_directory")); | ||
String soxParams = config.getProperty("sox_parameters"); | ||
|
||
WaveHandler wh = new WaveHandler(); | ||
DbSaveWorker dbSaveWorker = new DbSaveWorker(); | ||
|
||
for (File f : mp3dir.listFiles(new FilenameFilter() { | ||
@Override | ||
public boolean accept(File dir, String name) { | ||
return !dir.getName().endsWith(name); | ||
} | ||
})) { | ||
if (!f.isDirectory() && f.getName().toLowerCase().endsWith(".mp3")) { | ||
String songName = f.getName().substring(0, f.getName().length() - 4); | ||
System.out.println(songName); | ||
String command = "sox '" + f.getName() + "' " + soxParams + " '" + TEMPORARY_WAVE + "'"; | ||
ProcessBuilder pb = new ProcessBuilder("bash", "-c", command); | ||
pb.directory(mp3dir); | ||
try { | ||
Process p = pb.start(); | ||
int exitValue = p.waitFor(); | ||
System.out.println("Converting to a Wave has been done (exit status: " + exitValue + ")"); | ||
|
||
File wav = new File(mp3dir + File.separator + TEMPORARY_WAVE); | ||
if (wav.exists()) { | ||
dbSaveWorker.addSong(songName); | ||
wh.handle(wav, dbSaveWorker); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} catch (InvalidWaveFormatException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package commands; | ||
|
||
import kr.ac.ajou.dv.musicfinder.analyzer.InvalidWaveFormatException; | ||
import kr.ac.ajou.dv.musicfinder.analyzer.WaveHandler; | ||
import kr.ac.ajou.dv.musicfinder.lib.DbQueryWorker; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.SortedMap; | ||
|
||
public class MusicFinder { | ||
public static void main(String[] args) { | ||
File queryFile = new File("query/query-shining.wav"); | ||
|
||
WaveHandler wh = new WaveHandler(); | ||
DbQueryWorker dbQueryWorker = new DbQueryWorker(); | ||
|
||
try { | ||
wh.handle(queryFile, dbQueryWorker); | ||
SortedMap<Integer, List<Integer>> ranking = dbQueryWorker.getPoints(); | ||
for (int point : ranking.keySet()) { | ||
System.out.print(point + " points: "); | ||
for (int songId : ranking.get(point)) { | ||
System.out.print(songId + " "); | ||
} | ||
System.out.println(); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} catch (InvalidWaveFormatException e) { | ||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | ||
} | ||
} | ||
} | ||
|
13 changes: 13 additions & 0 deletions
13
WaveAnalyzer/src/kr/ac/ajou/dv/musicfinder/analyzer/InvalidWaveFormatException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package kr.ac.ajou.dv.musicfinder.analyzer; | ||
|
||
/** | ||
* Created with IntelliJ IDEA. | ||
* User: dvlab | ||
* Date: 11/7/12 | ||
* Time: 3:15 PM | ||
* To change this template use File | Settings | File Templates. | ||
*/ | ||
public class InvalidWaveFormatException extends Throwable { | ||
public InvalidWaveFormatException(String s) { | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
WaveAnalyzer/src/kr/ac/ajou/dv/musicfinder/analyzer/WaveHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package kr.ac.ajou.dv.musicfinder.analyzer; | ||
|
||
import kr.ac.ajou.dv.musicfinder.lib.DbWorker; | ||
import kr.ac.ajou.dv.musicfinder.lib.FftHelper; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.nio.ByteBuffer; | ||
import java.nio.ByteOrder; | ||
import java.util.concurrent.ArrayBlockingQueue; | ||
|
||
public class WaveHandler { | ||
public static final int CHUNK_SIZE = 4096; | ||
public static final int WINDOW_SIZE = 16; | ||
public static final int SUB_CHUNK_SIZE = (CHUNK_SIZE / WINDOW_SIZE); | ||
public static final int SHORT_BYTES = (Short.SIZE / Byte.SIZE); | ||
public static final int NUMBER_OF_SAMPLES = (CHUNK_SIZE / SHORT_BYTES); | ||
|
||
public void handle(File wav, DbWorker dbWorker) throws IOException, InvalidWaveFormatException { | ||
FileInputStream fis = new FileInputStream(wav); | ||
byte[] header = new byte[36]; | ||
|
||
fis.read(header); | ||
if (!new String(header, 0, 4).equals("RIFF")) | ||
throw new InvalidWaveFormatException("This file does not conform RIFF."); | ||
|
||
if (!new String(header, 8, 4).equals("WAVE")) | ||
throw new InvalidWaveFormatException("This is not a WAVE file."); | ||
|
||
String subChunk1Id = new String(header, 12, 4); | ||
int subChunk1Size = ByteBuffer.wrap(header, 16, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(); | ||
short audioFormat = ByteBuffer.wrap(header, 20, 2).order(ByteOrder.LITTLE_ENDIAN).getShort(); | ||
short numChannels = ByteBuffer.wrap(header, 22, 2).order(ByteOrder.LITTLE_ENDIAN).getShort(); | ||
int sampleRate = ByteBuffer.wrap(header, 24, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(); | ||
short bitsPerSample = ByteBuffer.wrap(header, 34, 2).order(ByteOrder.LITTLE_ENDIAN).getShort(); | ||
|
||
if (!subChunk1Id.equals("fmt ") || | ||
subChunk1Size != 16 || | ||
audioFormat != 1 || | ||
numChannels != 1 || | ||
sampleRate != 32000 || | ||
bitsPerSample != 16) | ||
throw new InvalidWaveFormatException("Invalid 'fmt' sub-chunk."); | ||
|
||
byte[] subChunk2Header = new byte[8]; | ||
fis.read(subChunk2Header); | ||
|
||
String subChunk2Id = new String(subChunk2Header, 0, 4); | ||
if (!subChunk2Id.equals("data")) | ||
throw new InvalidWaveFormatException("Invalid 'data' sub-chunk."); | ||
|
||
ArrayBlockingQueue<byte[]> queue = new ArrayBlockingQueue<byte[]>(WINDOW_SIZE); | ||
|
||
int position = 0; | ||
while (true) { | ||
byte[] subChunk = new byte[SUB_CHUNK_SIZE]; | ||
if (fis.read(subChunk) < SUB_CHUNK_SIZE) break; | ||
// In an initial state, the queue is not filled. We need the full 8 sub-chunks for the FFT transform. | ||
if (queue.offer(subChunk)) continue; | ||
queue.poll(); | ||
queue.offer(subChunk); | ||
|
||
byte[] chunk = new byte[CHUNK_SIZE]; | ||
int offset = 0; | ||
for (byte[] b : queue) { | ||
System.arraycopy(b, 0, chunk, offset, SUB_CHUNK_SIZE); | ||
offset += SUB_CHUNK_SIZE; | ||
} | ||
ByteBuffer sampleBuffer = ByteBuffer.wrap(chunk).order(ByteOrder.LITTLE_ENDIAN); | ||
|
||
short[] pcm = new short[NUMBER_OF_SAMPLES]; | ||
for (int i = 0; i < NUMBER_OF_SAMPLES; i++) | ||
pcm[i] = sampleBuffer.getShort(); | ||
|
||
int[] intensivePoints = FftHelper.getIntensivePointsAfterFft(pcm); | ||
dbWorker.work(position++, DbWorker.fuzz(intensivePoints)); | ||
} | ||
} | ||
} |