kopia lustrzana https://github.com/jameshball/osci-render
Add support for pitch bending with MIDI
rodzic
7ee7f4d644
commit
e6b198d0ec
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
|||
|
||||
<groupId>sh.ball</groupId>
|
||||
<artifactId>osci-render</artifactId>
|
||||
<version>1.11.4</version>
|
||||
<version>1.11.5</version>
|
||||
|
||||
<name>osci-render</name>
|
||||
|
||||
|
|
|
@ -14,10 +14,14 @@ public interface AudioPlayer<S> extends Runnable {
|
|||
|
||||
boolean isPlaying();
|
||||
|
||||
void setFrequency(double frequency);
|
||||
void setBaseFrequency(double frequency);
|
||||
|
||||
void setPitchBendFactor(double pitchBend);
|
||||
|
||||
double getFrequency();
|
||||
|
||||
double getBaseFrequency();
|
||||
|
||||
void addFrame(S frame);
|
||||
|
||||
void addEffect(Object identifier, Effect effect);
|
||||
|
|
|
@ -44,6 +44,7 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
private double lengthDrawn = 0;
|
||||
private int count = 0;
|
||||
private double frequency = MIDDLE_C;
|
||||
private double pitchBend = 1.0;
|
||||
private double trace = 0.5;
|
||||
|
||||
private AudioDevice device;
|
||||
|
@ -133,16 +134,27 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setFrequency(double frequency) {
|
||||
public void setBaseFrequency(double frequency) {
|
||||
this.frequency = frequency;
|
||||
updateLengthIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFrequency() {
|
||||
public void setPitchBendFactor(double pitchBend) {
|
||||
this.pitchBend = pitchBend;
|
||||
updateLengthIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBaseFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFrequency() {
|
||||
return frequency * pitchBend;
|
||||
}
|
||||
|
||||
private Shape getCurrentShape() {
|
||||
if (frame.size() == 0) {
|
||||
return new Vector2();
|
||||
|
@ -154,7 +166,8 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
private void updateLengthIncrement() {
|
||||
double totalLength = Shape.totalLength(frame);
|
||||
int sampleRate = device.sampleRate();
|
||||
lengthIncrement = Math.max(totalLength / (sampleRate / frequency), MIN_LENGTH_INCREMENT);
|
||||
double actualFrequency = frequency * pitchBend;
|
||||
lengthIncrement = Math.max(totalLength / (sampleRate / actualFrequency), MIN_LENGTH_INCREMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,6 +54,9 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
|
||||
private static final double MAX_FREQUENCY = 12000;
|
||||
private static final int PITCH_BEND_DATA_LENGTH = 7;
|
||||
private static final int PITCH_BEND_MAX = 16383;
|
||||
private static final int PITCH_BEND_SEMITONES = 2;
|
||||
|
||||
private final FileChooser fileChooser = new FileChooser();
|
||||
private final DirectoryChooser folderChooser = new DirectoryChooser();
|
||||
|
@ -213,7 +216,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
private Map<Slider, Consumer<Double>> initializeSliderMap() {
|
||||
return Map.of(
|
||||
frequencySlider, f -> audioPlayer.setFrequency(Math.pow(MAX_FREQUENCY, f)),
|
||||
frequencySlider, f -> audioPlayer.setBaseFrequency(Math.pow(MAX_FREQUENCY, f)),
|
||||
rotateSpeedSlider, rotateEffect::setSpeed,
|
||||
translationSpeedSlider, translateEffect::setSpeed,
|
||||
scaleSlider, scaleEffect::setScale,
|
||||
|
@ -631,7 +634,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
private void playNote(double frequency, double volume) {
|
||||
frequencySlider.setValue(Math.log(frequency) / Math.log(MAX_FREQUENCY));
|
||||
audioPlayer.setFrequency(frequency);
|
||||
audioPlayer.setBaseFrequency(frequency);
|
||||
scaleSlider.setValue(volume);
|
||||
}
|
||||
|
||||
|
@ -688,6 +691,19 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
}
|
||||
playNote(frequency, volume);
|
||||
}
|
||||
} else if (command == ShortMessage.PITCH_BEND) {
|
||||
// using these instructions https://sites.uci.edu/camp2014/2014/04/30/managing-midi-pitchbend-messages/
|
||||
|
||||
int pitchBend = (message.getData2() << PITCH_BEND_DATA_LENGTH) | message.getData1();
|
||||
// get pitch bend in range -1 to 1
|
||||
double pitchBendFactor = (double) pitchBend / PITCH_BEND_MAX;
|
||||
pitchBendFactor = 2 * pitchBendFactor - 1;
|
||||
pitchBendFactor *= PITCH_BEND_SEMITONES;
|
||||
// 12 tone equal temperament
|
||||
pitchBendFactor /= 12;
|
||||
pitchBendFactor = Math.pow(2, pitchBendFactor);
|
||||
|
||||
audioPlayer.setPitchBendFactor(pitchBendFactor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue