I'm trying to make a PShape SVG multipy. I want a new shape created every time a variable (that I'm importing from a CSV file) changes. I tried using a for, but it doesn`t respect the variable range I'm giving it, it just creates as many SVGs as it wants. Basically what I'm trying to do is that if the variable indicates there are 21 data between an X rage, draw 21 copies of the SVG in a fixed distance between one and other.
Table table;
PShape tipi2;
PShape tipi3;
void setup() {
size (1875, 871);
table = loadTable("WHO.csv", "header");
tipi2 = loadShape("tipi-02.svg");
}
void draw() {
background(0);
for (TableRow row : table.rows()) {
int hale = row.getInt("Healthy life expectancy (HALE) at birth (years) both sexes");
}
tipi2.disableStyle();
noStroke();
for( int i = 0 ;i<=1800;i=i+33){
pushMatrix();
translate(0,89.5);
if(hale > 40 && hale < 60){
shape(tipi2,i,0);
popMatrix();
}
}
There are a couple of things that couple things that could be improved in your current code:
the hale variable's visibility (or scope) is only within this loop: for (TableRow row : table.rows()) {
the drawing styles (noStroke()/disableStyle(),etc.) don't change much therefore could e set once in setup() rather than multiple times a second in draw()
you could move the for loop from 0 to 1800 inside the for (TableRow row : table.rows()) { loop, but that might not be very efficient:
Here's what I mean:
Table table;
PShape tipi2;
PShape tipi3;
void setup() {
size (1875, 871);
table = loadTable("WHO.csv", "header");
tipi2 = loadShape("tipi-02.svg");
//this styles could be set once in setup, rather than multiple times in draw();
tipi2.disableStyle();
noStroke();
background(0);
for (TableRow row : table.rows()) {
int hale = row.getInt("Healthy life expectancy (HALE) at birth (years) both sexes");
for ( int i = 0; i<=1800; i=i+33) {
pushMatrix();
translate(0, 89.5);
//hale is visible within this scope, but not outside the for loop
if (hale > 40 && hale < 60) {
shape(tipi2, i, 0);
}
//popMatrix(); should be called the same amount of times as pushMatrix
popMatrix();
}
}
}
void draw() {
}
Related
I am making a dice generator, which rolls 2 dices a thousand times and gives the output to an array, which is then displayed as bar charts on the graphic output. Now i want to add the dice numbers at the bottom of the chart (and also turn the chart around ), but it doesnt seem like i get any output [this line-> text(String.format("%s",i),i+w*(width/11),280,(width/11),280); ]. Did i place it in the wrong function, because the code should work like that( i ve adapted it from a previous project). [my dice has the numbers 0-5 on it just so i dont get that confused by the array starting at 0, im still fairly new to that]. Thank you in advance!
import java.util.Random;
Random rg = new Random();
final int N=1000;
void setup(){
println(f);
println(p);
size(700,500);
background(255);
}
int [] f=countDice2(N);
float[] p= getProbabilities(f);
int [] countDice2(int N){
int[] f = new int [11];
for(int i =0; i<N;i++){
int k =rg.nextInt(6);
int u= rg.nextInt(6);
int t =u+k;
f[t] +=1;
}
return f;
}
float[] getProbabilities(int[] f){
int n=0;
for(int j=0; j< f.length; j++){
n=n+f[j];
}
float[] prob=new float[f.length];
for(int i=0; i<f.length;i++){
prob[i]= (float)f[i]/n;
}
return prob;
}
void plotProbabilities(){
for( int i =0, w =0;w<=11 && i< 11; i++, w++){
//fill(0,255,0);
rect(i+w*(width/11) ,300,(width/11),f[0+i]);
}
}
void draw(){
plotProbabilities();
for( int i =0, w =0;w<=11 && i< 11; i++, w++){
text(String.format("%s",i),i+w*(width/11),280,(width/11),280);
}
}
Your mistake is very simple: you're writing in white.
Look how I found out:
void draw() {
plotProbabilities();
for ( int i =0, w =0; w<=11 && i< 11; i++, w++) {
fill(0);
text("" + i, i+w*(width/11), 280, (width/11), 280);
}
}
Think of fill() as changing pencil: everything you do after will use the new pencil, so the new color. If you draw several different things with their own color, you have to specify the fill color for every one.
You nailed it. This is just a small mistake.
Have fun!
I want to make something like Terraria item sidebar thing. (the Left-top rectangles one). And here is my code.
Variables are
public Rectangle InventorySlots;
public Item[] Quickbar = new Item[9];
public Item mouseItem = null;
public Item[] Backpack = new Item[49];
public int selectedBar = 0;
Here is the initialization
inventory[0] = Content.Load<Texture2D>("Contents/Overlays/InventoryBG");
inventory[1] = Content.Load<Texture2D>("Contents/Overlays/InventoryBG2");
update method
int a = viewport.Width / 22;
for (int b = 0; b <= Quickbar.Length; ++b)
{
InventorySlots = new Rectangle(((a/10)*b)+(b),0,a,a);
}
draw method
spriteBatch.Begin();
for (int num = 0; num <= Quickbar.Length; ++num )
spriteBatch.Draw(inventory[0], InventorySlots, Color.White);
spriteBatch.Draw(inventory[1], InventorySlots, Color.White);
spriteBatch.End();
Yes it is not done, but when i try to run it, the texture didn't show up.
I am unable to find out what is wrong in my code.
is it in with SpriteBatch? In the draw method? or In the Update?
Resolved
The problem isnt at the code Itself. the Problem is in this:
int a = viewport.Width / 22;
The thing is, i trought that viewport in here (I've used a Starter Kit) is the Game Window!
You are assigning InventorySlots overwriting its content...
also it seems that you want to draw two sprites... but you are drawing only one inside the loop... and your looping over Quickbar when seems that its not related with your drawing calls.
And it seems that your slot layout calculations have few sense...
You should use an array or a list:
public List<Rectangle> InventorySlots = new List<Rectangle>();
// You put this code in update... but it's not going to change..
// maybe initialize is best suited
// Initialize
int a = viewport.Width / 22;
InventorySlots.Clear();
for (int b = 0; b < Quickbar.Length; ++b)
{ // Generate slots in a line, with a pixel gap among them
InventorySlots.Add( new Rectangle( 1 + (a+2) * b ,0,a,a) );
}
//Draw
spriteBatch.Begin();
for (int num = 0; num < InventorySlots.Count; ++num )
{
spriteBatch.Draw(inventory[0], InventorySlots[num], Color.White);
spriteBatch.Draw(inventory[1], InventorySlots[num], Color.White);
}
spriteBatch.End();
To begin with I am using the Chili Framework for lessons 1-15 as downloadable here:
http://www.planetchili.net/
I am using DirectX 9 on an old laptop running Windows XP SP3. I have set the Direct3D rendering to software in order to run the framework. I am using Visual Studio Express C++ 2010 with the first service pack installed.
This is the code I am having trouble with:
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
Now Chili's solution is to move along the y axis while checking for x, and x while checking for y. I may post that later, don't have it readily available. You can see it at the beginning of this video:
http://youtu.be/JEmwkQsi8l0
However I wanted to do this logically, as if I was walking the border along an invisible wall inside a box. I wanted it to make sense what was going on. But the cursor won't move, and I see no reason why it doesn't. Here is my game.h:
#pragma once
#include "D3DGraphics.h"
#include "Keyboard.h"
class Game
{
public:
Game( HWND hWnd,const KeyboardServer& kServer );
void Go();
private:
void ComposeFrame();
/********************************/
/* User Functions */
void DrawReticle(int xP, int yP, int cR, int cG, int cB);
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
// TODO: User functions go here
/********************************/
private:
D3DGraphics gfx;
KeyboardClient kbd;
/********************************/
/* User Variables */
int pointA; // Starting at pointA (100, 100) - the top left
int pointAb; // Move from pointA to pointAb (700, 100) - the top right
int pointBc; // Move from pointAb to pointBc (700, 500) - the bottom right
int pointCd; // Move from pointBc to pointCd (100,500) - the bottom left
int pointDa; // Move from pointCd to pointDa (100,100) - the top left
/*
These points describe the process of starting, then four movements. The four points are A, B, C, D. We start at A, then go to B (pointAb, read as A to b), then go to C (pointBc, read as B to c), then go to D (pointCd, read as C to d) then go to A (pointDa, read as D to a).
This can be very confusing, because there are five varibles used. But if we drew it out there would only four points, as well as only four movements. The best way to think of it is that starting is itself a movement, and as you need a place to start from, it itself must have a point. Since you start at A, but haven't yet gone anywhere, pointA is our starting point. Once you start moving, you go from pointA to pointB. Now if we used pointB as our variable it would be confusing,because we would have to move from pointA to pointB to pointC to pointD and then back to pointA. Still five variables, one is repeating, but the first pointA describes where you start, and the last where you end. Since these are two different actions on the same point, I have elected to use two letter names for each of the points you move to, while the point you start at has a single letter name. It was the best way I could clearly think about this process.
*/
int itemLocX; // Initial position of item on the x axis
int itemLocY; // Initial position of item on the y axis
int reticleX; // Initial position of reticle on the x axis
int reticleY; // Initial position of reticle on the y axis
// TODO: User variables go here
/********************************/
};
Here is my game.cpp:
#include "Game.h"
Game::Game( HWND hWnd,const KeyboardServer& kServer )
: gfx(hWnd),
kbd(kServer),
itemLocX(100), // Initial position of item on the x axis
itemLocY(100), // Initial position of item on the y axis
reticleX(400), // Initial position of reticle on the x axis
reticleY(300), // Initial position of reticle on the y axis
pointA(100), // Movement from 0 to A, stopping at A
pointAb(700), // Movement from A to b, stopping at B
pointBc(500), // Movement from B to c, stopping at C
pointCd(700), // Movement from C to d, stopping at D
pointDa(500) // Movement from D to a, stopping at A
{}
void Game::Go()
{
gfx.BeginFrame();
ComposeFrame();
gfx.EndFrame();
}
void Game::DrawReticle(int xP, int yP, int cR, int cG, int cB)
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
{
gfx.PutPixel(xP-5,yP,cR,cG,cB);
gfx.PutPixel(xP-4,yP,cR,cG,cB);
gfx.PutPixel(xP-3,yP,cR,cG,cB);
gfx.PutPixel(xP+3,yP,cR,cG,cB);
gfx.PutPixel(xP+4,yP,cR,cG,cB);
gfx.PutPixel(xP+5,yP,cR,cG,cB);
gfx.PutPixel(xP,yP,cR,cG,cB);
gfx.PutPixel(xP,yP-5,cR,cG,cB);
gfx.PutPixel(xP,yP-4,cR,cG,cB);
gfx.PutPixel(xP,yP-3,cR,cG,cB);
gfx.PutPixel(xP,yP+3,cR,cG,cB);
gfx.PutPixel(xP,yP+4,cR,cG,cB);
gfx.PutPixel(xP,yP+5,cR,cG,cB);
}
void Game::ComposeFrame()
{
// Start draw reticle code
DrawReticle(reticleX, reticleY, 100, 155, 255);
// End draw reticle code
// Start color change code
int yT = 200; // Border 200 pixels from top
int yB = 400; // Border 200 pixels from bottom
int xL = 300; // Border 200 pixels from left
int xR = 500; // Border 200 pixels from right
if(reticleX < xL || reticleX > xR) // Defining color change area for X
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
if(reticleY < yT || reticleY > yB) // Defining color change area for Y
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
// End color change code
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
// Start border code
if(reticleX < 6)
{
reticleX = 6;
}
else if(reticleX > 794)
{
reticleX = 794;
}
if(reticleY < 6)
{
reticleY = 6;
}
else if(reticleY > 594)
{
reticleY = 594;
}
// End border code
// Start speed change code
int cSpeed = 4; // Default cursor speed
if(kbd.EnterIsPressed()) // Change to high speed
{
cSpeed = 8;
}
if(kbd.SpaceIsPressed()) // Change to low speed
{
cSpeed = 1;
}
if(kbd.RightIsPressed())
{
reticleX += cSpeed;
}
if(kbd.LeftIsPressed())
{
reticleX -= cSpeed;
}
if(kbd.UpIsPressed())
{
reticleY -= cSpeed;
}
if(kbd.DownIsPressed())
{
reticleY += cSpeed;
}
// End speed change code
}
Now I should note here that this should be done without functions and only the basic C++ operators. That's as far as Chili has taught to this point. This is my second attempt to solve this myself, after hours thinking about it and working on it on paper. I'm stuck. Just not seeing it. I think there is a logic error here on my part. I want to understand where my thinking may be mistaken, but more than that, how to think correctly, like the computer, about this.
I am also open to advice regarding my coding style. If I am not being clear enough, or am doing something that should not become a bad habit - basically if there is something I should be doing differently in writing my code I would like to know about it.
Thank you for your help - it is very much appreciated!
I see how you have tried to do this. Personally you have over complexed it.
1: you don't need the != operator in your if statements.
2: try this:
if(itemLocX < 700)
{
itemLocX += 2;
}
3: This worked fine during testing. Another point is that the if statements could be in the wrong order. I changed it to the order in which it moved across the screen in. I have X Y X Y and you have X X Y Y. (unconfirmed) It executes the if statements in order. I have hard coded the answer. set them to variables if you really want to. Hope this helped!
I'm trying to create a scrollView, but I don't know how to determine the maximum range of the scroll (or even better, the maximum scroll position).
This is what I have tried to do without any positive results:
void Update()
{
//get the amount of space that my text is taking
textSize = gs.CalcHeight(new GUIContent(text), (screenWidth/2));
if(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(0).tapCount==1)
{
var touch = Input.touches[0];
//check if touch is within the scrollView area
if(touch.position.x >= (screenWidth/2) && touch.position.x <= (screenWidth) && touch.position.y >= 0 && touch.position.y <= (screenHeight))
{
if(touch.phase == TouchPhase.Moved)
{
scrollPosition[1] += touch.deltaPosition.y;
if(scrollPosition[1] < 0)
{
scrollPosition[1] = 0;
}
//I subtracted this cause i read that the scrollbars take 16px
if(scrollPosition[1] > (textSize-scrollViewRect.yMax-16)) //scrollViewRect is a Rect with the size of my scrollView
{
scrollPosition[1] = textSize-scrollViewRect.yMax-16;
}
}
}
}
}
void OnGUI()
{
screenWidth = camera.pixelWidth;
screenHeight = camera.pixelHeight;
GUILayout.BeginArea(new Rect(screenWidth/2, 0, screenWidth/2, screenHeight));
GUILayout.BeginScrollView(scrollPosition/*, GUILayout.Width (screenWidth/2), GUILayout.Height (screenHeight/2)*/, "box");
GUILayout.Label (new GUIContent(text), gs);
// End the scrollview
GUILayout.EndScrollView ();
scrollViewRect = GUILayoutUtility.GetLastRect();
GUILayout.EndArea();
}
This was done assuming that the scrollView is on the right half of the screen.
Can you guys help me out on this?
Thanks in advance.
As shown in the API documentation for GUI.BeginScrollView, you can assign a Vector2 to the declaration of BeginScrollView to track and update where the box has been scrolled to.
I'll give an example:
using UnityEngine;
using System.Collections;
public class ScrollSize : MonoBehaviour {
private int screenBoxX = Screen.width;
private int screenBoxY = Screen.height;
private int scrollBoxX = Screen.width * 2;
private int scrollBoxY = Screen.height * 3;
public Vector2 scrollPosition = Vector2.zero;
void Awake()
{
Debug.Log ("box size is " + scrollBoxX + " " + scrollBoxY);
}
void OnGUI()
{
scrollPosition = GUI.BeginScrollView(new Rect(0, 0, screenBoxX, screenBoxY),
scrollPosition, new Rect(0, 0, scrollBoxX, scrollBoxY));
GUI.EndScrollView();
// showing 4 decimal places
Debug.Log ("Box scrolled # " + scrollPosition.ToString("F4"));
}
}
For the explanation of this example, let's assume that the screen resolution is 800 by 600.
Therefore the viewable scrollbox on the screen will be 800 wide and 600 high, with the internal area of the scrollbox being 1600 by 1800.
We create the scrollbox by assigning Gui.BeginScrollView() as the value of Vector2, scrollPosition. As the scrollbox is scrolled horizontally and vertically, the Vector2 will update with the scrolled value.
If the scrollbox is scrolled to the top-leftmost position, the value of scrollPosition will be 0,0.
If the scrollbox is scrolled to the bottom-rightmost position, the value of scrollPosition will be 816, 616, the size of the box on screen plus the thickness of the scroll bars.
I know this is 3 years later but maybe it will help others too...
I found that setting the scrollPosition to a very high number will force the scrollbar to the bottom:
scrollPosition.y = 999.9f;
Then you can read the position like this:
scrollPosition = GUILayout.BeginScrollView(scrollPosition,
GUILayout.Width(370),
GUILayout.Height(135));
And it will be set to whatever the maximum is.
Hope this helps!
I am trying to build a system that will be able to process a record of someone whistling and output notes.
Can anyone recommend an open-source platform which I can use as the base for the note/pitch recognition and analysis of wave files ?
Thanks in advance
As many others have already said, FFT is the way to go here. I've written a little example in Java using FFT code from http://www.cs.princeton.edu/introcs/97data/. In order to run it, you will need the Complex class from that page also (see the source for the exact URL).
The code reads in a file, goes window-wise over it and does an FFT on each window. For each FFT it looks for the maximum coefficient and outputs the corresponding frequency. This does work very well for clean signals like a sine wave, but for an actual whistle sound you probably have to add more. I've tested with a few files with whistling I created myself (using the integrated mic of my laptop computer), the code does get the idea of what's going on, but in order to get actual notes more needs to be done.
1) You might need some more intelligent window technique. What my code uses now is a simple rectangular window. Since the FFT assumes that the input singal can be periodically continued, additional frequencies are detected when the first and the last sample in the window don't match. This is known as spectral leakage ( http://en.wikipedia.org/wiki/Spectral_leakage ), usually one uses a window that down-weights samples at the beginning and the end of the window ( http://en.wikipedia.org/wiki/Window_function ). Although the leakage shouldn't cause the wrong frequency to be detected as the maximum, using a window will increase the detection quality.
2) To match the frequencies to actual notes, you could use an array containing the frequencies (like 440 Hz for a') and then look for the frequency that's closest to the one that has been identified. However, if the whistling is off standard tuning, this won't work any more. Given that the whistling is still correct but only tuned differently (like a guitar or other musical instrument can be tuned differently and still sound "good", as long as the tuning is done consistently for all strings), you could still find notes by looking at the ratios of the identified frequencies. You can read http://en.wikipedia.org/wiki/Pitch_%28music%29 as a starting point on that. This is also interesting: http://en.wikipedia.org/wiki/Piano_key_frequencies
3) Moreover it might be interesting to detect the points in time when each individual tone starts and stops. This could be added as a pre-processing step. You could do an FFT for each individual note then. However, if the whistler doesn't stop but just bends between notes, this would not be that easy.
Definitely have a look at the libraries the others suggested. I don't know any of them, but maybe they contain already functionality for doing what I've described above.
And now to the code. Please let me know what worked for you, I find this topic pretty interesting.
Edit: I updated the code to include overlapping and a simple mapper from frequencies to notes. It works only for "tuned" whistlers though, as mentioned above.
package de.ahans.playground;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
public class FftMaxFrequency {
// taken from http://www.cs.princeton.edu/introcs/97data/FFT.java.html
// (first hit in Google for "java fft"
// needs Complex class from http://www.cs.princeton.edu/introcs/97data/Complex.java
public static Complex[] fft(Complex[] x) {
int N = x.length;
// base case
if (N == 1) return new Complex[] { x[0] };
// radix 2 Cooley-Tukey FFT
if (N % 2 != 0) { throw new RuntimeException("N is not a power of 2"); }
// fft of even terms
Complex[] even = new Complex[N/2];
for (int k = 0; k < N/2; k++) {
even[k] = x[2*k];
}
Complex[] q = fft(even);
// fft of odd terms
Complex[] odd = even; // reuse the array
for (int k = 0; k < N/2; k++) {
odd[k] = x[2*k + 1];
}
Complex[] r = fft(odd);
// combine
Complex[] y = new Complex[N];
for (int k = 0; k < N/2; k++) {
double kth = -2 * k * Math.PI / N;
Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
y[k] = q[k].plus(wk.times(r[k]));
y[k + N/2] = q[k].minus(wk.times(r[k]));
}
return y;
}
static class AudioReader {
private AudioFormat audioFormat;
public AudioReader() {}
public double[] readAudioData(File file) throws UnsupportedAudioFileException, IOException {
AudioInputStream in = AudioSystem.getAudioInputStream(file);
audioFormat = in.getFormat();
int depth = audioFormat.getSampleSizeInBits();
long length = in.getFrameLength();
if (audioFormat.isBigEndian()) {
throw new UnsupportedAudioFileException("big endian not supported");
}
if (audioFormat.getChannels() != 1) {
throw new UnsupportedAudioFileException("only 1 channel supported");
}
byte[] tmp = new byte[(int) length];
byte[] samples = null;
int bytesPerSample = depth/8;
int bytesRead;
while (-1 != (bytesRead = in.read(tmp))) {
if (samples == null) {
samples = Arrays.copyOf(tmp, bytesRead);
} else {
int oldLen = samples.length;
samples = Arrays.copyOf(samples, oldLen + bytesRead);
for (int i = 0; i < bytesRead; i++) samples[oldLen+i] = tmp[i];
}
}
double[] data = new double[samples.length/bytesPerSample];
for (int i = 0; i < samples.length-bytesPerSample; i += bytesPerSample) {
int sample = 0;
for (int j = 0; j < bytesPerSample; j++) sample += samples[i+j] << j*8;
data[i/bytesPerSample] = (double) sample / Math.pow(2, depth);
}
return data;
}
public AudioFormat getAudioFormat() {
return audioFormat;
}
}
public class FrequencyNoteMapper {
private final String[] NOTE_NAMES = new String[] {
"A", "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"
};
private final double[] FREQUENCIES;
private final double a = 440;
private final int TOTAL_OCTAVES = 6;
private final int START_OCTAVE = -1; // relative to A
public FrequencyNoteMapper() {
FREQUENCIES = new double[TOTAL_OCTAVES*12];
int j = 0;
for (int octave = START_OCTAVE; octave < START_OCTAVE+TOTAL_OCTAVES; octave++) {
for (int note = 0; note < 12; note++) {
int i = octave*12+note;
FREQUENCIES[j++] = a * Math.pow(2, (double)i / 12.0);
}
}
}
public String findMatch(double frequency) {
if (frequency == 0)
return "none";
double minDistance = Double.MAX_VALUE;
int bestIdx = -1;
for (int i = 0; i < FREQUENCIES.length; i++) {
if (Math.abs(FREQUENCIES[i] - frequency) < minDistance) {
minDistance = Math.abs(FREQUENCIES[i] - frequency);
bestIdx = i;
}
}
int octave = bestIdx / 12;
int note = bestIdx % 12;
return NOTE_NAMES[note] + octave;
}
}
public void run (File file) throws UnsupportedAudioFileException, IOException {
FrequencyNoteMapper mapper = new FrequencyNoteMapper();
// size of window for FFT
int N = 4096;
int overlap = 1024;
AudioReader reader = new AudioReader();
double[] data = reader.readAudioData(file);
// sample rate is needed to calculate actual frequencies
float rate = reader.getAudioFormat().getSampleRate();
// go over the samples window-wise
for (int offset = 0; offset < data.length-N; offset += (N-overlap)) {
// for each window calculate the FFT
Complex[] x = new Complex[N];
for (int i = 0; i < N; i++) x[i] = new Complex(data[offset+i], 0);
Complex[] result = fft(x);
// find index of maximum coefficient
double max = -1;
int maxIdx = 0;
for (int i = result.length/2; i >= 0; i--) {
if (result[i].abs() > max) {
max = result[i].abs();
maxIdx = i;
}
}
// calculate the frequency of that coefficient
double peakFrequency = (double)maxIdx*rate/(double)N;
// and get the time of the start and end position of the current window
double windowBegin = offset/rate;
double windowEnd = (offset+(N-overlap))/rate;
System.out.printf("%f s to %f s:\t%f Hz -- %s\n", windowBegin, windowEnd, peakFrequency, mapper.findMatch(peakFrequency));
}
}
public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
new FftMaxFrequency().run(new File("/home/axr/tmp/entchen.wav"));
}
}
i think this open-source platform suits you
http://code.google.com/p/musicg-sound-api/
Well, you could always use fftw to perform the Fast Fourier Transform. It's a very well respected framework. Once you've got an FFT of your signal you can analyze the resultant array for peaks. A simple histogram style analysis should give you the frequencies with the greatest volume. Then you just have to compare those frequencies to the frequencies that correspond with different pitches.
in addition to the other great options:
csound pitch detection: http://www.csounds.com/manual/html/pvspitch.html
fmod: http://www.fmod.org/ (has a free version)
aubio: http://aubio.org/doc/pitchdetection_8h.html
You might want to consider Python(x,y). It's a scientific programming framework for python in the spirit of Matlab, and it has easy functions for working in the FFT domain.
If you use Java, have a look at TarsosDSP library. It has a pretty good ready-to-go pitch detector.
Here is an example for android, but I think it doesn't require too much modifications to use it elsewhere.
I'm a fan of the FFT but for the monophonic and fairly pure sinusoidal tones of whistling, a zero-cross detector would do a far better job at determining the actual frequency at a much lower processing cost. Zero-cross detection is used in electronic frequency counters that measure the clock rate of whatever is being tested.
If you going to analyze anything other than pure sine wave tones, then FFT is definitely the way to go.
A very simple implementation of zero cross detection in Java on GitHub