Author |
Message |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Wed Mar 05, 2008 2:15 pm Post subject:
Sample to BPM conversion Subject description: Anybody know how? |
 |
|
Hey all,
does anybody know the formula for converting samples into beats per minute? For instance, I know that if i have a loop at 120 BPM it has 88200 samples (at 44.1 khz.) Anyone know how to calculate this?
Just for the record, I arrived at this result using the MusicMath 4.0 BPM/sample/ms conversion calculator which can be downloaded free here:
http://www.hitsquad.com/smm/programs/Music_Math/
It's for MAC. |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Wed Mar 05, 2008 7:17 pm Post subject:
|
 |
|
Well to answer my own post, I found that dividing the number of samples by the sample rate gives you the length in seconds. So now it's about converting seconds (or ms) to BPM.  |
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Mar 06, 2008 4:49 am Post subject:
|
 |
|
wppk wrote: | So now it's about converting seconds (or ms) to BPM.  |
Well, that's easy as well. If we want to know the BPM we count the beats that fit in one minute, right? Well, we can simply count how many times a sample fits in a minute!
Code: |
//setting up
SndBuf buf => dac;
buf.read("my_sample");
//strongly timed simple reasoning
buf.samples()::samp => dur sample_length;
minute / sample_length => float samples_per_minute;
//we can make it convenient as well if we know stuff about the sample
//let's say we know it to be a simple techno loop
8 => float beats_in_my_sample;
//then we can go
<<< "bpm is" , samples_per_minute * beats_in_my_sample >>>; |
There you go, From there on you can send the BPM to other shreds using a static value in a public class and have other shreds sync perfectly to your looped sample, kinda like a DJ except without needing to practice. :¬) _________________ Kassen |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Thu Mar 06, 2008 7:40 pm Post subject:
|
 |
|
Thanks Kassen. You got me rolling again. Must appreciated. I spent my lunch hour creating a Sample class. I was kind of stuck on the sample conversion bit.
Now I've run into another issue,(imagine that) and I'm not sure if I fully understand Classes and how to properly use them.
Basically, I declared a bunch of variables under the Class, and then when I went to use them as arguments later in the code, I got the Undefined variable in line..
I thought they were already defined when I declared them within the class.
isn't that how it's supposed to work? |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Thu Mar 06, 2008 7:41 pm Post subject:
|
 |
|
Code: | class Samplewrecker {
//some declarations
int sixpos[16];
int eipos[8];
int qupos[4];
int T;
float notelength;
//midi shit
MidiMsg input1;
MidiIn min;
//store samples
SndBuf buffer[512];
//load a sample from directory and output tempo
fun void loadsample(string path,int beatnum, int index){
path => buffer[index].read;
buffer[index].samples()::samp => dur Ti;
minute/Ti => float spm;
beatnum => float beats;
<<<path>>>;
<<<"BPM is",spm*beats>>>;
}
// signalpath
fun void connect(UGen x){
buffer[512] => x;
}
// offset/duration assignments
T / 2 => int half;
T / 4 => int quart;
T / 8 => int eight;
T / 16 => int six;
T / 32 => int t2;
T / 64 => int t4;
T / 128 => int t5;
T / 256 => int t6;
T / 512 => int t7;
//array assignment: put sample offset positions at index, ie quarter note divisions, eighth etc.
0 => qupos[0]; quart => qupos[1]; quart*2 => qupos[2]; quart*3 => qupos[3];
0 => eipos[0]; eight => eipos[1]; eight*2 => eipos[2]; eight*3 => eipos[3];
eight*4 => eipos[4]; eight*5 => eipos[5]; eight*6 => eipos[6]; eight*7 => eipos[7];
0 => sixpos[0]; six => sixpos[1]; six*2 => sixpos[2]; six*3 => sixpos[3];
six*4 => sixpos[4]; six*5 => sixpos[5]; six*6 => sixpos[6]; six*7 => sixpos[7];
six*8 => sixpos[8]; six*9 => sixpos[9]; six*10 =>sixpos[10];six*11 =>sixpos[11];
six*12 => sixpos[12]; six*13 => sixpos[13]; six*14 =>sixpos[14];six*15 =>sixpos[15];
//go for it
fun void straight(int pos[], int speed, float notlen,int smp) {
while (true) {
for(0=>int i;i< pos.cap();i++) {
//assign on of the sample array's index to buffer.pos
pos[i] => buffer[smp].pos;
//play sample for a duration (eight, six, t1 etc..)
speed::samp => now;
//stop plaback and advance time to shorten note duration if wanted
0 => buffer[smp].rate;
notlen::samp => now;
}}
}
fun void jumble(int pos[],int speed, float notlen, int smp) {
while (true) {
pos[Std.rand2(0,4)] => buffer[smp].pos;
speed::samp => now;
0 => buffer[smp].rate;
notlen::samp => now;
}
}
fun float note_duration (int divisor) {
T / divisor => notelength;
return notelength;
}
fun void listindex(int index){
<<<buffer>>>;
}
fun void allsamps(){
for(0=>int i; i < buffer.cap();i++) {
<<<buffer>>>;
300::ms => now;
}
}
}
//Let the games begin!! sort of...
//Declare 2 objects
Samplewrecker loader;
Samplewrecker player;
//connect to the dac
loader.buffer[0] => dac;
//call loadsample() and return the BPM (Thanks Kassen) and index number in buffer.
loader.loadsample("slowhopper.aif", 4, 0);
// try to spork the function, but it doesn't recognise the variables?:(
//says Undefined Variables, but I thought I had already defined them within the class.
spork ~ player.straight(eipos[8], eight, eight, 0);
//advance time so shred won't quit
while(true) {100::ms => now;}
|
|
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Fri Mar 07, 2008 5:52 pm Post subject:
|
 |
|
I got why you have your error, there's a error beyond that, but let's first look at this, OK?
You write (in line 202 or so)
Code: | spork ~ player.straight(eipos[8], eight, eight, 0);
|
The problem starts at "eipos[]". The issue is that "eipos" belongs to the "Samplewrecker" class and that class has several instances. You can't just refer to the name of a member of a class, you need to specify which instance of that class you are talking about (even if there is only one and the name is only used once!) so in this case "eipos[8]" would likely become "player.eipos[8]". at that point you might want to consider reffering to "eipos[8]" inside of the function inside of the class.... or perhaps have the function take a int to be used a index to that array.... But before we go there let me illustrate this issue;
Code: | 1 => int foo;
class Bar
{
2 => int foo;
fun int returnFoo()
{
//refers to the "foo" inside of the class!
//these are different as you will see.
return foo;
}
}
fun int returnFoo()
{
//refers to the one outside of the class!
return foo;
}
fun int returnAnotherFoo()
{
//temporary variable!
//this one just exists while the function runs.
3 => int foo;
//refers to the one inside of this function!
return foo;
}
Bar bar;
//outside of class
<<<foo>>>;
//through function
<<<returnFoo()>>>;
//inside
<<<bar.foo>>>;
//through function in class
<<<bar.returnFoo()>>>;
//inside of function
<<<returnAnotherFoo()>>>; |
This is what we call "name space"; every "space" (classes and functions) can have their own names that only hold within them and can't be reached from outside without pointing at that name space (or class instance), though, if things aren't defined differently within them functions can reach names outside of themselves.
I realise this is a complex example that can be confusing but it's meant to illustrate a method that actually saves confusion (in the long run...).
I hope that helps you take another step, if not we can try a different way of explaining it. It's probably important to understand this if you want to make the most of classes. _________________ Kassen |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Sat Mar 08, 2008 11:54 pm Post subject:
|
 |
|
Ok. I'm clear on the namespace. Well, I at least understand that every time you call an object of a particular class it must be linked to an instance of the class.
spork ~ player.straight(player.eipos[8]..
i assumed that it wasn't necessary because it was an argument for a function of the class.
I did try this and the compiler allowed it but the argument types don't match now. |
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Sun Mar 09, 2008 1:56 am Post subject:
|
 |
|
wppk wrote: | spork ~ player.straight(player.eipos[8]..
i assumed that it wasn't necessary because it was an argument for a function of the class.
I did try this and the compiler allowed it but the argument types don't match now. |
That's because the function expects an array and you're giving it an int inside an array. Try giving it player.eipos as the argument.
player.eipos[8] is the 9th member of the eipos array, in this case it would throw an Out of Bounds exception because eipos only has 8 members. _________________ To boldly go where no man has bothered to go before. |
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Sun Mar 09, 2008 10:34 am Post subject:
|
 |
|
wppk wrote: |
i assumed that it wasn't necessary because it was an argument for a function of the class. |
Yes, that makes sense, like when you say "heads up" to a friend you don't mean him to lift the head of a third person.... it's still important to explicit about this because ChucK is a great deal dumber then your friends and can't make stuff out from the context.
This is because you may want a function to do something to a member of another class. Say I have a "wppk" object and a cake object... and the wppk eats the cherry that's on the cake.
Code: |
Person wppk;
//not a lie, I swear ;¬)
Cake cake;
wppk.eat( cake.cherry );
wppk.lick(wppk.finger); |
;¬)
See why we need this?
We also need the separate namespace inside of functions, if we didn't we would be unable to use temporary variables without first checking all of our code to make sure we didn't already use that one. It's far more convenient to always use "int i" for "index" and trust the VM and compiler will take care of the rest.
I recommend making sure you understand the example above and understand why some of the numbers that come out are the same and others are different and why as this will save a lot of headaches in the long run when working with classes.
Quote: | I did try this and the compiler allowed it but the argument types don't match now. |
Yeah, that's the next step ( I trust mr.Frost covered this). This is entirely normal with larger chunks of code everybody gets a few errors, you just resolve them one by one and keep at it and eventually it'll work. _________________ Kassen |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Mon Mar 10, 2008 9:57 am Post subject:
|
 |
|
Thanks so much guys. I've actually got it working now. Well..Almost.
But it's making sound! Thanks again for your help on this. |
|
Back to top
|
|
 |
|