Last active
November 7, 2018 13:48
-
-
Save ayaysir/09d47421dd3f72e94262a715e6cb2f67 to your computer and use it in GitHub Desktop.
audio2: controller and view
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
import java.io.PrintWriter; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import javax.servlet.http.HttpServletResponse; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.CrossOrigin; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import com.google.gson.Gson; | |
import com.springboot.morse.util.MinimImpl; | |
import ddf.minim.AudioPlayer; | |
import ddf.minim.AudioSample; | |
import ddf.minim.Minim; | |
import ddf.minim.analysis.FFT; | |
@Controller | |
@CrossOrigin(origins = "*") | |
public class SoundController { | |
@RequestMapping("/sound") | |
public void freqVisualizer(HttpServletResponse res){ | |
try { | |
res.setContentType("text/json"); | |
Minim minim = MinimImpl.getMinimInstance(); | |
AudioSample jingle = minim.loadSample("pastorale.mp3", 2048); | |
// get the left channel of the audio as a float array | |
// getChannel is defined in the interface BuffereAudio, | |
// which also defines two constants to use as an argument | |
// BufferedAudio.LEFT and BufferedAudio.RIGHT | |
float[] leftChannel = jingle.getChannel(AudioSample.LEFT); | |
System.out.println("channel length: " + leftChannel.length); | |
System.out.println("length / 500: " + (leftChannel.length / 500) ); | |
System.out.println("near pow2: " + (tempPowerOfTwo(leftChannel.length / 500) )); | |
// timeSize는 2의 제곱만 허용하기 때문에 사이즈에서 제일 가까운(그러나 작으면 안됨) 2의 제곱수를 찾는다. | |
// then we create an array we'll copy sample data into for the FFT object | |
// this should be as large as you want your FFT to be. generally speaking, 1024 is probably fine. | |
int fftSize = (int)(tempPowerOfTwo(leftChannel.length / 500)); | |
float[] fftSamples = new float[fftSize]; | |
System.out.println("sample rate: " + jingle.sampleRate()); | |
FFT fft = new FFT( fftSize, jingle.sampleRate() ); | |
// now analyze this buffer | |
fft.forward( fftSamples ); | |
// now we'll analyze the samples in chunks | |
int totalChunks = (leftChannel.length / fftSize) + 1; | |
System.out.println("totalChunks: " + totalChunks); | |
List<Double> outputFreqArr = new ArrayList<>(); | |
Map<String, Object> outputMap = new HashMap<String, Object>(); | |
// allocate a 2-dimensional array that will hold all of the spectrum data for all of the chunks. | |
// the second dimension if fftSize/2 because the spectrum size is always half the number of samples analyzed. | |
float[][] spectra = new float[totalChunks][fftSize/2]; | |
for(int chunkIdx = 0; chunkIdx < totalChunks; ++chunkIdx) | |
{ | |
int chunkStartIndex = chunkIdx * fftSize; | |
// the chunk size will always be fftSize, except for the | |
// last chunk, which will be however many samples are left in source | |
int chunkSize = Math.min( leftChannel.length - chunkStartIndex, fftSize ); | |
// copy first chunk into our analysis array | |
System.arraycopy( leftChannel, // source of the copy | |
chunkStartIndex, // index to start in the source | |
fftSamples, // destination of the copy | |
0, // index to copy to | |
chunkSize // how many samples to copy | |
); | |
// if the chunk was smaller than the fftSize, we need to pad the analysis buffer with zeroes | |
if ( chunkSize < fftSize ) | |
{ | |
// we use a system call for this | |
Arrays.fill( fftSamples, chunkSize, fftSamples.length - 1, 0.0F ); | |
} | |
// now analyze this buffer | |
fft.forward( fftSamples ); | |
// and copy the resulting spectrum into our spectra array | |
for(int i = 0; i < (fftSize / 2); ++i) | |
{ | |
spectra[chunkIdx][i] = fft.getBand(i); | |
} | |
} | |
jingle.close(); | |
double max = -1; | |
double min = 99; | |
for(int i = 0; i < spectra.length; i++) { | |
double sum = 0; | |
for(int j = 0; j < spectra[i].length; j++) { | |
// System.out.print(spectra[i][j] + " "); | |
sum += spectra[i][j]; | |
} | |
double ele = (sum / spectra[i].length); | |
outputFreqArr.add( ele ); | |
if(max < ele) { | |
max = ele; | |
} else if (min > ele){ | |
min = ele; | |
} | |
} | |
System.out.println("max: " + max); | |
System.out.println("min: " + min); | |
outputMap.put("max", max); | |
outputMap.put("min", min); | |
outputMap.put("totalChunks;", totalChunks); | |
outputMap.put("outputFreqArr", outputFreqArr); | |
String json = new Gson().toJson(outputMap); | |
System.out.println(json); | |
PrintWriter xout = res.getWriter(); | |
xout.print(json); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
public double tempPowerOfTwo(double numThatNotPowerOfTwo){ | |
double[] numList = new double[36]; | |
for(int power = 1; power <= 36; power++) { | |
numList[power - 1] = (long) Math.pow(2, power); | |
} | |
double nearNum = 0; | |
for(int i = 0; i < numList.length; i++) { | |
if (numThatNotPowerOfTwo >= numList[35]) { | |
nearNum = numList[35]; | |
break; | |
} else if(numList[i] < numThatNotPowerOfTwo) { | |
continue; | |
} else if (numList[i] == numThatNotPowerOfTwo) { | |
nearNum = numList[i]; | |
break; | |
} else { | |
nearNum = numList[i - 1]; | |
break; | |
} | |
} | |
return nearNum; | |
} | |
} |
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
<!DOCTYPE html> | |
<html lang="ko"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>주파수 그리기</title> | |
<style type="text/css"> | |
canvas { | |
border: 1px solid black; | |
} | |
</style> | |
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> | |
</head> | |
<body onload="draw();"> | |
<canvas id="tutorial" width="748" height="300"> | |
캔버스를 지원하지 않는 브라우저입니다. | |
</canvas> | |
<p id=loading>로딩중...</p> | |
<script> | |
function draw() { | |
$.get("http://localhost:8080/sound", function(data) { | |
var canvas = document.getElementById('tutorial') | |
if (canvas.getContext) { | |
var ctx = canvas.getContext('2d'); | |
console.log(data) | |
$('#tutorial').attr('width', data.totalChunks) | |
ctx.fillStyle = "rgb(200,0,0)"; | |
// x는 10 너비에 0부터 10씩 증가, y는 (300 - 길이) 에서 시작 | |
var freqArray = data.outputFreqArr | |
console.log(freqArray) | |
var max = data.max | |
for (var i in freqArray) { | |
var colorString = "rgb(" + Math.floor(Math.random() * 200) + "," + | |
Math.floor(Math.random() * 200) + "," + Math.floor(Math.random() * 200) + ")" | |
ctx.fillStyle = colorString | |
ctx.fillRect(i * 1, 300 - (freqArray[i] / max) * 250, 1, (freqArray[i] / max) * 250) | |
} | |
} else { | |
// canvas-unsupported code here | |
} | |
}) | |
} | |
var loading = $("#loading"); | |
$(document).ajaxStart(function () { | |
loading.show(); | |
}); | |
$(document).ajaxStop(function () { | |
loading.hide(); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment