-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstrument.pde
More file actions
141 lines (120 loc) · 4.24 KB
/
Copy pathinstrument.pde
File metadata and controls
141 lines (120 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class PitchData{ //Java won't return two things at once, so this keeps them together
float rate;
int index;
PitchData(float r, int i){
this.rate = r;
this.index = i;
}
}
class Instrument{
String name;
int[] samplePitches;
SoundFile[] samples;//Preloaded
String[] filePaths;
float[] sampleStarts; //Where each sample starts actually playing
int[] samplePlayID;
float volumeScale;
boolean letNotesRing;
PApplet app;
Instrument(String n, int[] pitches, String[] files, PApplet p){
this(n, pitches, files, new float[files.length], p);
}
Instrument(String n, int[] pitches, String[] files, float[] starts, PApplet p){
this.name = n;
this.app = p;
this.volumeScale = 1.0;
this.letNotesRing = false;
if (this.name.toLowerCase().indexOf("piano") >= 0){
this.volumeScale = 0.85;
this.letNotesRing = true;
}else if (this.name.toLowerCase().indexOf("strings") >= 0 || this.name.toLowerCase().indexOf("violin") >= 0){
this.volumeScale = 0.75;
}
this.samplePitches = new int[pitches.length];
this.filePaths = new String[files.length];
this.samples = new SoundFile[files.length];
this.sampleStarts = new float[files.length];
this.samplePlayID = new int[files.length];
for (int i=0;i<pitches.length;i++){
this.samplePitches[i] = pitches[i];
this.filePaths[i] = files[i];
this.sampleStarts[i] = starts[i];
if (files[i].indexOf("piano/") >= 0 && this.sampleStarts[i] < 0.03){
this.sampleStarts[i] = 0.03;
}
this.samples[i] = new SoundFile(this.app, files[i]);
}
}
//Will be talking about this
PitchData getPitchRate(int targetPitch){
//First find the closest matching sample pitch and calculate from that
//Minimum absolute differenc ebetween target pitch and sample
int minDiff = 1000;
int samplePitch = 0;
int index = -1;
for (int i=0;i<this.samplePitches.length;i++){
int p = this.samplePitches[i];
if (abs(p-targetPitch) < minDiff){
minDiff = abs(p-targetPitch);
samplePitch = p;
index = i; //To keep track of the specific sample pitch file location
}
}
//Calculate new rate based on samplePitch and targetPitch
int semitoneDifference = targetPitch - samplePitch;
//An octave is 12 semitones. 1 octave higher means the frequency doubles
//12 semitones up means 2x frequency, and 12 semitones down be 0.5x frequency
float rate = pow(2, semitoneDifference/12.0); //Calculates how much faster/slower to play te sample to get proper note
return new PitchData(rate, index);
}
void playNote(int midiNote, float duration){
playNote(midiNote, duration, 60000.0 / bpm);
}
void playNote(int midiNote, float duration, float quarterMs){
PitchData info = getPitchRate(midiNote);
stopAll(); //Stop all samples, not just the one about to play
this.samplePlayID[info.index]++; //Stops old timers from stopping newer notes
int playID = this.samplePlayID[info.index];
this.samples[info.index].cue(this.sampleStarts[info.index]);
this.samples[info.index].amp(masterVolume * this.volumeScale);
this.samples[info.index].play(info.rate);
if (letNotesRing){ //Piano notes get a timed release so they don't cut off too harshly
stopLater(info.index, playID, noteStopMs(duration, quarterMs));
}
}
float noteStopMs(float duration, float quarterMs){ //Vrey short piano notes need a minimum playback time
float stopMs = duration * quarterMs;
if (duration <= 0.25 + MUSIC_EPSILON){
stopMs = max(150, stopMs);
}else if (duration <= 0.5 + MUSIC_EPSILON){
stopMs = max(180, stopMs);
}
return stopMs;
}
void stopLater(final int index, final int playID, final float waitMs){
Thread stopThread = new Thread(new Runnable() {
public void run() {
try{
Thread.sleep((long)waitMs);
}
catch (Exception e){
}
if (samplePlayID[index] == playID){
samples[index].stop();
}
}
});
stopThread.start();
}
void stopForRest(){
if (!letNotesRing){
stopAll();
}
}
void stopAll(){
for (int i=0;i<this.samples.length;i++){
this.samplePlayID[i]++;
this.samples[i].stop();
}
}
}