Skip to content

Commit

Permalink
compiled SAM + midiclock for x86_64 + arm64 on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisppaul committed Jul 5, 2024
1 parent 765cc95 commit 74fcaf6
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 245 deletions.
7 changes: 7 additions & 0 deletions lib/SAM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ include_directories(./cpp)

set(SOURCE_FILES cpp/wellen_SAM_impl.cpp)

# build for x86_64 + arm64

IF (APPLE)
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
ENDIF (APPLE)

# SAM library

message("----- SAM library -----")
include_directories(./libraries/SAM/include)
set(SAM_SRC_PATH ./libraries/SAM/src)
Expand Down
280 changes: 139 additions & 141 deletions lib/SAM/java/wellen/SAM.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Wellen
*
* This file is part of the *wellen* library (https://github.com/dennisppaul/wellen).
* Copyright (c) 2022 Dennis P Paul.
* Copyright (c) 2024 Dennis P Paul.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -31,151 +31,13 @@
*/
public class SAM implements DSPNodeOutput {

private static final int[] mMIDItoSAMMap = new int[128];
/* mapping MIDI pitch to SAM pitch */
private float[] mBuffer;
private boolean mIsDoneSpeaking;
private float mSampleBufferCounter;
private float mSampleSpeed;

public SAM() {
this(getLibraryPath() + getLibraryPrefix() + getLibraryName() + getLibrarySuffix());
}

public SAM(String pNativeLibraryPath) {
loadNativeLibrary(pNativeLibraryPath);
defaults();
mIsDoneSpeaking = true;
mSampleBufferCounter = 0;
mBuffer = null;
}

private static String getLibraryName() {
return "jni_wellen_sam";
}

private static String getLibraryPrefix() {
final String mSuffix;
if (System.getProperty("os.name").startsWith("Windows")) {
mSuffix = "";
} else if (System.getProperty("os.name").startsWith("Mac")) {
mSuffix = "lib";
} else {
mSuffix = "lib";
}
return mSuffix;
}

private static String getLibrarySuffix() {
final String mSuffix;
if (System.getProperty("os.name").startsWith("Windows")) {
mSuffix = "dll";
} else if (System.getProperty("os.name").startsWith("Mac")) {
mSuffix = "dylib";
} else {
mSuffix = "so";
}
return "." + mSuffix;
}

private static String getLibraryPath() {
final URL url = SAM.class.getResource(SAM.class.getSimpleName() + ".class");
if (url != null) {
String path = url.toString().replace("%20", " ");
int n0 = path.indexOf('/');
int n1 = path.indexOf("wellen.jar");
if (System.getProperty("os.name").startsWith("Windows")) {
// In Windows, path string starts with "jar file/C:/..." so the substring up to the first / is removed.
n0++;
}
if ((-1 < n0) && (-1 < n1)) {
return path.substring(n0, n1);
} else {
return "";
}
}
return "";
}

public native float[] get_samples();

public native void set_mouth(int pMouth);

public native void set_pitch(int pPitch);

public native void set_sing_mode(boolean pMode);

public native void set_speed(int pSpeed);

public native void set_throat(int pThroat);

public native String convert_text_to_phonemes(String pText);

public float[] say(String pText) {
return say(pText, false);
}

@Override
public float output() {
if (!mIsDoneSpeaking && mBuffer != null && mBuffer.length > 0) {
float mSamples = mBuffer[(int) mSampleBufferCounter];
mSampleBufferCounter += mSampleSpeed;
if (mSampleBufferCounter > mBuffer.length - 1) {
mIsDoneSpeaking = true;
}
return mSamples;
} else {
return 0;
}
}

public void rewind() {
mIsDoneSpeaking = false;
mSampleBufferCounter = 0;
}

public void set_sample_speed(float pSampleSpeed) {
mSampleSpeed = pSampleSpeed;
}

private void defaults() {
set_pitch(64);
set_throat(128);
set_speed(72);
set_mouth(128);
mSampleSpeed = 0.5f;
}

private void loadNativeLibrary(String pNativeLibraryPath) {
try {
System.loadLibrary(getLibraryName());
} catch (java.lang.UnsatisfiedLinkError e) {
System.load(FileSystems.getDefault().getPath(pNativeLibraryPath).normalize().toAbsolutePath().toString());
}
}

public float[] get_buffer() {
return mBuffer;
}

public float[] say(String pText, boolean pUsePhonemes) {
speak(pText, pUsePhonemes);
mBuffer = get_samples();
mIsDoneSpeaking = (mBuffer == null) || mBuffer.length <= 0;
mSampleBufferCounter = 0;
return mBuffer;
}

private native void speak(String pText, boolean pUsePhonemes);

private native void speak_ascii(int pASCIIValue);

/* mapping MIDI pitch to SAM pitch */

public static int get_pitch_from_MIDI_note(int pMIDINote) {
return mMIDItoSAMMap[pMIDINote];
}

private static final int[] mMIDItoSAMMap = new int[128];

static {
mMIDItoSAMMap[21] = 0; // A0
mMIDItoSAMMap[22] = 0; // A#0
Expand Down Expand Up @@ -286,6 +148,142 @@ public static int get_pitch_from_MIDI_note(int pMIDINote) {
mMIDItoSAMMap[127] = 0; // G9
}

public SAM() {
this(getLibraryPath() + getLibraryPrefix() + getLibraryName() + getLibrarySuffix());
}

public SAM(String pNativeLibraryPath) {
loadNativeLibrary(pNativeLibraryPath);
defaults();
mIsDoneSpeaking = true;
mSampleBufferCounter = 0;
mBuffer = null;
}

public static int get_pitch_from_MIDI_note(int pMIDINote) {
return mMIDItoSAMMap[pMIDINote];
}

private static String getLibraryName() {
return "jni_wellen_sam";
}

private static String getLibraryPath() {
final URL url = SAM.class.getResource(SAM.class.getSimpleName() + ".class");
if (url != null) {
String path = url.toString().replace("%20", " ");
int n0 = path.indexOf('/');
int n1 = path.indexOf("wellen.jar");
if (System.getProperty("os.name").startsWith("Windows")) {
// In Windows, path string starts with "jar file/C:/..." so the substring up to the first / is removed.
n0++;
}
if ((-1 < n0) && (-1 < n1)) {
return path.substring(n0, n1);
} else {
return "";
}
}
return "";
}

private static String getLibraryPrefix() {
final String mSuffix;
if (System.getProperty("os.name").startsWith("Windows")) {
mSuffix = "";
} else if (System.getProperty("os.name").startsWith("Mac")) {
mSuffix = "lib";
} else {
mSuffix = "lib";
}
return mSuffix;
}

private static String getLibrarySuffix() {
final String mSuffix;
if (System.getProperty("os.name").startsWith("Windows")) {
mSuffix = "dll";
} else if (System.getProperty("os.name").startsWith("Mac")) {
mSuffix = "dylib";
} else {
mSuffix = "so";
}
return "." + mSuffix;
}

public native float[] get_samples();

public native void set_mouth(int pMouth);

public native void set_pitch(int pPitch);

public native void set_sing_mode(boolean pMode);

public native void set_speed(int pSpeed);

public native void set_throat(int pThroat);

public native String convert_text_to_phonemes(String pText);

public float[] say(String pText) {
return say(pText, false);
}

@Override
public float output() {
if (!mIsDoneSpeaking && mBuffer != null && mBuffer.length > 0) {
float mSamples = mBuffer[(int) mSampleBufferCounter];
mSampleBufferCounter += mSampleSpeed;
if (mSampleBufferCounter > mBuffer.length - 1) {
mIsDoneSpeaking = true;
}
return mSamples;
} else {
return 0;
}
}

public void rewind() {
mIsDoneSpeaking = false;
mSampleBufferCounter = 0;
}

public void set_sample_speed(float pSampleSpeed) {
mSampleSpeed = pSampleSpeed;
}

public float[] get_buffer() {
return mBuffer;
}

public float[] say(String pText, boolean pUsePhonemes) {
speak(pText, pUsePhonemes);
mBuffer = get_samples();
mIsDoneSpeaking = (mBuffer == null) || mBuffer.length <= 0;
mSampleBufferCounter = 0;
return mBuffer;
}

private void defaults() {
set_pitch(64);
set_throat(128);
set_speed(72);
set_mouth(128);
mSampleSpeed = 0.5f;
}

private void loadNativeLibrary(String pNativeLibraryPath) {
try {
System.loadLibrary(getLibraryName());
} catch (java.lang.UnsatisfiedLinkError e) {
System.load(FileSystems.getDefault().getPath(pNativeLibraryPath).normalize().toAbsolutePath().toString());
}
}

private native void speak(String pText, boolean pUsePhonemes);

private native void speak_ascii(int pASCIIValue);

public static void main(String[] args) {
/* test */
float[] mSamples;
Expand Down
2 changes: 1 addition & 1 deletion lib/SAM/java/wellen/dsp/DSPNodeOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Wellen
*
* This file is part of the *wellen* library (https://github.com/dennisppaul/wellen).
* Copyright (c) 2022 Dennis P Paul.
* Copyright (c) 2024 Dennis P Paul.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down
Binary file modified lib/libjni_wellen_sam.dylib
Binary file not shown.
Binary file modified processing-library/wellen/library/libjni_wellen_sam.dylib
Binary file not shown.
Binary file modified processing-library/wellen/library/wellen.jar
Binary file not shown.
4 changes: 3 additions & 1 deletion processing-library/wellen/src/wellen/SamplerListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package wellen;

import wellen.dsp.Sampler;

public interface SamplerListener {
void is_done();
void is_done(Sampler pSampler);
}
20 changes: 17 additions & 3 deletions processing-library/wellen/src/wellen/Tone.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static <T extends Instrument> T create_instrument(Class<T> instrument_cla
// c = instrument_class.getDeclaredConstructor(Minim.class, int.class);
// mInstrument = c.newInstance((Minim) ((ToneEngineMinim) instance()).minim(), ID);
// } else {
c = instrument_class.getDeclaredConstructor(int.class);
c = instrument_class.getDeclaredConstructor(int.class);
mInstrument = c.newInstance(ID);
// }
} catch (Exception ex) {
Expand Down Expand Up @@ -85,6 +85,20 @@ public static float[] get_buffer() {
return instance().get_buffer();
}

/**
* @return reference to left output buffer
*/
public static float[] get_output_buffer_left() {
return get_buffer_left();
}

/**
* @return reference to right output buffer
*/
public static float[] get_output_buffer_right() {
return get_buffer_right();
}

public static float[] get_buffer_left() {
return instance().get_buffer_left();
}
Expand Down Expand Up @@ -251,7 +265,7 @@ public static void stop() {

private static void printAlreadyStartedWarning() {
System.err.println("+++ WARNING @" + Tone.class.getSimpleName() + ".start" + " / tone engine already " +
"initialized. make sure that `start` is the first call to `Ton`. " + "use " +
"`set_engine(ToneEngine)` to switch tone engines.");
"initialized. make sure that `start` is the first call to `Ton`. " + "use " +
"`set_engine(ToneEngine)` to switch tone engines.");
}
}
Loading

0 comments on commit 74fcaf6

Please sign in to comment.