Skip to content

Instantly share code, notes, and snippets.

@ayaysir
Last active November 7, 2018 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayaysir/09d47421dd3f72e94262a715e6cb2f67 to your computer and use it in GitHub Desktop.
Save ayaysir/09d47421dd3f72e94262a715e6cb2f67 to your computer and use it in GitHub Desktop.
audio2: controller and view
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;
}
}
<!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