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>
|
<groupId>sh.ball</groupId>
|
||||||
<artifactId>osci-render</artifactId>
|
<artifactId>osci-render</artifactId>
|
||||||
<version>1.11.4</version>
|
<version>1.11.5</version>
|
||||||
|
|
||||||
<name>osci-render</name>
|
<name>osci-render</name>
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,14 @@ public interface AudioPlayer<S> extends Runnable {
|
||||||
|
|
||||||
boolean isPlaying();
|
boolean isPlaying();
|
||||||
|
|
||||||
void setFrequency(double frequency);
|
void setBaseFrequency(double frequency);
|
||||||
|
|
||||||
|
void setPitchBendFactor(double pitchBend);
|
||||||
|
|
||||||
double getFrequency();
|
double getFrequency();
|
||||||
|
|
||||||
|
double getBaseFrequency();
|
||||||
|
|
||||||
void addFrame(S frame);
|
void addFrame(S frame);
|
||||||
|
|
||||||
void addEffect(Object identifier, Effect effect);
|
void addEffect(Object identifier, Effect effect);
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
private double lengthDrawn = 0;
|
private double lengthDrawn = 0;
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
private double frequency = MIDDLE_C;
|
private double frequency = MIDDLE_C;
|
||||||
|
private double pitchBend = 1.0;
|
||||||
private double trace = 0.5;
|
private double trace = 0.5;
|
||||||
|
|
||||||
private AudioDevice device;
|
private AudioDevice device;
|
||||||
|
@ -133,16 +134,27 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFrequency(double frequency) {
|
public void setBaseFrequency(double frequency) {
|
||||||
this.frequency = frequency;
|
this.frequency = frequency;
|
||||||
updateLengthIncrement();
|
updateLengthIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getFrequency() {
|
public void setPitchBendFactor(double pitchBend) {
|
||||||
|
this.pitchBend = pitchBend;
|
||||||
|
updateLengthIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBaseFrequency() {
|
||||||
return frequency;
|
return frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getFrequency() {
|
||||||
|
return frequency * pitchBend;
|
||||||
|
}
|
||||||
|
|
||||||
private Shape getCurrentShape() {
|
private Shape getCurrentShape() {
|
||||||
if (frame.size() == 0) {
|
if (frame.size() == 0) {
|
||||||
return new Vector2();
|
return new Vector2();
|
||||||
|
@ -154,7 +166,8 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
private void updateLengthIncrement() {
|
private void updateLengthIncrement() {
|
||||||
double totalLength = Shape.totalLength(frame);
|
double totalLength = Shape.totalLength(frame);
|
||||||
int sampleRate = device.sampleRate();
|
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
|
@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 InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
|
||||||
private static final double MAX_FREQUENCY = 12000;
|
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 FileChooser fileChooser = new FileChooser();
|
||||||
private final DirectoryChooser folderChooser = new DirectoryChooser();
|
private final DirectoryChooser folderChooser = new DirectoryChooser();
|
||||||
|
@ -213,7 +216,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
||||||
|
|
||||||
private Map<Slider, Consumer<Double>> initializeSliderMap() {
|
private Map<Slider, Consumer<Double>> initializeSliderMap() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
frequencySlider, f -> audioPlayer.setFrequency(Math.pow(MAX_FREQUENCY, f)),
|
frequencySlider, f -> audioPlayer.setBaseFrequency(Math.pow(MAX_FREQUENCY, f)),
|
||||||
rotateSpeedSlider, rotateEffect::setSpeed,
|
rotateSpeedSlider, rotateEffect::setSpeed,
|
||||||
translationSpeedSlider, translateEffect::setSpeed,
|
translationSpeedSlider, translateEffect::setSpeed,
|
||||||
scaleSlider, scaleEffect::setScale,
|
scaleSlider, scaleEffect::setScale,
|
||||||
|
@ -631,7 +634,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
||||||
|
|
||||||
private void playNote(double frequency, double volume) {
|
private void playNote(double frequency, double volume) {
|
||||||
frequencySlider.setValue(Math.log(frequency) / Math.log(MAX_FREQUENCY));
|
frequencySlider.setValue(Math.log(frequency) / Math.log(MAX_FREQUENCY));
|
||||||
audioPlayer.setFrequency(frequency);
|
audioPlayer.setBaseFrequency(frequency);
|
||||||
scaleSlider.setValue(volume);
|
scaleSlider.setValue(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,6 +691,19 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
||||||
}
|
}
|
||||||
playNote(frequency, volume);
|
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