diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3c9800b..afdd88d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,11 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: macos-latest + permissions: + actions: read + contents: read + security-events: write strategy: fail-fast: false @@ -36,11 +40,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,19 +54,34 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + - name: Build with Maven + run: mvn -B package --file pom.xml -Dmaven.test.skip=true - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + - name: Build with Maven + run: mvn -B package -Dmaven.test.skip=true #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index d6e9c5e..9767766 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,7 +1,7 @@ # This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven -name: Java CI with Maven +name: Java CI on: push: @@ -15,10 +15,21 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Build with Maven - run: mvn -B package --file pom.xml + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check w/o SNAPSHOT when "bump version" + if: ${{ contains(github.event.head_commit.message, 'bump version') }} + run: grep "" pom.xml | head -1 | grep -v SNAPSHOT + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + run: | + wget -O src/test/resources/unpacked.bin https://github.com/bwhitman/learnfm/blob/f5415157c65b0298dad692e5e332c71644718e28/unpacked.bin?raw=true + mvn -B package --file pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..466170f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +unpacked.bin +/tmp/ +local.properties diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000..efde7bf --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,2 @@ +jdk: + - openjdk17 diff --git a/local.properties.sample b/local.properties.sample new file mode 100644 index 0000000..18f57a3 --- /dev/null +++ b/local.properties.sample @@ -0,0 +1,4 @@ +#test.midi=/foo/bar.mid + +vavi.test.volume=0.02 +vavi.test.volume.midi=0.2 diff --git a/pom.xml b/pom.xml index 39468b9..9664be1 100644 --- a/pom.xml +++ b/pom.xml @@ -3,25 +3,72 @@ vavi vavi-sound-dx7 - 0.0.2 + 0.0.3 + + + 0.02 + 0.2 + + + + + local + + + ${basedir}/local.properties + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.1.0 + + + read-properties + initialize + + read-project-properties + + + + ${basedir}/local.properties + + + + + + + + + + org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.11.0 - 1.8 - 1.8 + 17 + 17 + + --add-exports + java.desktop/com.sun.media.sound=ALL-UNNAMED + org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.2.2 + --add-opens java.desktop/com.sun.media.sound=ALL-UNNAMED -Djava.util.logging.config.file=${project.build.testOutputDirectory}/logging.properties + -Dvavi.test.volume=${vavi.test.volume} + -Dvavi.test.volume.midi=${vavi.test.volume.midi} false @@ -36,34 +83,43 @@ + + + + org.junit + junit-bom + 5.10.2 + pom + import + + + + com.github.umjammer vavi-commons - 1.1.4 + 1.1.10 com.github.umjammer vavi-sound - 1.0.10 + 1.0.16 org.junit.jupiter junit-jupiter-api - 5.3.0 test org.junit.jupiter junit-jupiter-engine - 5.3.0 test org.junit.platform junit-platform-commons - 1.5.2 test diff --git a/readme.md b/readme.md index 9efa9be..6d08d5f 100644 --- a/readme.md +++ b/readme.md @@ -1,27 +1,34 @@ -[![Release](https://jitpack.io/v/umjammer/vavi-sound-dx7.svg)](https://jitpack.io/#umjammer/vavi-sound-dx7) [![Java CI with Maven](https://github.com/umjammer/vavi-sound-dx7/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/umjammer/vavi-sound-dx7/actions) +[![Release](https://jitpack.io/v/umjammer/vavi-sound-dx7.svg)](https://jitpack.io/#umjammer/vavi-sound-dx7) +[![Java CI](https://github.com/umjammer/vavi-sound-dx7/actions/workflows/maven.yml/badge.svg)](https://github.com/umjammer/vavi-sound-dx7/actions/workflows/maven.yml) +[![CodeQL](https://github.com/umjammer/vavi-sound-dx7/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/umjammer/vavi-sound-dx7/actions/workflows/codeql-analysis.yml) +![Java](https://img.shields.io/badge/Java-17-b07219) # vavi-sound-dx7 +logo Š YAMAHA + DX7 emulated synthesizer. `javax.sound.midi.spi` compatible. -## spec. +### spec. * sysex [43, 00, 09, 20, 00] supported * control change 1, 2, 3, 64 supported ## install - * maven repo: [jitpack](https://jitpack.io/#umjammer/vavi-sound-dx7) + * maven [jitpack](https://jitpack.io/#umjammer/vavi-sound-dx7) * copy [`unpacked.bin`](https://github.com/bwhitman/learnfm/blob/f5415157c65b0298dad692e5e332c71644718e28/unpacked.bin) into your class path - * edit `dx7.properties`, create your instruments set + * edit `dx7.properties`([sample](src/test/resources/dx7.properties)), create your instruments set + +## Usage -## with [Herr Mueller's DX7](http://www.vstforx.de/index.php/disco-news-blog/29-goodies/92-vstforx-presents-herr-mueller-s-dx7) +### with [Herr Mueller's DX7](http://www.vstforx.de/index.php/disco-news-blog/29-goodies/92-vstforx-presents-herr-mueller-s-dx7) -without the real dx7 machine, you can play dx7 sound! +without a real dx7 machine, you can play dx7 sound! -![herrMueller](https://lh3.googleusercontent.com/pw/ACtC-3erXg2jLuvfN_0EvFXnGhCRSRaf5D75KJZfOtmtUk8NuZGNkLOm87vipTViapFHoixBgOuMFQ4WTKMZAmfaMeU-wLlZol_udw5XMDLNDj_O9i-5Vl7U4mG-O8r0hJijXE7liyY2RjSXLVLAir0dyg2P=w640-h225-no?authuser=0) +![SS 2020-11-10 15 42 30](https://user-images.githubusercontent.com/493908/195994898-beb01841-8a6b-4071-91e1-542b36a4ac4c.jpg) -## thanks +## References * https://github.com/google/music-synthesizer-for-android * gervill @@ -30,4 +37,5 @@ without the real dx7 machine, you can play dx7 sound! * better default instruments set * syx, vcs loader (use SoundbankReader) - * automatic instruments recognizer/classifier \ No newline at end of file + * automatic instruments recognizer/classifier + * ~~volume~~ works! thanks gervill diff --git a/src/main/java/vavi/sound/dx7/Context.java b/src/main/java/vavi/sound/dx7/Context.java new file mode 100644 index 0000000..f65e4ba --- /dev/null +++ b/src/main/java/vavi/sound/dx7/Context.java @@ -0,0 +1,47 @@ +package vavi.sound.dx7; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Context. + * + * @author Naohide Sano (nsano) + * @version 0.00 2022-06-15 nsano initial version
+ */ +public class Context { + public float sampleRate; + + // The original DX7 had one single LFO. Later units had an LFO per note. + public Lfo lfo; + public FreqLut freqLut; + public PitchEnv pitchEnv; + + private static Map instances = new HashMap<>(); + + public static Context getInstance(float sampleRate) { + if (instances.containsKey(sampleRate)) { + return instances.get(sampleRate); + } else { + Context context = new Context(sampleRate); + instances.put(sampleRate, context); + return context; + } + } + + private Context(float sampleRate) { + this.sampleRate = sampleRate; + freqLut = new FreqLut(sampleRate); + lfo = new Lfo(sampleRate); + pitchEnv = new PitchEnv(sampleRate); + } + + public void setSampleRate(float sampleRate) { + this.sampleRate = sampleRate; + Context context = getInstance(sampleRate); + this.freqLut = context.freqLut; + this.lfo = context.lfo; + this.pitchEnv = context.pitchEnv; + } +} diff --git a/src/main/java/vavi/sound/dx7/Env.java b/src/main/java/vavi/sound/dx7/Env.java index 84979a9..2807159 100644 --- a/src/main/java/vavi/sound/dx7/Env.java +++ b/src/main/java/vavi/sound/dx7/Env.java @@ -19,102 +19,102 @@ class Env { - private int[] rates_ = new int[4]; - private int[] levels_ = new int[4]; - private int outlevel_; - private int rate_scaling_; + private int[] rates = new int[4]; + private int[] levels = new int[4]; + private int outLevel; + private int rateScaling; // Level is stored so that 2^24 is one doubling, ie 16 more bits than // the DX7 itself (fraction is stored in level rather than separate // counter) - private int level_; - private int targetlevel_; - private boolean rising_; - private int ix_; - private int inc_; + private int level; + private int targetLevel; + private boolean rising; + private int ix; + private int inc; - private boolean down_; + private boolean down; - Env(final int[] r, final int[] l, int ol, int rate_scaling) { + Env(int[] r, int[] l, int ol, int rateScaling) { for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; + rates[i] = r[i]; + levels[i] = l[i]; } - outlevel_ = ol; - rate_scaling_ = rate_scaling; - level_ = 0; - down_ = true; + outLevel = ol; + this.rateScaling = rateScaling; + level = 0; + down = true; advance(0); } - int getsample() { - if (ix_ < 3 || (ix_ < 4) && !down_) { - if (rising_) { - final int jumptarget = 1716; - if (level_ < (jumptarget << 16)) { - level_ = jumptarget << 16; + int getSample() { + if (ix < 3 || (ix < 4) && !down) { + if (rising) { + final int jumpTarget = 1716; + if (level < (jumpTarget << 16)) { + level = jumpTarget << 16; } - level_ += (((17 << 24) - level_) >> 24) * inc_; + level += (((17 << 24) - level) >> 24) * inc; // TODO: should probably be more accurate when inc is large - if (level_ >= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); + if (level >= targetLevel) { + level = targetLevel; + advance(ix + 1); } } else { // !rising - level_ -= inc_; - if (level_ <= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); + level -= inc; + if (level <= targetLevel) { + level = targetLevel; + advance(ix + 1); } } } // TODO: this would be a good place to set level to 0 when under // threshold - return level_; + return level; } - void keydown(boolean d) { - if (down_ != d) { - down_ = d; + void keyDown(boolean d) { + if (down != d) { + down = d; advance(d ? 0 : 3); } } - void setparam(int param, int value) { + void setParam(int param, int value) { if (param < 4) { - rates_[param] = value; + rates[param] = value; } else if (param < 8) { - levels_[param - 4] = value; + levels[param - 4] = value; } // Unknown parameter, ignore for now } - private static final int levellut[] = { + private static final int[] levelLut = { 0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46 }; - public static int scaleoutlevel(int outlevel) { - return outlevel >= 20 ? 28 + outlevel : levellut[outlevel]; + public static int scaleOutLevel(int outLevel) { + return outLevel >= 20 ? 28 + outLevel : levelLut[outLevel]; } - void advance(int newix) { - ix_ = newix; - if (ix_ < 4) { - int newlevel = levels_[ix_]; - int actuallevel = scaleoutlevel(newlevel) >> 1; + void advance(int newIx) { + ix = newIx; + if (ix < 4) { + int newLevel = levels[ix]; + int actualLevel = scaleOutLevel(newLevel) >> 1; - actuallevel = (actuallevel << 6) + outlevel_ - 4256; - actuallevel = actuallevel < 16 ? 16 : actuallevel; + actualLevel = (actualLevel << 6) + outLevel - 4256; + actualLevel = Math.max(actualLevel, 16); // level here is same as Java impl - targetlevel_ = actuallevel << 16; - rising_ = (targetlevel_ > level_); + targetLevel = actualLevel << 16; + rising = (targetLevel > level); // rate - int qrate = (rates_[ix_] * 41) >> 6; + int qRate = (rates[ix] * 41) >> 6; - qrate += rate_scaling_; - qrate = Math.min(qrate, 63); - inc_ = (4 + (qrate & 3)) << (2 + Note.LG_N + (qrate >> 2)); + qRate += rateScaling; + qRate = Math.min(qRate, 63); + inc = (4 + (qRate & 3)) << (2 + Note.LG_N + (qRate >> 2)); } } } diff --git a/src/main/java/vavi/sound/dx7/Exp2.java b/src/main/java/vavi/sound/dx7/Exp2.java index 2ac91eb..dae4474 100644 --- a/src/main/java/vavi/sound/dx7/Exp2.java +++ b/src/main/java/vavi/sound/dx7/Exp2.java @@ -22,27 +22,27 @@ class Exp2 { private static final int EXP2_LG_N_SAMPLES = 10; private static final int EXP2_N_SAMPLES = 1 << EXP2_LG_N_SAMPLES; - private static int[] exp2tab = new int[EXP2_N_SAMPLES << 1]; + private static int[] exp2Tab = new int[EXP2_N_SAMPLES << 1]; static { double inc = Math.pow(2, 1.0 / EXP2_N_SAMPLES); double y = 1 << 30; for (int i = 0; i < EXP2_N_SAMPLES; i++) { - exp2tab[(i << 1) + 1] = (int) Math.floor(y + 0.5); + exp2Tab[(i << 1) + 1] = (int) Math.floor(y + 0.5); y *= inc; } for (int i = 0; i < EXP2_N_SAMPLES - 1; i++) { - exp2tab[i << 1] = exp2tab[(i << 1) + 3] - exp2tab[(i << 1) + 1]; + exp2Tab[i << 1] = exp2Tab[(i << 1) + 3] - exp2Tab[(i << 1) + 1]; } - exp2tab[(EXP2_N_SAMPLES << 1) - 2] = (1 << 31) - exp2tab[(EXP2_N_SAMPLES << 1) - 1]; + exp2Tab[(EXP2_N_SAMPLES << 1) - 2] = (1 << 31) - exp2Tab[(EXP2_N_SAMPLES << 1) - 1]; } - public static final int lookup(int x) { + public static int lookup(int x) { final int SHIFT = 24 - EXP2_LG_N_SAMPLES; int lowbits = x & ((1 << SHIFT) - 1); int x_int = (x >> (SHIFT - 1)) & ((EXP2_N_SAMPLES - 1) << 1); - int dy = exp2tab[x_int]; - int y0 = exp2tab[x_int + 1]; + int dy = exp2Tab[x_int]; + int y0 = exp2Tab[x_int + 1]; int y = (int) (y0 + (((long)dy * (long)lowbits) >> SHIFT)); return y >> (6 - (x >> 24)); @@ -53,13 +53,13 @@ class Tanh { private static final int TANH_LG_N_SAMPLES = 10; private static final int TANH_N_SAMPLES = 1 << TANH_LG_N_SAMPLES; - private static int[] tanhtab = new int[TANH_N_SAMPLES << 1]; + private static int[] tanhTab = new int[TANH_N_SAMPLES << 1]; static { double step = 4.0 / TANH_N_SAMPLES; double y = 0; for (int i = 0; i < TANH_N_SAMPLES; i++) { - tanhtab[(i << 1) + 1] = (int) ((1 << 24) * y + 0.5); + tanhTab[(i << 1) + 1] = (int) ((1 << 24) * y + 0.5); // printf("%d\n", tanhtab[(i << 1) + 1]); // Use a basic 4th order Runge-Kutte to compute tanh from its // differential equation. @@ -71,10 +71,10 @@ class Tanh { y += dy; } for (int i = 0; i < TANH_N_SAMPLES - 1; i++) { - tanhtab[i << 1] = tanhtab[(i << 1) + 3] - tanhtab[(i << 1) + 1]; + tanhTab[i << 1] = tanhTab[(i << 1) + 3] - tanhTab[(i << 1) + 1]; } int lasty = (int) ((1 << 24) * y + 0.5); - tanhtab[(TANH_N_SAMPLES << 1) - 2] = lasty - tanhtab[(TANH_N_SAMPLES << 1) - 1]; + tanhTab[(TANH_N_SAMPLES << 1) - 2] = lasty - tanhTab[(TANH_N_SAMPLES << 1) - 1]; } public static int lookup(int x) { @@ -88,11 +88,11 @@ public static int lookup(int x) { return signum ^ ((1 << 24) - 2 * Exp2.lookup(sx)); } else { final int SHIFT = 26 - TANH_LG_N_SAMPLES; - int lowbits = x & ((1 << SHIFT) - 1); - int x_int = (x >> (SHIFT - 1)) & ((TANH_N_SAMPLES - 1) << 1); - int dy = tanhtab[x_int]; - int y0 = tanhtab[x_int + 1]; - int y = (int) (y0 + (((long) dy * (long) lowbits) >> SHIFT)); + int lowBits = x & ((1 << SHIFT) - 1); + int xInt = (x >> (SHIFT - 1)) & ((TANH_N_SAMPLES - 1) << 1); + int dy = tanhTab[xInt]; + int y0 = tanhTab[xInt + 1]; + int y = (int) (y0 + (((long) dy * (long) lowBits) >> SHIFT)); return y ^ signum; } } diff --git a/src/main/java/vavi/sound/dx7/FmCore.java b/src/main/java/vavi/sound/dx7/FmCore.java index f6430c1..bd75e71 100644 --- a/src/main/java/vavi/sound/dx7/FmCore.java +++ b/src/main/java/vavi/sound/dx7/FmCore.java @@ -28,7 +28,7 @@ public static class FmOpParams { public static class FmOperatorInfo { int in; int out; - }; + } private static final int OUT_BUS_ONE = 1 << 0; private static final int OUT_BUS_TWO = 1 << 1; @@ -83,7 +83,7 @@ public FmAlgorithm(Integer... args) { new FmAlgorithm(0xc4, 0x04, 0x04, 0x04, 0x04, 0x04), // 32 }; - private int n_out(final FmAlgorithm alg) { + private int n_out(FmAlgorithm alg) { int count = 0; for (int i = 0; i < 6; i++) { if ((alg.ops[i] & 7) == OUT_BUS_ADD) @@ -93,16 +93,16 @@ private int n_out(final FmAlgorithm alg) { } public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < 32; i++) { - sb.append((i + 1) + ":"); - final FmAlgorithm alg = algorithms[i]; + sb.append(i + 1).append(":"); + FmAlgorithm alg = algorithms[i]; for (int j = 0; j < 6; j++) { int flags = alg.ops[j]; sb.append(" "); if ((flags & FB_IN) != 0) sb.append("["); - sb.append(((flags & IN_BUS_ONE) != 0 ? "1" : (flags & IN_BUS_TWO) != 0 ? "2" : "0") + "->"); + sb.append((flags & IN_BUS_ONE) != 0 ? "1" : (flags & IN_BUS_TWO) != 0 ? "2" : "0").append("->"); sb.append((flags & OUT_BUS_ONE) != 0 ? "1" : (flags & OUT_BUS_TWO) != 0 ? "2" : "0"); if ((flags & OUT_BUS_ADD) != 0) sb.append("+"); @@ -110,46 +110,46 @@ public String toString() { if ((flags & FB_OUT) != 0) sb.append("]"); } - sb.append(" " + n_out(alg)); + sb.append(" ").append(n_out(alg)); } return sb.toString(); } - public void compute(int[] output, FmOpParams[] params, int algorithm, int[] fb_buf, int feedback_shift) { + public void compute(int[] output, FmOpParams[] params, int algorithm, int[] fbBuf, int feedbackShift) { final int kLevelThresh = 1120; - final FmAlgorithm alg = algorithms[algorithm]; - boolean[] has_contents = { + FmAlgorithm alg = algorithms[algorithm]; + boolean[] hasContents = { true, false, false }; for (int op = 0; op < 6; op++) { int flags = alg.ops[op]; boolean add = (flags & OUT_BUS_ADD) != 0; FmOpParams param = params[op]; - int inbus = (flags >> 4) & 3; - int outbus = flags & 3; - int[] outptr = (outbus == 0) ? output : output; + int inBus = (flags >> 4) & 3; + int outBus = flags & 3; + int[] outPtr = (outBus == 0) ? output : output; // maybe align or not int gain1 = param.gain[0]; int gain2 = param.gain[1]; if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { - if (!has_contents[outbus]) { + if (!hasContents[outBus]) { add = false; } - if (inbus == 0 || !has_contents[inbus]) { + if (inBus == 0 || !hasContents[inBus]) { // TODO more than one op in a feedback loop - if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { - // Debug.println(op + " fb " + inbus + outbus + add); - FmOpKernel.compute_fb(outptr, param.phase, param.freq, gain1, gain2, fb_buf, feedback_shift, add); + if ((flags & 0xc0) == 0xc0 && feedbackShift < 16) { + // Debug.println(op + " fb " + inBus + outBus + add); + FmOpKernel.computeFb(outPtr, param.phase, param.freq, gain1, gain2, fbBuf, feedbackShift, add); } else { - // Debug.println(op + " pure " + inbus + outbus + add); - FmOpKernel.compute_pure(outptr, param.phase, param.freq, gain1, gain2, add); + // Debug.println(op + " pure " + inBus + outBus + add); + FmOpKernel.computePure(outPtr, param.phase, param.freq, gain1, gain2, add); } } else { - // Debug.println(op + " normal " + inbus + outbus + " " + param.freq + add); - FmOpKernel.compute(outptr, outptr, param.phase, param.freq, gain1, gain2, add); // TODO 2nd outptr + // Debug.println(op + " normal " + inBus + outBus + " " + param.freq + add); + FmOpKernel.compute(outPtr, outPtr, param.phase, param.freq, gain1, gain2, add); // TODO 2nd outPtr } - has_contents[outbus] = true; + hasContents[outBus] = true; } else if (!add) { - has_contents[outbus] = false; + hasContents[outBus] = false; } param.phase += param.freq << Note.LG_N; } diff --git a/src/main/java/vavi/sound/dx7/FmOpKernel.java b/src/main/java/vavi/sound/dx7/FmOpKernel.java index b2d09df..711c1fe 100644 --- a/src/main/java/vavi/sound/dx7/FmOpKernel.java +++ b/src/main/java/vavi/sound/dx7/FmOpKernel.java @@ -19,20 +19,20 @@ class FmOpKernel { - public static void compute(int[] output, final int[] input, int phase0, int freq, int gain1, int gain2, boolean add) { - int dgain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; + public static void compute(int[] output, int[] input, int phase0, int freq, int gain1, int gain2, boolean add) { + int dGain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; int gain = gain1; int phase = phase0; if (add) { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int y = Sin.lookup(phase + input[i]); output[i] += (int) (((long) y * (long) gain) >> 24); phase += freq; } } else { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int y = Sin.lookup(phase + input[i]); output[i] = (int) (((long) y * (long) gain) >> 24); phase += freq; @@ -40,20 +40,20 @@ public static void compute(int[] output, final int[] input, int phase0, int freq } } - public static void compute_pure(int[] output, int phase0, int freq, int gain1, int gain2, boolean add) { - int dgain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; + public static void computePure(int[] output, int phase0, int freq, int gain1, int gain2, boolean add) { + int dGain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; int gain = gain1; int phase = phase0; if (add) { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int y = Sin.lookup(phase); output[i] += (int) (((long) y * (long) gain) >> 24); phase += freq; } } else { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int y = Sin.lookup(phase); output[i] = (int) (((long) y * (long) gain) >> 24); phase += freq; @@ -61,15 +61,15 @@ public static void compute_pure(int[] output, int phase0, int freq, int gain1, i } } - public static void compute_fb(int[] output, int phase0, int freq, int gain1, int gain2, int[] fb_buf, int fb_shift, boolean add) { - int dgain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; + public static void computeFb(int[] output, int phase0, int freq, int gain1, int gain2, int[] fbBuf, int fb_shift, boolean add) { + int dGain = (gain2 - gain1 + (Note.N >> 1)) >> Note.LG_N; int gain = gain1; int phase = phase0; - int y0 = fb_buf[0]; - int y = fb_buf[1]; + int y0 = fbBuf[0]; + int y = fbBuf[1]; if (add) { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int scaled_fb = (y0 + y) >> (fb_shift + 1); y0 = y; y = Sin.lookup(phase + scaled_fb); @@ -79,7 +79,7 @@ public static void compute_fb(int[] output, int phase0, int freq, int gain1, int } } else { for (int i = 0; i < Note.N; i++) { - gain += dgain; + gain += dGain; int scaled_fb = (y0 + y) >> (fb_shift + 1); y0 = y; y = Sin.lookup(phase + scaled_fb); @@ -88,7 +88,7 @@ public static void compute_fb(int[] output, int phase0, int freq, int gain1, int phase += freq; } } - fb_buf[0] = y0; - fb_buf[1] = y; + fbBuf[0] = y0; + fbBuf[1] = y; } } diff --git a/src/main/java/vavi/sound/dx7/Freqlut.java b/src/main/java/vavi/sound/dx7/FreqLut.java similarity index 70% rename from src/main/java/vavi/sound/dx7/Freqlut.java rename to src/main/java/vavi/sound/dx7/FreqLut.java index a90d1c0..05bb758 100644 --- a/src/main/java/vavi/sound/dx7/Freqlut.java +++ b/src/main/java/vavi/sound/dx7/FreqLut.java @@ -23,16 +23,16 @@ * The LUT is just a global, and we'll need the init function to be called before * use. */ -public class Freqlut { +public class FreqLut { private static final int LG_N_SAMPLES = 10; private static final int N_SAMPLES = 1 << LG_N_SAMPLES; private static final int SAMPLE_SHIFT = 24 - LG_N_SAMPLES; private static final int MAX_LOGFREQ_INT = 20; - private static int[] lut = new int[N_SAMPLES + 1]; + private int[] lut = new int[N_SAMPLES + 1]; - public static void init(double sample_rate) { - double y = (1L << (24 + MAX_LOGFREQ_INT)) / sample_rate; + FreqLut(double sampleRate) { + double y = (1L << (24 + MAX_LOGFREQ_INT)) / sampleRate; double inc = Math.pow(2, 1.0 / N_SAMPLES); for (int i = 0; i < N_SAMPLES + 1; i++) { lut[i] = (int) Math.floor(y + 0.5); @@ -40,16 +40,16 @@ public static void init(double sample_rate) { } } - // Note: if logfreq is more than 20.0, the results will be inaccurate. However, + // Note: if logFreq is more than 20.0, the results will be inaccurate. However, // that will be many times the Nyquist rate. - public static int lookup(int logfreq) { - int ix = (logfreq & 0xffffff) >> SAMPLE_SHIFT; + public int lookup(int logFreq) { + int ix = (logFreq & 0xffffff) >> SAMPLE_SHIFT; int y0 = lut[ix]; int y1 = lut[ix + 1]; - int lowbits = logfreq & ((1 << SAMPLE_SHIFT) - 1); - int y = (int) (y0 + ((((long) (y1 - y0) * (long) lowbits)) >> SAMPLE_SHIFT)); - int hibits = logfreq >> 24; - return y >> (MAX_LOGFREQ_INT - hibits); + int lowBits = logFreq & ((1 << SAMPLE_SHIFT) - 1); + int y = (int) (y0 + ((((long) (y1 - y0) * (long) lowBits)) >> SAMPLE_SHIFT)); + int hiBits = logFreq >> 24; + return y >> (MAX_LOGFREQ_INT - hiBits); } } diff --git a/src/main/java/vavi/sound/dx7/Lfo.java b/src/main/java/vavi/sound/dx7/Lfo.java index 95648d2..a69fc21 100644 --- a/src/main/java/vavi/sound/dx7/Lfo.java +++ b/src/main/java/vavi/sound/dx7/Lfo.java @@ -22,90 +22,90 @@ */ public class Lfo { - private long phase_; // Q32 - private long delta_; - private byte waveform_; - private byte randstate_; - private boolean sync_; + private long phase; // Q32 + private long delta; + private byte waveform; + private byte randState; + private boolean sync; - private long delaystate_; - private long delayinc_; - private long delayinc2_; + private long delayState; + private long delayInc; + private long delayInc2; - private static int unit_; + private static long unit; - public static void init(double sample_rate) { - // finalant is 1 << 32 / 15.5s / 11 - unit_ = (int) (Note.N * 25190424 / sample_rate + 0.5); + Lfo(double sampleRate) { + // constant is 1 << 32 / 15.5s / 11 + unit = (int) (Note.N * 25190424 / sampleRate + 0.5); } - public void reset(final byte[] params, int ofs) { + public void reset(byte[] params, int ofs) { int rate = params[ofs + 0]; // 0..99 int sr = rate == 0 ? 1 : (165 * rate) >> 6; sr *= sr < 160 ? 11 : (11 + ((sr - 160) >> 4)); - delta_ = unit_ * sr; + delta = unit * sr; int a = 99 - params[ofs + 1]; // LFO delay if (a == 99) { - delayinc_ = ~0; - delayinc2_ = ~0; + delayInc = ~0; + delayInc2 = ~0; } else { a = (16 + (a & 15)) << (1 + (a >> 4)); - delayinc_ = unit_ * a; + delayInc = unit * a; a &= 0xff80; a = Math.max(0x80, a); - delayinc2_ = unit_ * a; + delayInc2 = unit * a; } - waveform_ = params[ofs + 5]; - sync_ = params[ofs + 4] != 0; + waveform = params[ofs + 5]; + sync = params[ofs + 4] != 0; } // result is 0..1 in Q24 - public int getsample() { - phase_ += delta_; + public int getSample() { + phase += delta; int x; - switch (waveform_) { + switch (waveform) { case 0: // triangle - x = (int) (phase_ >> 7); - x ^= -(phase_ >> 31); + x = (int) (phase >> 7); + x ^= -(phase >> 31); x &= (1 << 24) - 1; return x; case 1: // sawtooth down - return (int) ((~phase_ ^ (1 << 31)) >> 8); + return (int) ((~phase ^ (1 << 31)) >> 8); case 2: // sawtooth up - return (int) ((phase_ ^ (1 << 31)) >> 8); + return (int) ((phase ^ (1 << 31)) >> 8); case 3: // square - return (int) (((~phase_) >> 7) & (1 << 24)); + return (int) (((~phase) >> 7) & (1 << 24)); case 4: // sine - return (1 << 23) + (Sin.lookup((int) (phase_ >> 8)) >> 1); + return (1 << 23) + (Sin.lookup((int) (phase >> 8)) >> 1); case 5: // s&h - if (phase_ < delta_) { - randstate_ = (byte) ((randstate_ * 179 + 17) & 0xff); + if (phase < delta) { + randState = (byte) ((randState * 179 + 17) & 0xff); } - x = randstate_ ^ 0x80; + x = randState ^ 0x80; return (x + 1) << 16; } return 1 << 23; } // result is 0..1 in Q24 - public int getdelay() { - int delta = (int) (delaystate_ < (1 << 31) ? delayinc_ : delayinc2_); - int d = (int) (delaystate_ + delta); - if (d < delayinc_) { + public int getDelay() { + long delta = (delayState < (1L << 31) ? delayInc : delayInc2); + long d = delayState + delta; + if (d < delayInc) { return 1 << 24; } - delaystate_ = d; - if (d < (1 << 31)) { + delayState = d; + if (d < (1L << 31)) { return 0; } else { - return (d >> 7) & ((1 << 24) - 1); + return (int) ((d >> 7) & ((1 << 24) - 1)); } } - public void keydown() { - if (sync_) { - phase_ = (1 << 31) - 1; + public void keyDown() { + if (sync) { + phase = (1L << 31) - 1; } - delaystate_ = 0; + delayState = 0; } } diff --git a/src/main/java/vavi/sound/dx7/Note.java b/src/main/java/vavi/sound/dx7/Note.java index 1d9250a..42f914e 100644 --- a/src/main/java/vavi/sound/dx7/Note.java +++ b/src/main/java/vavi/sound/dx7/Note.java @@ -26,51 +26,51 @@ public class Note { public static final int LG_N = 6; public static final int N = 1 << LG_N; - private FmCore core_ = new FmCore(); - private Env[] env_ = new Env[6]; + private FmCore core = new FmCore(); + private Env[] env = new Env[6]; private FmCore.FmOpParams[] params_ = new FmCore.FmOpParams[6]; - private PitchEnv pitchenv_; + private Context context; private int[] basepitch_ = new int[6]; private int[] fb_buf_ = new int[2]; - private int fb_shift_; - private int algorithm_; - private int pitchmoddepth_; - private int pitchmodsens_; + private int fbShift; + private int algorithm; + private int pitchModDepth; + private int pitchModSens; - private int midinoteToLogfreq(int midinote) { + private int midiNoteToLogFreq(int midiNote) { final int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12) final int step = (1 << 24) / 12; - return base + step * midinote; + return base + step * midiNote; } - private static final int[] coarsemul = { + private static final int[] coarseMul = { -16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600, 50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816, 65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858, 74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032, 81503396, 82323963, 83117622 }; - private int oscFreq(int midinote, int mode, int coarse, int fine, int detune) { + private int oscFreq(int midiNote, int mode, int coarse, int fine, int detune) { // TODO: pitch randomization - int logfreq; + int logFreq; if (mode == 0) { - logfreq = midinoteToLogfreq(midinote); - logfreq += coarsemul[coarse & 31]; + logFreq = midiNoteToLogFreq(midiNote); + logFreq += coarseMul[coarse & 31]; if (fine != 0) { // (1 << 24) / log(2) - logfreq += (int) Math.floor(24204406.323123 * Math.log(1 + 0.01 * fine) + 0.5); + logFreq += (int) Math.floor(24204406.323123 * Math.log(1 + 0.01 * fine) + 0.5); } // This was measured at 7.213Hz per count at 9600Hz, but the exact - // value is somewhat dependent on midinote. Close enough for now. - logfreq += 12606 * (detune - 7); + // value is somewhat dependent on midiNote. Close enough for now. + logFreq += 12606 * (detune - 7); } else { // ((1 << 24) * log(10) / log(2) * .01) << 3 - logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; - logfreq += detune > 7 ? 13457 * (detune - 7) : 0; + logFreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; + logFreq += detune > 7 ? 13457 * (detune - 7) : 0; } - return logfreq; + return logFreq; } - private static final int[] velocity_data = { + private static final int[] velocityData = { 0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163, 166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202, 205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232, 233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251, 252, 253, 254 @@ -78,27 +78,27 @@ private int oscFreq(int midinote, int mode, int coarse, int fine, int detune) { // See "velocity" section of notes. Returns velocity delta in microsteps. private int scaleVelocity(int velocity, int sensitivity) { - int clamped_vel = Math.max(0, Math.min(127, velocity)); - int vel_value = velocity_data[clamped_vel >> 1] - 239; - int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4; - return scaled_vel; + int clampedVel = Math.max(0, Math.min(127, velocity)); + int velValue = velocityData[clampedVel >> 1] - 239; + int scaledVel = ((sensitivity * velValue + 7) >> 3) << 4; + return scaledVel; } - private int scaleRate(int midinote, int sensitivity) { - int x = Math.min(31, Math.max(0, midinote / 3 - 7)); - int qratedelta = (sensitivity * x) >> 3; + private int scaleRate(int midiNote, int sensitivity) { + int x = Math.min(31, Math.max(0, midiNote / 3 - 7)); + int qrateDelta = (sensitivity * x) >> 3; int rem = x & 7; if (sensitivity == 3 && rem == 3) { - qratedelta -= 1; + qrateDelta -= 1; } else if (sensitivity == 7 && rem > 0 && rem < 4) { - qratedelta += 1; + qrateDelta += 1; } - return qratedelta; + return qrateDelta; } - private static final int[] exp_scale_data = { + private static final int[] expScaleData = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66, 80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250 }; @@ -110,9 +110,9 @@ private int scaleCurve(int group, int depth, int curve) { scale = (group * depth * 329) >> 12; } else { // exponential - int n_scale_data = exp_scale_data.length; - int raw_exp = exp_scale_data[Math.min(group, n_scale_data - 1)]; - scale = (raw_exp * depth * 329) >> 15; + int nScaleData = expScaleData.length; + int rawExp = expScaleData[Math.min(group, nScaleData - 1)]; + scale = (rawExp * depth * 329) >> 15; } if (curve < 2) { scale = -scale; @@ -120,20 +120,21 @@ private int scaleCurve(int group, int depth, int curve) { return scale; } - private int scaleLevel(int midinote, int break_pt, int left_depth, int right_depth, int left_curve, int right_curve) { - int offset = midinote - break_pt - 17; + private int scaleLevel(int midiNote, int breakPt, int leftDepth, int rightDepth, int leftCurve, int rightCurve) { + int offset = midiNote - breakPt - 17; if (offset >= 0) { - return scaleCurve(offset / 3, right_depth, right_curve); + return scaleCurve(offset / 3, rightDepth, rightCurve); } else { - return scaleCurve((-offset) / 3, left_depth, left_curve); + return scaleCurve((-offset) / 3, leftDepth, leftCurve); } } - private static final int[] pitchmodsenstab = { + private static final int[] pitchModSensTab = { 0, 10, 20, 33, 55, 92, 153, 255 }; - public Note(final byte[] patch, int midinote, int velocity) { + public Note(Context context, byte[] patch, int midiNote, int velocity) { + this.context = context; int[] rates = new int[4]; int[] levels = new int[4]; for (int op = 0; op < 6; op++) { @@ -142,35 +143,35 @@ public Note(final byte[] patch, int midinote, int velocity) { rates[i] = patch[off + i]; levels[i] = patch[off + 4 + i]; } - int outlevel = patch[off + 16]; - outlevel = Env.scaleoutlevel(outlevel); + int outLevel = patch[off + 16]; + outLevel = Env.scaleOutLevel(outLevel); for (int j = 8; j < 12; j++) { Debug.println(Level.FINE, patch[off + j] + " "); } - int level_scaling = scaleLevel(midinote, - patch[off + 8], - patch[off + 9], - patch[off + 10], - patch[off + 11], - patch[off + 12]); - outlevel += level_scaling; - outlevel = Math.min(127, outlevel); + int scaleLevel = scaleLevel(midiNote, + patch[off + 8], + patch[off + 9], + patch[off + 10], + patch[off + 11], + patch[off + 12]); + outLevel += scaleLevel; + outLevel = Math.min(127, outLevel); - Debug.println(Level.FINE, op + ": " + level_scaling + " " + outlevel); + Debug.println(Level.FINE, op + ": " + scaleLevel + " " + outLevel); - outlevel = outlevel << 5; - outlevel += scaleVelocity(velocity, patch[off + 15]); - outlevel = Math.max(0, outlevel); - int rate_scaling = scaleRate(midinote, patch[off + 13]); - env_[op] = new Env(rates, levels, outlevel, rate_scaling); + outLevel = outLevel << 5; + outLevel += scaleVelocity(velocity, patch[off + 15]); + outLevel = Math.max(0, outLevel); + int rateScaling = scaleRate(midiNote, patch[off + 13]); + env[op] = new Env(rates, levels, outLevel, rateScaling); int mode = patch[off + 17]; int coarse = patch[off + 18]; int fine = patch[off + 19]; int detune = patch[off + 20]; - int freq = oscFreq(midinote, mode, coarse, fine, detune); + int freq = oscFreq(midiNote, mode, coarse, fine, detune); basepitch_[op] = freq; // cout << op << " freq: " << freq << endl; params_[op] = new FmCore.FmOpParams(); @@ -181,50 +182,49 @@ public Note(final byte[] patch, int midinote, int velocity) { rates[i] = patch[126 + i]; levels[i] = patch[130 + i]; } - pitchenv_ = new PitchEnv(); - pitchenv_.set(rates, levels); - algorithm_ = patch[134]; + context.pitchEnv.set(rates, levels); + algorithm = patch[134]; int feedback = patch[135]; - fb_shift_ = feedback != 0 ? 8 - feedback : 16; - pitchmoddepth_ = (patch[139] * 165) >> 6; - pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; + fbShift = feedback != 0 ? 8 - feedback : 16; + pitchModDepth = (patch[139] * 165) >> 6; + pitchModSens = pitchModSensTab[patch[143] & 7]; } static final int kControllerPitch = 128; public static class Controllers { - public int[] values_ = new int[129]; + public int[] values = new int[129]; public Controllers(int value) { - values_[kControllerPitch] = value; + values[kControllerPitch] = value; } } - public void compute(int[] buf, int lfo_val, int lfo_delay, final Controllers ctrls) { - int pitchmod = pitchenv_.getsample(); - long pmd = pitchmoddepth_ * lfo_delay; // Q32 + public void compute(int[] buf, int lfoVal, int lfoDelay, Controllers ctrls) { + int pitchMod = context.pitchEnv.getSample(); + long pmd = (long) pitchModDepth * lfoDelay; // Q32 // TODO: add modulation sources (mod wheel, etc) - int senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); - pitchmod += (int) ((pmd * senslfo) >> 39); + int sensLfo = pitchModSens * (lfoVal - (1 << 23)); + pitchMod += (int) ((pmd * sensLfo) >> 39); - // hardcodes a pitchbend range of 3 semitones, TODO make configurable - int pitchbend = ctrls.values_[kControllerPitch]; - int pb = (pitchbend - 0x2000) << 9; - pitchmod += pb; + // hardcodes a pitchBend range of 3 semitones, TODO make configurable + int pitchBend = ctrls.values[kControllerPitch]; + int pb = (pitchBend - 0x2000) << 9; + pitchMod += pb; for (int op = 0; op < 6; op++) { params_[op].gain[0] = params_[op].gain[1]; - int level = env_[op].getsample(); + int level = env[op].getSample(); int gain = Exp2.lookup(level - (14 * (1 << 24))); // int gain = pow(2, 10 + level * (1.0 / (1 << 24))); - params_[op].freq = Freqlut.lookup(basepitch_[op] + pitchmod); + params_[op].freq = context.freqLut.lookup(basepitch_[op] + pitchMod); params_[op].gain[1] = gain; } - core_.compute(buf, params_, algorithm_, fb_buf_, fb_shift_); + core.compute(buf, params_, algorithm, fb_buf_, fbShift); } - public void keyup() { + public void keyUp() { for (int op = 0; op < 6; op++) { - env_[op].keydown(false); - pitchenv_.keydown(false); + env[op].keyDown(false); + context.pitchEnv.keyDown(false); } } } diff --git a/src/main/java/vavi/sound/dx7/Patch.java b/src/main/java/vavi/sound/dx7/Patch.java index f711e58..aaa119b 100644 --- a/src/main/java/vavi/sound/dx7/Patch.java +++ b/src/main/java/vavi/sound/dx7/Patch.java @@ -24,34 +24,34 @@ */ class Patch { - public static void unpackPatch(final byte[] bulk, byte[] patch) { + public static void unpackPatch(byte[] bulk, byte[] patch) { for (int op = 0; op < 6; op++) { // eg rate and level, brk pt, depth, scaling System.arraycopy(bulk, op * 17, patch, op * 21, 11); - byte leftrightcurves = bulk[op * 17 + 11]; - patch[op * 21 + 11] = (byte) (leftrightcurves & 3); - patch[op * 21 + 12] = (byte) ((leftrightcurves >> 2) & 3); - byte detune_rs = bulk[op * 17 + 12]; - patch[op * 21 + 13] = (byte) (detune_rs & 7); - patch[op * 21 + 20] = (byte) (detune_rs >> 3); - byte kvs_ams = bulk[op * 17 + 13]; - patch[op * 21 + 14] = (byte) (kvs_ams & 3); - patch[op * 21 + 15] = (byte) (kvs_ams >> 2); + byte leftRightCurves = bulk[op * 17 + 11]; + patch[op * 21 + 11] = (byte) (leftRightCurves & 3); + patch[op * 21 + 12] = (byte) ((leftRightCurves >> 2) & 3); + byte detuneRs = bulk[op * 17 + 12]; + patch[op * 21 + 13] = (byte) (detuneRs & 7); + patch[op * 21 + 20] = (byte) (detuneRs >> 3); + byte kvsAms = bulk[op * 17 + 13]; + patch[op * 21 + 14] = (byte) (kvsAms & 3); + patch[op * 21 + 15] = (byte) (kvsAms >> 2); patch[op * 21 + 16] = bulk[op * 17 + 14]; // output level - byte fcoarse_mode = bulk[op * 17 + 15]; - patch[op * 21 + 17] = (byte) (fcoarse_mode & 1); - patch[op * 21 + 18] = (byte) (fcoarse_mode >> 1); + byte fCoarseMode = bulk[op * 17 + 15]; + patch[op * 21 + 17] = (byte) (fCoarseMode & 1); + patch[op * 21 + 18] = (byte) (fCoarseMode >> 1); patch[op * 21 + 19] = bulk[op * 17 + 16]; // fine freq } System.arraycopy(bulk, 102, patch, 126, 9); // pitch env, algo - byte oks_fb = bulk[111]; - patch[135] = (byte) (oks_fb & 7); - patch[136] = (byte) (oks_fb >> 3); + byte oksFb = bulk[111]; + patch[135] = (byte) (oksFb & 7); + patch[136] = (byte) (oksFb >> 3); System.arraycopy(bulk, 112, patch, 137, 4); // lfo - byte lpms_lfw_lks = bulk[116]; - patch[141] = (byte) (lpms_lfw_lks & 1); - patch[142] = (byte) ((lpms_lfw_lks >> 1) & 7); - patch[143] = (byte) (lpms_lfw_lks >> 4); + byte lpmsLfwLks = bulk[116]; + patch[141] = (byte) (lpmsLfwLks & 1); + patch[142] = (byte) ((lpmsLfwLks >> 1) & 7); + patch[143] = (byte) (lpmsLfwLks >> 4); System.arraycopy(bulk, 117, patch, 144, 11); // transpose, name patch[155] = 0x3f; // operator on/off @@ -61,12 +61,12 @@ public static void unpackPatch(final byte[] bulk, byte[] patch) { private static int clamped = 0; // not thread safe - private static int file_clamped = 0; // not thread safe + private static int fileClamped = 0; // not thread safe private static byte clamp(byte byte_, int pos, byte max) { if (byte_ > max || byte_ < 0) { clamped++; - Debug.printf("file %d clamped %d pos %d was %d is %d\n", file_clamped, clamped, pos, byte_, max); + Debug.printf("file %d clamped %d pos %d was %d is %d\n", fileClamped, clamped, pos, byte_, max); return max; } return byte_; @@ -95,7 +95,7 @@ private static void checkPatch(byte[] patch) { patch[i] = clamp(patch[i], i, max[i]); } if (clamped != 0) - file_clamped++; + fileClamped++; clamped = 0; } } diff --git a/src/main/java/vavi/sound/dx7/PitchEnv.java b/src/main/java/vavi/sound/dx7/PitchEnv.java index 4798d17..54583ba 100644 --- a/src/main/java/vavi/sound/dx7/PitchEnv.java +++ b/src/main/java/vavi/sound/dx7/PitchEnv.java @@ -19,80 +19,80 @@ public class PitchEnv { - private int[] rates_ = new int[4]; - private int[] levels_ = new int[4]; - private int level_; - private int targetlevel_; - private boolean rising_; - private int ix_; - private int inc_; + private int[] rates = new int[4]; + private int[] levels = new int[4]; + private int level; + private int targetLevel; + private boolean rising; + private int ix; + private int inc; - private boolean down_; + private boolean down; - private static int unit_; + private int unit; - public static void init(double sample_rate) { - unit_ = (int) (Note.N * (1 << 24) / (21.3 * sample_rate) + 0.5); + PitchEnv(double sampleRate) { + unit = (int) (Note.N * (1 << 24) / (21.3 * sampleRate) + 0.5); } - private static int ratetab[] = { + private static final int[] rateTab = { 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 33, 34, 36, 37, 38, 39, 41, 42, 44, 46, 47, 49, 51, 53, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 79, 82, 85, 88, 91, 94, 98, 102, 106, 110, 115, 120, 125, 130, 135, 141, 147, 153, 159, 165, 171, 178, 185, 193, 202, 211, 232, 243, 254, 255 }; - private static int pitchtab[] = { + private static final int[] pitchTab = { -128, -116, -104, -95, -85, -76, -68, -61, -56, -52, -49, -46, -43, -41, -39, -37, -35, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 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, 38, 40, 43, 46, 49, 53, 58, 65, 73, 82, 92, 103, 115, 127 }; - public void set(final int[] r, final int[] l) { + public void set(int[] r, int[] l) { for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; + rates[i] = r[i]; + levels[i] = l[i]; } - level_ = pitchtab[l[3]] << 19; - down_ = true; + level = pitchTab[l[3]] << 19; + down = true; advance(0); } - public int getsample() { - if (ix_ < 3 || (ix_ < 4) && !down_) { - if (rising_) { - level_ += inc_; - if (level_ >= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); + public int getSample() { + if (ix < 3 || (ix < 4) && !down) { + if (rising) { + level += inc; + if (level >= targetLevel) { + level = targetLevel; + advance(ix + 1); } } else { // !rising - level_ -= inc_; - if (level_ <= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); + level -= inc; + if (level <= targetLevel) { + level = targetLevel; + advance(ix + 1); } } } - return level_; + return level; } - public void keydown(boolean d) { - if (down_ != d) { - down_ = d; + public void keyDown(boolean d) { + if (down != d) { + down = d; advance(d ? 0 : 3); } } - public void advance(int newix) { - ix_ = newix; - if (ix_ < 4) { - int newlevel = levels_[ix_]; - targetlevel_ = pitchtab[newlevel] << 19; - rising_ = (targetlevel_ > level_); + public void advance(int newIx) { + ix = newIx; + if (ix < 4) { + int newLevel = levels[ix]; + targetLevel = pitchTab[newLevel] << 19; + rising = (targetLevel > level); - inc_ = ratetab[rates_[ix_]] * unit_; + inc = rateTab[rates[ix]] * unit; } } } diff --git a/src/main/java/vavi/sound/dx7/ResoFilter.java b/src/main/java/vavi/sound/dx7/ResoFilter.java index bc9913f..17cc3ab 100644 --- a/src/main/java/vavi/sound/dx7/ResoFilter.java +++ b/src/main/java/vavi/sound/dx7/ResoFilter.java @@ -27,30 +27,27 @@ */ public class ResoFilter { -// private static double this_sample_rate; - -// public static void init(double sample_rate) { -// this_sample_rate = sample_rate; -// } - private int[] x = new int[4]; private int[] w = new int[4]; private int yy; - public ResoFilter() { + private Context context; + + public ResoFilter(Context context) { for (int i = 0; i < 4; i++) { x[i] = 0; w[i] = 0; } + this.context = context; } - private static int compute_alpha(int logf) { - return Math.min(1 << 24, Freqlut.lookup(logf)); + private int computeAlpha(int logf) { + return Math.min(1 << 24, context.freqLut.lookup(logf)); } // Some really generic 4x4 matrix multiplication operations, suitable // for NEON'ing - private static void matmult4(float[] dst, int dP, final float[] a, int aP, final float[] b, int bP) { + private static void matMult4(float[] dst, int dP, float[] a, int aP, float[] b, int bP) { dst[dP + 0] = a[aP + 0] * b[bP + 0] + a[aP + 4] * b[bP + 1] + a[aP + 8] * b[bP + 2] + a[aP + 12] * b[bP + 3]; dst[dP + 1] = a[aP + 1] * b[bP + 0] + a[aP + 5] * b[bP + 1] + a[aP + 9] * b[bP + 2] + a[aP + 13] * b[bP + 3]; dst[dP + 2] = a[aP + 2] * b[bP + 0] + a[aP + 6] * b[bP + 1] + a[aP + 10] * b[bP + 2] + a[aP + 14] * b[bP + 3]; @@ -69,27 +66,27 @@ private static void matmult4(float[] dst, int dP, final float[] a, int aP, final dst[dP + 15] = a[aP + 3] * b[bP + 12] + a[aP + 7] * b[bP + 13] + a[aP + 11] * b[bP + 14] + a[aP + 15] * b[bP + 15]; } - private static void matvec4(float[] dst, int dP, final float[] a, int aP, final float[] b, int bP) { + private static void matVec4(float[] dst, int dP, float[] a, int aP, float[] b, int bP) { dst[dP + 0] = a[aP + 0] * b[bP + 0] + a[aP + 4] * b[bP + 1] + a[aP + 8] * b[bP + 2] + a[aP + 12] * b[bP + 3]; dst[dP + 1] = a[aP + 1] * b[bP + 0] + a[aP + 5] * b[bP + 1] + a[aP + 9] * b[bP + 2] + a[aP + 13] * b[bP + 3]; dst[dP + 2] = a[aP + 2] * b[bP + 0] + a[aP + 6] * b[bP + 1] + a[aP + 10] * b[bP + 2] + a[aP + 14] * b[bP + 3]; dst[dP + 3] = a[aP + 3] * b[bP + 0] + a[aP + 7] * b[bP + 1] + a[aP + 11] * b[bP + 2] + a[aP + 15] * b[bP + 3]; } - private static void vecupdate4(float[] dst, float x, final float[] a) { + private static void vecUpdate4(float[] dst, float x, float[] a) { for (int i = 0; i < 4; i++) { dst[i] += x * a[i]; } } /* compute dst := dst + x * a */ - private static void matupdate4(float[] dst, int dP, float x, final float[] a, int aP) { + private static void matUpdate4(float[] dst, int dP, float x, float[] a, int aP) { for (int i = 0; i < 16; i++) { dst[i + dP] += x * a[i + aP]; } } - private static void dump_matrix(final float[] a) { + private static void dumpMatrix(float[] a) { for (int row = 0; row < 5; row++) { System.err.printf("%s[", row == 0 ? "[" : " "); for (int col = 0; col < 5; col++) { @@ -100,13 +97,13 @@ private static void dump_matrix(final float[] a) { } } - private static void make_state_transition(float[] result, int f0, int k) { + private static void makeStateTransition(float[] result, int f0, int k) { // TODO: these should depend on k, and be just enough to meet error bound int n1 = 4; int n2 = 4; float f = f0 * (1.0f / (1 << (24 + n2))); - float k_f = k * (1.0f / (1 << 24)); - k_f = Math.min(k_f, 3.98f); + float kF = k * (1.0f / (1 << 24)); + kF = Math.min(kF, 3.98f); // these are 5x5 matrices of which we store the bottom 5x4 // Top row of Jacobian is all zeros @@ -120,7 +117,7 @@ private static void make_state_transition(float[] result, int f0, int k) { j[10] = f; j[14] = -f; j[15] = f; - j[16] = -k_f * f; + j[16] = -kF * f; j[19] = -f; // Top row of exponential is [1 0 0 0 0] @@ -134,16 +131,16 @@ private static void make_state_transition(float[] result, int f0, int k) { float[] c = new float[20]; System.arraycopy(j, 0, c, 0, 20); - final float[] scales = { 1.0f, 1 / 2.0f, 1 / 6.0f, 1 / 24.0f }; + float[] scales = { 1.0f, 1 / 2.0f, 1 / 6.0f, 1 / 24.0f }; // taylor's series to n1 for (int i = 0; i < n1; i++) { float scale = scales[i]; - vecupdate4(a, scale, c); - matupdate4(a, 4, scale, c, 4); + vecUpdate4(a, scale, c); + matUpdate4(a, 4, scale, c, 4); if (i < n1 - 1) { float[] tmp = new float[20]; - matvec4(tmp, 0, c, 4, j, 0); - matmult4(tmp, 4, c, 4, j, 4); + matVec4(tmp, 0, c, 4, j, 0); + matMult4(tmp, 4, c, 4, j, 4); System.arraycopy(tmp, 0, c, 0, 20); } } @@ -151,8 +148,8 @@ private static void make_state_transition(float[] result, int f0, int k) { // repeated squaring for (int i = 0; i < n2; i++) { float[] tmp = new float[20]; - matvec4(tmp, 0, a, 4, a, 0); - matmult4(tmp, 4, a, 4, a, 4); + matVec4(tmp, 0, a, 4, a, 0); + matMult4(tmp, 4, a, 4, a, 4); for (int l = 0; l < 4; l++) { a[l] += tmp[l]; } @@ -162,28 +159,28 @@ private static void make_state_transition(float[] result, int f0, int k) { System.arraycopy(a, 0, result, 0, 20); } - static void test_matrix() { + static void testMatrix() { float[] params = { 1.0f, 3.99f }; float[] a = new float[20]; - make_state_transition(a, (int) (params[0] * (1 << 24)), (int) (params[1] * (1 << 24))); - dump_matrix(a); + makeStateTransition(a, (int) (params[0] * (1 << 24)), (int) (params[1] * (1 << 24))); + dumpMatrix(a); } - public void process(final int[][] inbufs, final int[] control_in, final int[] control_last, int[][] outbufs) { - int alpha = compute_alpha(control_last[0]); - int alpha_in = compute_alpha(control_in[0]); - int delta_alpha = (alpha_in - alpha) >> Note.LG_N; - int k = control_last[1]; - int k_in = control_in[1]; - int delta_k = (k_in - k) >> Note.LG_N; - if ((((long) alpha_in * (long) k_in) >> 24) > 1 << 24) { - k_in = ((1 << 30) / alpha_in) << 18; + public void process(int[][] inBufs, int[] controlIn, int[] controlLast, int[][] outBufs) { + int alpha = computeAlpha(controlLast[0]); + int alphaIn = computeAlpha(controlIn[0]); + int deltaAlpha = (alphaIn - alpha) >> Note.LG_N; + int k = controlLast[1]; + int kIn = controlIn[1]; + int deltaK = (kIn - k) >> Note.LG_N; + if ((((long) alphaIn * (long) kIn) >> 24) > 1 << 24) { + kIn = ((1 << 30) / alphaIn) << 18; } if ((((long) alpha * (long) k) >> 24) > 1 << 24) { k = ((1 << 30) / alpha) << 18; } - final int[] ibuf = inbufs[0]; - int[] obuf = outbufs[0]; + int[] iBuf = inBufs[0]; + int[] obuf = outBufs[0]; int x0 = x[0]; int x1 = x[1]; int x2 = x[2]; @@ -194,9 +191,9 @@ public void process(final int[][] inbufs, final int[] control_in, final int[] co int w3 = w[3]; int yy0 = yy; for (int i = 0; i < Note.N; i++) { - alpha += delta_alpha; - k += delta_k; - int signal = ibuf[i]; + alpha += deltaAlpha; + k += deltaK; + int signal = iBuf[i]; int fb = (int) (((long) k * (long) (x3 + yy0)) >> 25); yy0 = x3; int rx = signal - fb; diff --git a/src/main/java/vavi/sound/dx7/Sawtooth.java b/src/main/java/vavi/sound/dx7/Sawtooth.java index e837bdb..2159c4a 100644 --- a/src/main/java/vavi/sound/dx7/Sawtooth.java +++ b/src/main/java/vavi/sound/dx7/Sawtooth.java @@ -16,6 +16,8 @@ package vavi.sound.dx7; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import vavi.util.Debug; @@ -24,163 +26,175 @@ class Sawtooth { @SuppressWarnings("unused") - private static final int R = (1 << 29); + private static final int R = 1 << 29; private static final int LG_N_SAMPLES = 10; - private static final int N_SAMPLES = (1 << LG_N_SAMPLES); - private static final int N_PARTIALS_MAX = (N_SAMPLES / 2); + private static final int N_SAMPLES = 1 << LG_N_SAMPLES; + private static final int N_PARTIALS_MAX = N_SAMPLES / 2; private static final int LG_SLICES_PER_OCTAVE = 2; - private static final int SLICES_PER_OCTAVE = (1 << LG_SLICES_PER_OCTAVE); - private static final int SLICE_SHIFT = (24 - LG_SLICES_PER_OCTAVE); + private static final int SLICES_PER_OCTAVE = 1 << LG_SLICES_PER_OCTAVE; + private static final int SLICE_SHIFT = 24 - LG_SLICES_PER_OCTAVE; private static final int SLICE_EXTRA = 3; private static final int N_SLICES = 36; // 0.5 * (log(440./44100) / log(2) + log(440./48000) / log(2) + 2./12) + 1./64 - 3 in Q24 private static final int SLICE_BASE = 161217316; private static final int LOW_FREQ_LIMIT = -SLICE_BASE; - private static final double NEG2OVERPI = -0.63661977236758138; + private static final double NEG2OVER_PI = -0.63661977236758138; - private static int[][] sawtooth = new int[N_SLICES][N_SAMPLES]; + private int[][] sawTooth = new int[N_SLICES][N_SAMPLES]; - private static int sawtooth_freq_off; + private static int sawToothFreqOff; + + private static Map instances = new HashMap<>(); + + public static Sawtooth getInstance(double sampleRate) { + if (instances.containsKey(sampleRate)) { + return instances.get(sampleRate); + } else { + Sawtooth sawtooth = new Sawtooth(sampleRate); + instances.put(sampleRate, sawtooth); + return sawtooth; + } + } // There's a fair amount of lookup table and so on that needs to be set before // generating any signal. In Java, this would be done by a separate factory class. // Here, we're just going to do it as globals. - public static void init(double sample_rate) { - sawtooth_freq_off = (int) (-(1 << 24) * Math.log(sample_rate) / Math.log(2)); + private void init(double sampleRate) { + sawToothFreqOff = (int) (-(1 << 24) * Math.log(sampleRate) / Math.log(2)); int[] lut = new int[N_SAMPLES / 2]; for (int i = 0; i < N_SAMPLES / 2; i++) { lut[i] = 0; } - double slice_inc = Math.pow(2.0, 1.0 / SLICES_PER_OCTAVE); - double f_0 = Math.pow(slice_inc, N_SLICES - 1) * Math.pow(0.5, SLICE_BASE * 1.0 / (1 << 24)); - int n_partials_last = 0; + double sliceInc = Math.pow(2.0, 1.0 / SLICES_PER_OCTAVE); + double f0 = Math.pow(sliceInc, N_SLICES - 1) * Math.pow(0.5, SLICE_BASE * 1.0 / (1 << 24)); + int nPartialsLast = 0; for (int j = N_SLICES - 1; j >= 0; j--) { - int n_partials = (int) Math.floor(0.5 / f_0); - n_partials = n_partials < N_PARTIALS_MAX ? n_partials : N_PARTIALS_MAX; - // printf("slice %d: n_partials=%d\n", j, n_partials); - for (int k = n_partials_last + 1; k <= n_partials; k++) { - double scale = NEG2OVERPI / k; + int nPartials = (int) Math.floor(0.5 / f0); + nPartials = Math.min(nPartials, N_PARTIALS_MAX); + // System.err.printf("slice %d: nPartials=%d\n", j, nPartials); + for (int k = nPartialsLast + 1; k <= nPartials; k++) { + double scale = NEG2OVER_PI / k; scale = (N_PARTIALS_MAX - k) > (N_PARTIALS_MAX >> 2) ? scale : scale * (N_PARTIALS_MAX - k) / (N_PARTIALS_MAX >> 2); - double dphase = k * 2 * Math.PI / N_SAMPLES; - int maxerr = 0; - double ds_d = (1 << 30) * scale * Math.sin(dphase); - double cm2_d = (1 << 29) * (2 * (Math.cos(dphase) - 1)); - int dshift = 0; - for (dshift = 0; dshift < 16; dshift++) { - if (ds_d < -(1 << (30 - dshift))) + double dPhase = k * 2 * Math.PI / N_SAMPLES; + int maxErr = 0; + double dsD = (1 << 30) * scale * Math.sin(dPhase); + double cm2D = (1 << 29) * (2 * (Math.cos(dPhase) - 1)); + int dShift; + for (dShift = 0; dShift < 16; dShift++) { + if (dsD < -(1 << (30 - dShift))) break; - if (cm2_d < -(1 << (30 - dshift))) + if (cm2D < -(1 << (30 - dShift))) break; } - int ds = (int) Math.floor((1 << dshift) * ds_d + 0.5); - int cm2 = (int) Math.floor((1 << dshift) * cm2_d + 0.5); - // cout << cm2_d << " " << cm2 << " " << dphase << " " << ds << - // " " << dshift << endl; + int ds = (int) Math.floor((1 << dShift) * dsD + 0.5); + int cm2 = (int) Math.floor((1 << dShift) * cm2D + 0.5); + // Debug.println(cm2D + " " + cm2 + " " + dPhase + " " + ds + " " + dShift); int s = 0; - int round = (1 << dshift) >> 1; + int round = (1 << dShift) >> 1; for (int i = 0; i < N_SAMPLES / 2; i++) { lut[i] += s; - int good = (int) Math.floor(scale * Math.sin(dphase * i) * (1 << 30) + 0.5); + int good = (int) Math.floor(scale * Math.sin(dPhase * i) * (1 << 30) + 0.5); int err = s - good; - int abs_err = err > 0 ? err : -err; - maxerr = abs_err > maxerr ? abs_err : maxerr; + int absErr = err > 0 ? err : -err; + maxErr = Math.max(absErr, maxErr); ds += (int) (((long) cm2 * (long) s + (1 << 28)) >> 29); - s += (ds + round) >> dshift; + s += (ds + round) >> dShift; } - Debug.println(Level.FINE, maxerr); + Debug.println(Level.FINE, maxErr); } - sawtooth[j][0] = 0; - sawtooth[j][N_SAMPLES / 2] = 0; + sawTooth[j][0] = 0; + sawTooth[j][N_SAMPLES / 2] = 0; for (int i = 1; i < N_SAMPLES / 2; i++) { int value = (lut[i] + 32) >> 6; - sawtooth[j][i] = value; - sawtooth[j][N_SAMPLES - i] = -value; + sawTooth[j][i] = value; + sawTooth[j][N_SAMPLES - i] = -value; } - n_partials_last = n_partials; - f_0 *= 1.0 / slice_inc; + nPartialsLast = nPartials; + f0 *= 1.0 / sliceInc; } } private int phase; - public Sawtooth() { + public Sawtooth(double sampleRate) { phase = 0; + init(sampleRate); } private int compute(int phase) { return phase * 2 - (1 << 24); } - private int lookup_1(int phase, int slice) { - int phase_int = (phase >> (24 - LG_N_SAMPLES)) & (N_SAMPLES - 1); - int lowbits = phase & ((1 << (24 - LG_N_SAMPLES)) - 1); - int y0 = sawtooth[slice][phase_int]; - int y1 = sawtooth[slice][(phase_int + 1) & (N_SAMPLES - 1)]; + private int lookup1(int phase, int slice) { + int phaseInt = (phase >> (24 - LG_N_SAMPLES)) & (N_SAMPLES - 1); + int lowBits = phase & ((1 << (24 - LG_N_SAMPLES)) - 1); + int y0 = sawTooth[slice][phaseInt]; + int y1 = sawTooth[slice][(phaseInt + 1) & (N_SAMPLES - 1)]; - return (int) (y0 + ((((long) (y1 - y0) * (long) lowbits)) >> (24 - LG_N_SAMPLES))); + return (int) (y0 + ((((long) (y1 - y0) * (long) lowBits)) >> (24 - LG_N_SAMPLES))); } - private int lookup_2(int phase, int slice, int slice_lowbits) { - int phase_int = (phase >> (24 - LG_N_SAMPLES)) & (N_SAMPLES - 1); - int lowbits = phase & ((1 << (24 - LG_N_SAMPLES)) - 1); - int y0 = sawtooth[slice][phase_int]; - int y1 = sawtooth[slice][(phase_int + 1) & (N_SAMPLES - 1)]; - int y4 = (int) (y0 + ((((long) (y1 - y0) * (long) lowbits)) >> (24 - LG_N_SAMPLES))); + private int lookup2(int phase, int slice, int sliceLowBits) { + int phaseInt = (phase >> (24 - LG_N_SAMPLES)) & (N_SAMPLES - 1); + int lowBits = phase & ((1 << (24 - LG_N_SAMPLES)) - 1); + int y0 = sawTooth[slice][phaseInt]; + int y1 = sawTooth[slice][(phaseInt + 1) & (N_SAMPLES - 1)]; + int y4 = (int) (y0 + ((((long) (y1 - y0) * (long) lowBits)) >> (24 - LG_N_SAMPLES))); - int y2 = sawtooth[slice + 1][phase_int]; - int y3 = sawtooth[slice + 1][(phase_int + 1) & (N_SAMPLES - 1)]; - int y5 = (int) (y2 + ((((long) (y3 - y2) * (long) lowbits)) >> (24 - LG_N_SAMPLES))); + int y2 = sawTooth[slice + 1][phaseInt]; + int y3 = sawTooth[slice + 1][(phaseInt + 1) & (N_SAMPLES - 1)]; + int y5 = (int) (y2 + ((((long) (y3 - y2) * (long) lowBits)) >> (24 - LG_N_SAMPLES))); - return (int) (y4 + ((((long) (y5 - y4) * (long) slice_lowbits)) >> (SLICE_SHIFT - SLICE_EXTRA))); + return (int) (y4 + ((((long) (y5 - y4) * (long) sliceLowBits)) >> (SLICE_SHIFT - SLICE_EXTRA))); } - public void process(final int[][] inbufs, final int[] control_in, final int[] control_last, int[][] outbufs) { - int logf = control_last[0]; - int[] obuf = outbufs[0]; - int actual_logf = logf + sawtooth_freq_off; - int f = Exp2.lookup(actual_logf); + public void process(int[][] inBufs, int[] controlIn, int[] controlLast, int[][] outBufs) { + int logf = controlLast[0]; + int[] oBuf = outBufs[0]; + int actualLogF = logf + sawToothFreqOff; + int f = Exp2.lookup(actualLogF); int p = phase; // choose a strategy based on the frequency - if (actual_logf < LOW_FREQ_LIMIT - (1 << (SLICE_SHIFT - SLICE_EXTRA))) { + if (actualLogF < LOW_FREQ_LIMIT - (1 << (SLICE_SHIFT - SLICE_EXTRA))) { for (int i = 0; i < Note.N; i++) { - obuf[i] = compute(p); + oBuf[i] = compute(p); p += f; p &= (1 << 24) - 1; } - } else if (actual_logf < LOW_FREQ_LIMIT) { + } else if (actualLogF < LOW_FREQ_LIMIT) { // interpolate between computed and lookup int slice = (LOW_FREQ_LIMIT + SLICE_BASE + (1 << SLICE_SHIFT) - 1) >> SLICE_SHIFT; - int slice_lowbits = actual_logf - LOW_FREQ_LIMIT + (1 << (SLICE_SHIFT - SLICE_EXTRA)); + int sliceLowBits = actualLogF - LOW_FREQ_LIMIT + (1 << (SLICE_SHIFT - SLICE_EXTRA)); for (int i = 0; i < Note.N; i++) { int yc = compute(p); - int yl = lookup_1(p, slice + 1); - obuf[i] = (int) (yc + ((((long) (yl - yc) * (long) slice_lowbits)) >> (SLICE_SHIFT - SLICE_EXTRA))); + int yl = lookup1(p, slice + 1); + oBuf[i] = (int) (yc + ((((long) (yl - yc) * (long) sliceLowBits)) >> (SLICE_SHIFT - SLICE_EXTRA))); p += f; p &= (1 << 24) - 1; } } else { - int slice = (actual_logf + SLICE_BASE + (1 << SLICE_SHIFT) - 1) >> SLICE_SHIFT; - final int slice_start = (1 << SLICE_SHIFT) - (1 << (SLICE_SHIFT - SLICE_EXTRA)); - int slice_lowbits = ((actual_logf + SLICE_BASE) & ((1 << SLICE_SHIFT) - 1)) - slice_start; + int slice = (actualLogF + SLICE_BASE + (1 << SLICE_SHIFT) - 1) >> SLICE_SHIFT; + final int sliceStart = (1 << SLICE_SHIFT) - (1 << (SLICE_SHIFT - SLICE_EXTRA)); + int sliceLowBits = ((actualLogF + SLICE_BASE) & ((1 << SLICE_SHIFT) - 1)) - sliceStart; // slice < 0 can't happen because LOW_FREQ_LIMIT kicks in first if (slice > N_SLICES - 2) { - if (slice > N_SLICES - 1 || slice_lowbits > 0) { + if (slice > N_SLICES - 1 || sliceLowBits > 0) { slice = N_SLICES - 1; - slice_lowbits = 0; + sliceLowBits = 0; } } - if (slice_lowbits <= 0) { + if (sliceLowBits <= 0) { for (int i = 0; i < Note.N; i++) { - obuf[i] = lookup_1(p, slice); + oBuf[i] = lookup1(p, slice); p += f; p &= (1 << 24) - 1; } } else { for (int i = 0; i < Note.N; i++) { - obuf[i] = lookup_2(p, slice, slice_lowbits); + oBuf[i] = lookup2(p, slice, sliceLowBits); p += f; p &= (1 << 24) - 1; } diff --git a/src/main/java/vavi/sound/dx7/Sin.java b/src/main/java/vavi/sound/dx7/Sin.java index e93ebc6..942304d 100644 --- a/src/main/java/vavi/sound/dx7/Sin.java +++ b/src/main/java/vavi/sound/dx7/Sin.java @@ -22,35 +22,35 @@ class Sin { private static final int SIN_N_SAMPLES = 1 << SIN_LG_N_SAMPLES; private static final int R = 1 << 29; - private static int[] sintab = new int[SIN_N_SAMPLES << 1]; + private static int[] sinTab = new int[SIN_N_SAMPLES << 1]; static { - double dphase = 2 * Math.PI / SIN_N_SAMPLES; - int c = (int) Math.floor(Math.cos(dphase) * (1 << 30) + 0.5); - int s = (int) Math.floor(Math.sin(dphase) * (1 << 30) + 0.5); + double dPhase = 2 * Math.PI / SIN_N_SAMPLES; + int c = (int) Math.floor(Math.cos(dPhase) * (1 << 30) + 0.5); + int s = (int) Math.floor(Math.sin(dPhase) * (1 << 30) + 0.5); int u = 1 << 30; int v = 0; for (int i = 0; i < SIN_N_SAMPLES / 2; i++) { - sintab[(i << 1) + 1] = (v + 32) >> 6; - sintab[((i + SIN_N_SAMPLES / 2) << 1) + 1] = -((v + 32) >> 6); + sinTab[(i << 1) + 1] = (v + 32) >> 6; + sinTab[((i + SIN_N_SAMPLES / 2) << 1) + 1] = -((v + 32) >> 6); int t = (int) (((long) u * (long) s + (long) v * (long) c + R) >> 30); u = (int) (((long) u * (long) c - (long) v * (long) s + R) >> 30); v = t; } for (int i = 0; i < SIN_N_SAMPLES - 1; i++) { - sintab[i << 1] = sintab[(i << 1) + 3] - sintab[(i << 1) + 1]; + sinTab[i << 1] = sinTab[(i << 1) + 3] - sinTab[(i << 1) + 1]; } - sintab[(SIN_N_SAMPLES << 1) - 2] = -sintab[(SIN_N_SAMPLES << 1) - 1]; + sinTab[(SIN_N_SAMPLES << 1) - 2] = -sinTab[(SIN_N_SAMPLES << 1) - 1]; } public static int lookup(int phase) { final int SHIFT = 24 - SIN_LG_N_SAMPLES; - int lowbits = phase & ((1 << SHIFT) - 1); - int phase_int = (phase >> (SHIFT - 1)) & ((SIN_N_SAMPLES - 1) << 1); - int dy = sintab[phase_int]; - int y0 = sintab[phase_int + 1]; + int lowBits = phase & ((1 << SHIFT) - 1); + int phaseInt = (phase >> (SHIFT - 1)) & ((SIN_N_SAMPLES - 1) << 1); + int dy = sinTab[phaseInt]; + int y0 = sinTab[phaseInt + 1]; - return (int) (y0 + (((long) dy * (long) lowbits) >> SHIFT)); + return (int) (y0 + (((long) dy * (long) lowBits) >> SHIFT)); } // coefficients are Chebyshev polynomial, computed by compute_cos_poly.py @@ -63,9 +63,11 @@ public static int lookup(int phase) { public static int compute(int phase) { int x = (phase & ((1 << 23) - 1)) - (1 << 22); int x2 = (int) (((long) x * (long) x) >> 16); - int y = (int) (((((((((((((long) C8_8 * (long) x2) >> 32) + C8_6) * x2) >> 32) + C8_4) * x2) >> 32) + C8_2) * - x2) >> 32) + - C8_0); + int y = (int) (((((((((((((long) C8_8 + * (long) x2) >> 32) + C8_6) + * x2) >> 32) + C8_4) + * x2) >> 32) + C8_2) + * x2) >> 32) + C8_0); y ^= -((phase >> 23) & 1); return y; } @@ -80,11 +82,12 @@ public static int compute(int phase) { public static int compute10(int phase) { int x = (phase & ((1 << 29) - 1)) - (1 << 28); int x2 = (int) (((long) x * (long) x) >> 26); - int y = (int) ((((((((((((((((long) C10_10 * (long) x2) >> 34) + C10_8) * x2) >> 34) + C10_6) * x2) >> 34) + C10_4) * - x2) >> 32) + - C10_2) * - x2) >> 30) + - C10_0); + int y = (int) ((((((((((((((((long) C10_10 + * (long) x2) >> 34) + C10_8) + * x2) >> 34) + C10_6) + * x2) >> 34) + C10_4) + * x2) >> 32) + C10_2) + * x2) >> 30) + C10_0); y ^= -((phase >> 29) & 1); return y; } diff --git a/src/main/java/vavi/sound/dx7/SynthUnit.java b/src/main/java/vavi/sound/dx7/SynthUnit.java index 608dff0..4649999 100644 --- a/src/main/java/vavi/sound/dx7/SynthUnit.java +++ b/src/main/java/vavi/sound/dx7/SynthUnit.java @@ -35,81 +35,77 @@ public class SynthUnit { }; private static class ActiveNote { - int midi_note; - boolean keydown; + int midiNote; + boolean keyDown; boolean sustained; boolean live; - Note dx7_note; + Note dx7Note; // int channel; } private BlockingDeque deque; private long timestump; - private static final int max_active_notes = 16; - private ActiveNote[] active_note_ = new ActiveNote[max_active_notes]; - private int current_note_; + private static final int MAX_ACTIVE_NOTES = 16; + private ActiveNote[] activeNote = new ActiveNote[MAX_ACTIVE_NOTES]; + private int currentNote; - private byte[] patch_data_ = new byte[156]; + private byte[] patchData = new byte[156]; - // The original DX7 had one single LFO. Later units had an LFO per note. - private Lfo lfo_ = new Lfo(); + private Context context; // in MIDI units (0x4000 is neutral) - private Note.Controllers controllers_; + private Note.Controllers controllers; - private ResoFilter filter_ = new ResoFilter(); - private int[] filter_control_ = new int[3]; - private boolean sustain_; + private ResoFilter filter; + private int[] filterControl = new int[3]; + private boolean sustain; // Extra buffering for when GetSamples wants a buffer not a multiple of N - private int[] extra_buf_ = new int[Note.N]; - private int extra_buf_size_; + private int[] extraBuf = new int[Note.N]; + private int extraBufSize; private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - public static void init(double sample_rate) { - Freqlut.init(sample_rate); - Lfo.init(sample_rate); - PitchEnv.init(sample_rate); - } - public void close() { executor.shutdown(); } - public SynthUnit(BlockingDeque deque) { - for (int note = 0; note < max_active_notes; ++note) { - active_note_[note] = new ActiveNote(); + public SynthUnit(float sampleRate, BlockingDeque deque) { + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + activeNote[note] = new ActiveNote(); } - for (int i = 0; i < patch_data_.length; i++) { + for (int i = 0; i < patchData.length; i++) { byte[] unpacked_patch_ = new byte[156]; Patch.unpackPatch(epiano2, unpacked_patch_); - System.arraycopy(unpacked_patch_, 0, patch_data_, 0, epiano2.length); + System.arraycopy(unpacked_patch_, 0, patchData, 0, epiano2.length); } - current_note_ = 0; - filter_control_[0] = 258847126; - filter_control_[1] = 0; - filter_control_[2] = 0; - controllers_ = new Note.Controllers(0x2000); - sustain_ = false; - extra_buf_size_ = 0; + currentNote = 0; + filterControl[0] = 258847126; + filterControl[1] = 0; + filterControl[2] = 0; + controllers = new Note.Controllers(0x2000); + sustain = false; + extraBufSize = 0; this.deque = deque; timestump = System.currentTimeMillis(); -Debug.println("period: " + (int) (1000.0 * Note.N / 44100.0)); + context = Context.getInstance(sampleRate); + filter = new ResoFilter(context); + + Debug.println("period: " + (int) (1000.0 * Note.N / 44100.0)); executor.scheduleAtFixedRate(this::process, 1000, (int) (1000.0 * Note.N / 44100.0), TimeUnit.MILLISECONDS); } private int allocateNote() { - int note = current_note_; - for (int i = 0; i < max_active_notes; i++) { - if (!active_note_[note].keydown) { - current_note_ = (note + 1) % max_active_notes; + int note = currentNote; + for (int i = 0; i < MAX_ACTIVE_NOTES; i++) { + if (!activeNote[note].keyDown) { + currentNote = (note + 1) % MAX_ACTIVE_NOTES; return note; } - note = (note + 1) % max_active_notes; + note = (note + 1) % MAX_ACTIVE_NOTES; } Debug.println("allocateNote: max"); return -1; @@ -117,24 +113,24 @@ private int allocateNote() { public void programChange(int p, byte[] patch, int ofs) { p = Math.min(p, 31); - System.arraycopy(patch, ofs, patch_data_, 0, patch_data_.length); - lfo_.reset(patch_data_, 137); + System.arraycopy(patch, ofs, patchData, 0, patchData.length); + context.lfo.reset(patchData, 137); byte[] name = new byte[10]; - System.arraycopy(patch_data_, 145, name, 0, 10); + System.arraycopy(patchData, 145, name, 0, 10); Debug.println("Loaded patch " + p + ": " + new String(name, 0, 10)); } public void noteOff(int noteNumber) { //Debug.println("note off: " + noteNumber); - for (int note = 0; note < max_active_notes; ++note) { - if (active_note_[note].midi_note == noteNumber && active_note_[note].keydown) { - if (sustain_) { - active_note_[note].sustained = true; + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + if (activeNote[note].midiNote == noteNumber && activeNote[note].keyDown) { + if (sustain) { + activeNote[note].sustained = true; } else { - active_note_[note].dx7_note.keyup(); + activeNote[note].dx7Note.keyUp(); } - active_note_[note].keydown = false; + activeNote[note].keyDown = false; } } } @@ -145,37 +141,38 @@ public void noteOn(int noteNumber, int velocity) { return; } //Debug.println("note on: " + noteNumber + ", " + velocity); - int note_ix = allocateNote(); - if (note_ix >= 0) { - lfo_.keydown(); // TODO: should only do this if # keys down was 0 - active_note_[note_ix].midi_note = noteNumber; - active_note_[note_ix].keydown = true; - active_note_[note_ix].sustained = sustain_; - active_note_[note_ix].live = true; - active_note_[note_ix].dx7_note = new Note(patch_data_, noteNumber, velocity); + int noteIx = allocateNote(); + if (noteIx >= 0) { + context.lfo.keyDown(); // TODO: should only do this if # keys down was 0 + activeNote[noteIx].midiNote = noteNumber; + activeNote[noteIx].keyDown = true; + activeNote[noteIx].sustained = sustain; + activeNote[noteIx].live = true; + activeNote[noteIx].dx7Note = new Note(context, patchData, noteNumber, velocity); } } public void controlChange(int controller, int value) { // TODO: move more logic into setController if (controller == 1) { - filter_control_[0] = 142365917 + value * 917175; + filterControl[0] = 142365917 + value * 917175; } else if (controller == 2) { - filter_control_[1] = value * 528416; + filterControl[1] = value * 528416; } else if (controller == 3) { - filter_control_[2] = value * 528416; + filterControl[2] = value * 528416; } else if (controller == 64) { - sustain_ = value != 0; - if (!sustain_) { - for (int note = 0; note < max_active_notes; note++) { - if (active_note_[note].sustained && !active_note_[note].keydown) { - active_note_[note].dx7_note.keyup(); - active_note_[note].sustained = false; + // damper pedal hold 1 + sustain = value != 0; + if (!sustain) { + for (int note = 0; note < MAX_ACTIVE_NOTES; note++) { + if (activeNote[note].sustained && !activeNote[note].keyDown) { + activeNote[note].dx7Note.keyUp(); + activeNote[note].sustained = false; } } } } - controllers_.values_[controller] = value; + controllers.values[controller] = value; //Debug.println("control change: " + controller + ", " + value); } @@ -187,94 +184,90 @@ public void pitchBend(int data1, int data2) { public void sysex(byte[] b) { } - public void getSamples(int n_samples, int[] buffer) { + public void getSamples(int nSamples, int[] buffer) { int i; - for (i = 0; i < n_samples && i < extra_buf_size_; i++) { - buffer[i] = extra_buf_[i]; + for (i = 0; i < nSamples && i < extraBufSize; i++) { + buffer[i] = extraBuf[i]; } - if (extra_buf_size_ > n_samples) { - for (int j = 0; j < extra_buf_size_ - n_samples; j++) { - extra_buf_[j] = extra_buf_[j + n_samples]; - } - extra_buf_size_ -= n_samples; + if (extraBufSize > nSamples) { + System.arraycopy(extraBuf, nSamples, extraBuf, 0, extraBufSize - nSamples); + extraBufSize -= nSamples; return; } - for (; i < n_samples; i += Note.N) { - int[] audiobuf = new int[Note.N]; - int[] audiobuf2 = new int[Note.N]; - int lfovalue = lfo_.getsample(); - int lfodelay = lfo_.getdelay(); - for (int note = 0; note < max_active_notes; ++note) { - if (active_note_[note].live && active_note_[note].dx7_note != null) { - active_note_[note].dx7_note.compute(audiobuf, lfovalue, lfodelay, controllers_); -// active_note_[note].dx7_note.compute(audiobuf, 0, 0, controllers_); + for (; i < nSamples; i += Note.N) { + int[] audioBuf = new int[Note.N]; + int[] audioBuf2 = new int[Note.N]; + int lfoValue = context.lfo.getSample(); + int lfoDelay = context.lfo.getDelay(); + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + if (activeNote[note].live && activeNote[note].dx7Note != null) { + activeNote[note].dx7Note.compute(audioBuf, lfoValue, lfoDelay, controllers); +// activeNote[note].dx7Note.compute(audioBuf, 0, 0, controllers); } } - final int[][] bufs = { audiobuf }; - int[][] bufs2 = { audiobuf2 }; - filter_.process(bufs, filter_control_, filter_control_, bufs2); - int jmax = n_samples - i; + int[][] bufs = { audioBuf }; + int[][] bufs2 = { audioBuf2 }; + filter.process(bufs, filterControl, filterControl, bufs2); + int jmax = nSamples - i; for (int j = 0; j < Note.N; ++j) { - int val = audiobuf2[j] >> 4; -// int val = audiobuf[j] >> 4; + int val = audioBuf2[j] >> 4; +// int val = audioBuf[j] >> 4; int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; // TODO: maybe some dithering? if (j < jmax) { buffer[i + j] = clip_val; } else { - extra_buf_[j - jmax] = clip_val; + extraBuf[j - jmax] = clip_val; } } } - extra_buf_size_ = i - n_samples; -//Debug.println("extra: " + (i - n_samples)); + extraBufSize = i - nSamples; +//Debug.println("extra: " + (i - nSamples)); } public void process() { int nsec = (int) (System.currentTimeMillis() - timestump); timestump = System.currentTimeMillis(); - int n_samples = (int) (44100 * nsec / 1000.0); + int nSamples = (int) (44100 * nsec / 1000.0); int i; - for (i = 0; i < n_samples && i < extra_buf_size_; i++) { - deque.add(extra_buf_[i]); + for (i = 0; i < nSamples && i < extraBufSize; i++) { + deque.add(extraBuf[i]); } - if (extra_buf_size_ > n_samples) { - for (int j = 0; j < extra_buf_size_ - n_samples; j++) { - extra_buf_[j] = extra_buf_[j + n_samples]; - } - extra_buf_size_ -= n_samples; + if (extraBufSize > nSamples) { + System.arraycopy(extraBuf, nSamples, extraBuf, 0, extraBufSize - nSamples); + extraBufSize -= nSamples; return; } - for (; i < n_samples; i += Note.N) { - int[] audiobuf = new int[Note.N]; -// int[] audiobuf2 = new int[Note.N]; -// int lfovalue = lfo_.getsample(); -// int lfodelay = lfo_.getdelay(); - for (int note = 0; note < max_active_notes; ++note) { - if (active_note_[note].live && active_note_[note].dx7_note != null) { -// active_note_[note].dx7_note.compute(audiobuf, lfovalue, lfodelay, controllers_); - active_note_[note].dx7_note.compute(audiobuf, 0, 0, controllers_); + for (; i < nSamples; i += Note.N) { + int[] audioBuf = new int[Note.N]; +// int[] audioBuf2 = new int[Note.N]; +// int lfoValue = lfo.getSample(); +// int lfoDelay = lfo.getSelay(); + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + if (activeNote[note].live && activeNote[note].dx7Note != null) { +// activeNnote[note].dx7Note.compute(audioBuf, lfoValue, lfoDelay, controllers); + activeNote[note].dx7Note.compute(audioBuf, 0, 0, controllers); } } -// final int[][] bufs = { audiobuf }; +// final int[][] bufs = { audioBuf }; // int[][] bufs2 = { audiobuf2 }; -// filter_.process(bufs, filter_control_, filter_control_, bufs2); - int jmax = n_samples - i; +// filter.process(bufs, filterControl, filterControl, bufs2); + int jmax = nSamples - i; for (int j = 0; j < Note.N; ++j) { // int val = audiobuf2[j] >> 4; - int val = audiobuf[j] >> 4; - int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; + int val = audioBuf[j] >> 4; + int clipVal = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; // TODO: maybe some dithering? if (j < jmax) { - deque.add(clip_val); + deque.add(clipVal); } else { - extra_buf_[j - jmax] = clip_val; + extraBuf[j - jmax] = clipVal; } } } - extra_buf_size_ = i - n_samples; + extraBufSize = i - nSamples; //Debug.println("deque: " + deque.size()); } } diff --git a/src/main/java/vavi/sound/midi/dx7/Dx7.java b/src/main/java/vavi/sound/midi/dx7/Dx7.java index a0c1777..5e11682 100644 --- a/src/main/java/vavi/sound/midi/dx7/Dx7.java +++ b/src/main/java/vavi/sound/midi/dx7/Dx7.java @@ -9,10 +9,8 @@ import java.util.ArrayList; import java.util.List; -import vavi.sound.dx7.Freqlut; -import vavi.sound.dx7.Lfo; +import vavi.sound.dx7.Context; import vavi.sound.dx7.Note; -import vavi.sound.dx7.PitchEnv; import vavi.sound.dx7.ResoFilter; import vavi.util.Debug; @@ -27,19 +25,16 @@ class Dx7 { static final int BUFFER_SIZE = Note.N; private static class ActiveNote { - boolean keydown; + boolean keyDown; // TODO should be use the value in SoftVoice? boolean sustained; Note note; } - // The original DX7 had one single LFO. Later units had an LFO per note. - private Lfo lfo = new Lfo(); - // in MIDI units (0x4000 is neutral) private Note.Controllers controllers; - private ResoFilter filter = new ResoFilter(); + private ResoFilter filter; private int[] filterControl = new int[3]; @@ -54,15 +49,16 @@ private static class ActiveNote { controllers = new Note.Controllers(0x2000); } - private static float sampleRate = -1; + private Context context = null; - static void setSampleRate(float sampleRate) { - if (Dx7.sampleRate != sampleRate) { + void setSampleRate(float sampleRate) { + if (this.context == null) { + this.context = Context.getInstance(sampleRate); + filter = new ResoFilter(context); + } + if (this.context.sampleRate != sampleRate) { Debug.println("sampleRate: " + sampleRate); - Freqlut.init(sampleRate); - Lfo.init(sampleRate); - PitchEnv.init(sampleRate); - Dx7.sampleRate = sampleRate; + this.context.setSampleRate(sampleRate); } } @@ -74,26 +70,28 @@ static void setSampleRate(float sampleRate) { private int[] audioBuf2 = new int[BUFFER_SIZE]; void write(int offset, int len, int i, float[] buffer, float[] extraBuf) { - int lfoValue = lfo.getsample(); - int lfoDelay = lfo.getdelay(); + int lfoValue = context.lfo.getSample(); + int lfoDelay = context.lfo.getDelay(); activeNote.note.compute(audioBuf, lfoValue, lfoDelay, controllers); -// activeNote.dx7_note.compute(audiobuf, 0, 0, controllers_); - final int[][] bufs = { audioBuf }; +// activeNote.note.compute(audioBuf, 0, 0, controllers); + int[][] bufs = { audioBuf }; int[][] bufs2 = { audioBuf2 }; filter.process(bufs, filterControl, filterControl, bufs2); int jmax = len - i; for (int j = 0; j < Note.N; j++) { int val = audioBuf2[j] >> 4; -// int val = audiobuf[j] >> 4; - int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; +// int val = audioBuf[j] >> 4; + int clipVal = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; // TODO: maybe some dithering? float f; - int x = clip_val; - f = ((float) x) / (float) 32768; - if (f > 1) + int x = clipVal; + f = ((float) x) / (float) 0x8000; + if (f > 1) { f = 1; - if (f < -1) + } + if (f < -1) { f = -1; + } if (j < jmax) { buffer[offset + i + j] = f; } else { @@ -103,23 +101,23 @@ void write(int offset, int len, int i, float[] buffer, float[] extraBuf) { } void noteOn(byte[] patch, int noteNumber, int velocity) { - lfo.keydown(); + context.lfo.keyDown(); activeNote = new Dx7.ActiveNote(); - activeNote.keydown = true; + activeNote.keyDown = true; activeNote.sustained = sustain; - activeNote.note = new Note(patch, noteNumber, velocity); + activeNote.note = new Note(context, patch, noteNumber, velocity); activeNotes.add(activeNote); } void noteOff() { - if (activeNote.keydown) { + if (activeNote.keyDown) { if (sustain) { activeNote.sustained = true; } else { - activeNote.note.keyup(); + activeNote.note.keyUp(); activeNotes.remove(activeNote); } - activeNote.keydown = false; + activeNote.keyDown = false; } } @@ -127,7 +125,7 @@ public void programChange(int p, byte[] patch, int ofs) { // TODO location byte[] b = Dx7Soundbank.getDirectBuffer(p); System.arraycopy(patch, ofs, b, 0, b.length); - lfo.reset(b, 137); + context.lfo.reset(b, 137); Debug.println("Loaded patch " + p + ": " + new String(b, 145, 10)); } @@ -154,8 +152,8 @@ public void controlChange(int controller, int value) { sustain = value != 0; if (!sustain) { for (ActiveNote activeNote : activeNotes) { - if (activeNote.sustained && !activeNote.keydown) { - activeNote.note.keyup(); + if (activeNote.sustained && !activeNote.keyDown) { + activeNote.note.keyUp(); activeNote.sustained = false; activeNotes.remove(activeNote); } @@ -164,7 +162,6 @@ public void controlChange(int controller, int value) { Debug.println("control change: " + controller + ", " + value); break; } - controllers.values_[controller] = value; + controllers.values[controller] = value; } } -/* */ diff --git a/src/main/java/vavi/sound/midi/dx7/Dx7MidiDeviceProvider.java b/src/main/java/vavi/sound/midi/dx7/Dx7MidiDeviceProvider.java index fc1d516..aabe11d 100644 --- a/src/main/java/vavi/sound/midi/dx7/Dx7MidiDeviceProvider.java +++ b/src/main/java/vavi/sound/midi/dx7/Dx7MidiDeviceProvider.java @@ -47,5 +47,3 @@ public MidiDevice getDevice(MidiDevice.Info info) } } } - -/* */ diff --git a/src/main/java/vavi/sound/midi/dx7/Dx7Oscillator.java b/src/main/java/vavi/sound/midi/dx7/Dx7Oscillator.java index 31417a0..6f0f553 100644 --- a/src/main/java/vavi/sound/midi/dx7/Dx7Oscillator.java +++ b/src/main/java/vavi/sound/midi/dx7/Dx7Oscillator.java @@ -37,13 +37,10 @@ public class Dx7Oscillator extends ModelAbstractOscillator { soundbank = new Dx7Soundbank(); } - /** TODO not works as class field */ - private Dx7 dx7; + /** */ + private Dx7 dx7 = new Dx7(); public Dx7 getDx7() { - if (dx7 == null) { - dx7 = new Dx7(); - } return dx7; } @@ -54,15 +51,12 @@ public Dx7 getDx7() { @Override public void init() { //Debug.println("init"); - if (dx7 == null) { - dx7 = new Dx7(); - } super.init(); } @Override public void setSampleRate(float sampleRate) { - Dx7.setSampleRate(sampleRate); + dx7.setSampleRate(sampleRate); super.setSampleRate(sampleRate); } @@ -124,9 +118,7 @@ public int read(float[][] buffers, int offset, int len) throws IOException { buffer[offset + i] = extraBuf[i]; } if (extraBufSize > len) { - for (int j = 0; j < extraBufSize - len; j++) { - extraBuf[j] = extraBuf[j + len]; - } + System.arraycopy(extraBuf, len, extraBuf, 0, extraBufSize - len); extraBufSize -= len; return len; } diff --git a/src/main/java/vavi/sound/midi/dx7/Dx7Soundbank.java b/src/main/java/vavi/sound/midi/dx7/Dx7Soundbank.java index e4f252a..c92976d 100644 --- a/src/main/java/vavi/sound/midi/dx7/Dx7Soundbank.java +++ b/src/main/java/vavi/sound/midi/dx7/Dx7Soundbank.java @@ -93,6 +93,8 @@ public Object getData() { } instruments.put("p." + 0 + "." + 0, new Dx7Instrument(0, 0, true, drums)); + } catch (NullPointerException e) { + throw new IllegalStateException("unpacked.bin might not be found in classpath", e); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -129,7 +131,7 @@ public SoundbankResource[] getResources() { @Override public Instrument[] getInstruments() { - return instruments.values().stream().toArray(Instrument[]::new); + return instruments.values().toArray(new Instrument[0]); } private Map emergencies = new HashMap<>(); @@ -159,5 +161,3 @@ public Instrument getInstrument(Patch patch) { return ins; } } - -/* */ diff --git a/src/main/java/vavi/sound/midi/dx7/Dx7Synthesizer.java b/src/main/java/vavi/sound/midi/dx7/Dx7Synthesizer.java index 4448023..e7cfdd9 100644 --- a/src/main/java/vavi/sound/midi/dx7/Dx7Synthesizer.java +++ b/src/main/java/vavi/sound/midi/dx7/Dx7Synthesizer.java @@ -6,10 +6,14 @@ package vavi.sound.midi.dx7; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Properties; +import java.util.logging.Level; import javax.sound.midi.Instrument; +import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiChannel; import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiMessage; @@ -34,22 +38,39 @@ * creating a synthesizer is too much for us. we need to reproduce * timing management, multiple voice management, mix down polyphony etc. * Gervill provides well considered sound system. what we need to do - * is just to create a oscillator. see {@link Dx7Oscillator}. + * is just to create an oscillator. see {@link Dx7Oscillator}. * * @author Naohide Sano (umjammer) * @version 0.00 2020/10/31 umjammer initial version
*/ public class Dx7Synthesizer implements Synthesizer { - private static final String version = "0.0.2"; + static { + try { + try (InputStream is = Dx7Synthesizer.class.getResourceAsStream("/META-INF/maven/vavi/vavi-sound-dx7/pom.properties")) { + if (is != null) { + Properties props = new Properties(); + props.load(is); + version = props.getProperty("version", "undefined in pom.properties"); + } else { + version = System.getProperty("vavi.test.version", "undefined"); + } + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private static final String version; /** the device information */ protected static final MidiDevice.Info info = new MidiDevice.Info("DX7 MIDI Synthesizer", - "Vavisoft", + "vavi", "Software synthesizer for DX7", "Version " + version) {}; + /** required gervill */ private Synthesizer synthesizer; private Dx7Oscillator dx7Oscillator; @@ -75,7 +96,11 @@ public void close() { @Override public boolean isOpen() { - return synthesizer.isOpen(); + if (synthesizer != null) { + return synthesizer.isOpen(); + } else { + return false; + } } @Override @@ -212,37 +237,52 @@ public Dx7Receiver(Receiver receiver) { @Override public void send(MidiMessage message, long timeStamp) { try { - if (message instanceof ShortMessage) { - ShortMessage shortMessage = (ShortMessage) message; + if (message instanceof ShortMessage shortMessage) { int command = shortMessage.getCommand(); int data1 = shortMessage.getData1(); int data2 = shortMessage.getData2(); switch (command) { - case ShortMessage.CONTROL_CHANGE: - dx7Oscillator.getDx7().controlChange(data1, data2); - break; + case ShortMessage.CONTROL_CHANGE -> dx7Oscillator.getDx7().controlChange(data1, data2); } - } else if (message instanceof SysexMessage) { - SysexMessage sysexMessage = (SysexMessage) message; + } else if (message instanceof SysexMessage sysexMessage) { byte[] data = sysexMessage.getData(); -//Debug.print("sysex:\n" + StringUtil.getDump(data)); //Debug.printf(Level.FINE, "sysex: %02x %02x %02x", data[1], data[2], data[3]); - if (data[0] == 0x43) { - if (data[1] == 0x00 && data[2] == 0x09 && data[3] == 0x20 && data[4] == 0x00) { - if (data.length > 4096) { + +Debug.printf(Level.FINE, "sysex: %02X\n%s", sysexMessage.getStatus(), StringUtil.getDump(data)); + switch (data[0]) { + case 0x43 -> { + switch (data[1]) { + case 0x00 -> { + switch (data[2]) { + case 0x09: // + if (data[3] == 0x20 && data[4] == 0x00) { // Debug.println("sysex: bank change?"); - } - } else if (data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x01 && data[4] == 0x1b) { - dx7Oscillator.getDx7().programChange(0, data, 5); - } else { -// Dx7Oscillator.getDx7().sysex(data); + } + break; + case 0x00: // + if (data[3] == 0x01 && data[4] == 0x1b) { + dx7Oscillator.getDx7().programChange(0, data, 5); + } + break; + } // + } + } // Yamaha } - } else { -Debug.println("sysex\n" + StringUtil.getDump(data)); + default -> {} } + + receiver.send(sysexMessage, timeStamp); + } else if (message instanceof MetaMessage metaMessage) { +Debug.printf("meta: %02x", metaMessage.getType()); + switch (metaMessage.getType()) { + case 0x2f -> {} + } + receiver.send(message, timeStamp); + } else { + assert false; } } catch (Throwable t) { - t.printStackTrace(); + Debug.printStackTrace(t); } this.receiver.send(message, timeStamp); } @@ -253,5 +293,3 @@ public void close() { } } } - -/* */ diff --git a/src/test/java/vavi/sound/dx7/Dx7SynthesizerTest.java b/src/test/java/vavi/sound/dx7/Dx7SynthesizerTest.java index cb03855..713d850 100644 --- a/src/test/java/vavi/sound/dx7/Dx7SynthesizerTest.java +++ b/src/test/java/vavi/sound/dx7/Dx7SynthesizerTest.java @@ -6,14 +6,17 @@ package vavi.sound.dx7; +import java.io.BufferedInputStream; import java.io.DataInputStream; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Random; import java.util.concurrent.CountDownLatch; import javax.sound.midi.Instrument; import javax.sound.midi.MetaEventListener; -import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiChannel; import javax.sound.midi.MidiSystem; import javax.sound.midi.Receiver; @@ -23,12 +26,11 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; -import javax.sound.sampled.FloatControl; import javax.sound.sampled.SourceDataLine; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; import com.sun.media.sound.ModelAbstractOscillator; import com.sun.media.sound.ModelPatch; @@ -38,6 +40,11 @@ import vavi.sound.midi.dx7.Dx7Synthesizer; import vavi.util.Debug; import vavi.util.StringUtil; +import vavi.util.properties.annotation.Property; +import vavi.util.properties.annotation.PropsEntity; + +import static vavi.sound.SoundUtil.volume; +import static vavi.sound.midi.MidiUtil.volume; /** @@ -47,6 +54,7 @@ * @version 0.00 2020/10/30 umjammer initial version
*/ @SuppressWarnings("restriction") +@PropsEntity(url = "file:local.properties") public class Dx7SynthesizerTest { static { @@ -54,9 +62,24 @@ public class Dx7SynthesizerTest { System.setProperty("javax.sound.midi.Sequencer", "#Real Time Sequencer"); } + static boolean localPropertiesExists() { + return Files.exists(Paths.get("local.properties")); + } + + static float volume = Float.parseFloat(System.getProperty("vavi.test.volume.midi", "0.2")); + + @BeforeEach + void setup() throws IOException { + if (localPropertiesExists()) { + PropsEntity.Util.bind(this); + } + } + + @Property(name = "test.midi") + String midi = "src/test/resources/test.mid"; + @Test -// @Disabled - @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*") + @DisplayName("directly") void test() throws Exception { Synthesizer synthesizer = new Dx7Synthesizer(); synthesizer.open(); @@ -65,31 +88,34 @@ void test() throws Exception { Sequencer sequencer = MidiSystem.getSequencer(false); sequencer.open(); Debug.println("sequencer: " + sequencer.getClass().getName()); - sequencer.getTransmitter().setReceiver(synthesizer.getReceiver()); + Receiver receiver = synthesizer.getReceiver(); + sequencer.getTransmitter().setReceiver(receiver); -// String filename = "../../src/sano-n/vavi-apps-dx7/tmp/midi/minute_waltz.mid"; -// String filename = "1/TongPoo.mid"; -// String filename = "1/title-screen.mid"; -// String filename = "1/overworld.mid"; - String filename = "1/m0057_01.mid"; -// String filename = "1/ac4br_gm.MID"; - File file = new File(System.getProperty("user.home"), "/Music/midi/" + filename); - Sequence seq = MidiSystem.getSequence(file); + Path file = Paths.get(midi); + + Sequence seq = MidiSystem.getSequence(new BufferedInputStream(Files.newInputStream(file))); CountDownLatch countDownLatch = new CountDownLatch(1); - MetaEventListener mel = new MetaEventListener() { - public void meta(MetaMessage meta) { + MetaEventListener mel = meta -> { //System.err.println("META: " + meta.getType()); - if (meta.getType() == 47) { - countDownLatch.countDown(); - } + if (meta.getType() == 47) { + countDownLatch.countDown(); } }; sequencer.setSequence(seq); sequencer.addMetaEventListener(mel); System.err.println("START"); sequencer.start(); + + volume(receiver, volume); // gervill volume works! + +if (!System.getProperty("vavi.test", "").equals("ide")) { + Thread.sleep(10 * 1000); + sequencer.stop(); + Debug.println("STOP"); +} else { countDownLatch.await(); +} System.err.println("END"); sequencer.removeMetaEventListener(mel); sequencer.close(); @@ -98,12 +124,13 @@ public void meta(MetaMessage meta) { } @Test - @Disabled void test2() throws Exception { Synthesizer synthesizer = new Dx7Synthesizer(); synthesizer.open(); Debug.println("synthesizer: " + synthesizer); + volume(synthesizer.getReceiver(), volume); // gervill volume works! + MidiChannel channel = synthesizer.getChannels()[0]; for (int i = 0; i < 32; i++) { channel.programChange(1 + i); @@ -118,14 +145,11 @@ void test2() throws Exception { } @Test - @Disabled void test4() throws Exception { ModelAbstractOscillator oscs; try { - oscs = Dx7Oscillator.class.newInstance(); - } catch (InstantiationException e) { - throw new IllegalArgumentException(e); - } catch (IllegalAccessException e) { + oscs = Dx7Oscillator.class.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { throw new IllegalArgumentException(e); } oscs.setSampleRate(44100); @@ -133,8 +157,7 @@ void test4() throws Exception { } @Test - @Disabled - @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*") + @DisplayName("spi") void test3() throws Exception { Synthesizer synthesizer = MidiSystem.getSynthesizer(); Debug.println("synthesizer: " + synthesizer.getClass().getName()); @@ -142,13 +165,9 @@ void test3() throws Exception { synthesizer.unloadAllInstruments(synthesizer.getDefaultSoundbank()); synthesizer.loadAllInstruments(new Dx7Oscillator()); - String filename = "../../src/sano-n/vavi-apps-dx7/tmp/midi/minute_waltz.mid"; -// String filename = "1/title-screen.mid"; -// String filename = "1/overworld.mid"; -// String filename = "1/m0057_01.mid"; -// String filename = "1/ac4br_gm.MID"; - File file = new File(System.getProperty("user.home"), "/Music/midi/" + filename); - Sequence seq = MidiSystem.getSequence(file); + Path file = Paths.get(midi); + + Sequence seq = MidiSystem.getSequence(new BufferedInputStream(Files.newInputStream(file))); Sequencer sequencer = MidiSystem.getSequencer(false); Debug.println("sequencer: " + sequencer.getClass().getName()); @@ -157,12 +176,10 @@ void test3() throws Exception { sequencer.getTransmitter().setReceiver(receiver); CountDownLatch countDownLatch = new CountDownLatch(1); - MetaEventListener mel = new MetaEventListener() { - public void meta(MetaMessage meta) { + MetaEventListener mel = meta -> { System.err.println("META: " + meta.getType()); - if (meta.getType() == 47) { - countDownLatch.countDown(); - } + if (meta.getType() == 47) { + countDownLatch.countDown(); } }; sequencer.setSequence(seq); @@ -170,7 +187,15 @@ public void meta(MetaMessage meta) { System.err.println("START"); sequencer.start(); + volume(receiver, volume); // gervill volume works! + +if (!System.getProperty("vavi.test", "").equals("ide")) { + Thread.sleep(10 * 1000); + sequencer.stop(); + Debug.println("STOP"); +} else { countDownLatch.await(); +} System.err.println("END"); sequencer.removeMetaEventListener(mel); @@ -179,32 +204,24 @@ public void meta(MetaMessage meta) { synthesizer.close(); } - /** - * - * @param args - */ + /** */ public static void main(String[] args) throws Exception { t3(args); } + /** */ public static void t3(String[] args) throws Exception { - final int n_samples = 20 * 1024; - final double sample_rate = 44100.0; - Freqlut.init(sample_rate); - Lfo.init(sample_rate); - PitchEnv.init(sample_rate); + final int nSamples = 20 * 1024; + final float sampleRate = 44100.0f; Instrument instrument = new Dx7Soundbank().getInstrument(new ModelPatch(0, 0, true)); Debug.println(instrument.getName()); - AudioFormat audioFormat = new AudioFormat((float) sample_rate, 16, 1, true, false); + AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(lineInfo); - line.addLineListener(event -> { Debug.println(event.getType()); }); + line.addLineListener(event -> Debug.println(event.getType())); line.open(); -FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); -double gain = .2d; // number between 0 and 1 (loudest) -float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); -gainControl.setValue(dB); + volume(line, volume); line.start(); for (int m = 35; m < 82; m++) { @@ -212,35 +229,34 @@ public static void t3(String[] args) throws Exception { byte[] x = ((byte[][]) instrument.getData())[m]; Debug.println("drum: " + m); - Lfo.init(audioFormat.getSampleRate()); + Context context = Context.getInstance(sampleRate); - Lfo lfo = new Lfo(); - ResoFilter filter = new ResoFilter(); + ResoFilter filter = new ResoFilter(context); int[] filterControl = new int[3]; filterControl[0] = 258847126; filterControl[1] = 0; filterControl[2] = 0; - lfo.keydown(); - Note note = new Note(x, 63, 100); + context.lfo.keyDown(); + Note note = new Note(context, x, 63, 100); Note.Controllers controllers = new Note.Controllers(0x2000); int[] buf = new int[Note.N]; int[] buf2 = new int[Note.N]; - for (int i = 0; i < n_samples; i += Note.N) { - if (i >= n_samples * (7. / 8.)) { - note.keyup(); + for (int i = 0; i < nSamples; i += Note.N) { + if (i >= nSamples * (7. / 8.)) { + note.keyUp(); } - int lfoValue = lfo.getsample(); - int lfoDelay = lfo.getdelay(); + int lfoValue = context.lfo.getSample(); + int lfoDelay = context.lfo.getDelay(); note.compute(buf, lfoValue, lfoDelay, controllers); - final int[][] bufs = { buf }; + int[][] bufs = { buf }; int[][] bufs2 = { buf2 }; filter.process(bufs, filterControl, filterControl, bufs2); for (int j = 0; j < Note.N; j++) { buf2[j] >>= 2; } - write_data(line, buf2, Note.N); + writeData(line, buf2, Note.N); } } line.drain(); @@ -248,22 +264,16 @@ public static void t3(String[] args) throws Exception { } public static void t2(String[] args) throws Exception { - final int n_samples = 20 * 1024; - final double sample_rate = 44100.0; - Freqlut.init(sample_rate); - Lfo.init(sample_rate); - PitchEnv.init(sample_rate); + final int nSamples = 20 * 1024; + final float sampleRate = 44100.0f; Instrument[] instruments = new Dx7Soundbank().getInstruments(); - AudioFormat audioFormat = new AudioFormat((float) sample_rate, 16, 1, true, false); + AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(lineInfo); - line.addLineListener(event -> { Debug.println(event.getType()); }); + line.addLineListener(event -> Debug.println(event.getType())); line.open(); -FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); -double gain = .2d; // number between 0 and 1 (loudest) -float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); -gainControl.setValue(dB); + volume(line, volume); line.start(); Random r = new Random(); @@ -272,35 +282,34 @@ public static void t2(String[] args) throws Exception { byte[] x = (byte[]) instruments[m].getData(); Debug.println(m + ": " + instruments[m].getName()); - Lfo.init(audioFormat.getSampleRate()); + Context context = Context.getInstance(audioFormat.getSampleRate()); - Lfo lfo = new Lfo(); - ResoFilter filter = new ResoFilter(); + ResoFilter filter = new ResoFilter(context); int[] filterControl = new int[3]; filterControl[0] = 258847126; filterControl[1] = 0; filterControl[2] = 0; - lfo.keydown(); - Note note = new Note(x, 50 + (r.nextInt(12)), 100); + context.lfo.keyDown(); + Note note = new Note(context, x, 50 + (r.nextInt(12)), 100); Note.Controllers controllers = new Note.Controllers(0x2000); int[] buf = new int[Note.N]; int[] buf2 = new int[Note.N]; - for (int i = 0; i < n_samples; i += Note.N) { - if (i >= n_samples * (7. / 8.)) { - note.keyup(); + for (int i = 0; i < nSamples; i += Note.N) { + if (i >= nSamples * (7. / 8.)) { + note.keyUp(); } - int lfoValue = lfo.getsample(); - int lfoDelay = lfo.getdelay(); + int lfoValue = context.lfo.getSample(); + int lfoDelay = context.lfo.getDelay(); note.compute(buf, lfoValue, lfoDelay, controllers); - final int[][] bufs = { buf }; + int[][] bufs = { buf }; int[][] bufs2 = { buf2 }; filter.process(bufs, filterControl, filterControl, bufs2); for (int j = 0; j < Note.N; j++) { buf2[j] >>= 2; } - write_data(line, buf2, Note.N); + writeData(line, buf2, Note.N); } } line.drain(); @@ -308,11 +317,8 @@ public static void t2(String[] args) throws Exception { } public static void t1(String[] args) throws Exception { - final int n_samples = 10 * 1024; - final double sample_rate = 44100.0; - Freqlut.init(sample_rate); - Lfo.init(sample_rate); - PitchEnv.init(sample_rate); + final int nSamples = 10 * 1024; + final float sampleRate = 44100.0f; int k = 1004; @@ -324,15 +330,12 @@ public static void t1(String[] args) throws Exception { dis.readFully(b[i]); } - AudioFormat audioFormat = new AudioFormat((float) sample_rate, 16, 1, true, false); + AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(lineInfo); - line.addLineListener(event -> { Debug.println(event.getType()); }); + line.addLineListener(event -> Debug.println(event.getType())); line.open(); -FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); -double gain = .2d; // number between 0 and 1 (loudest) -float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); -gainControl.setValue(dB); + volume(line, volume); line.start(); Random r = new Random(); @@ -345,37 +348,36 @@ public static void t1(String[] args) throws Exception { Debug.println("patch: " + k / 32 + ", " + k % 32); Debug.println(x.length + "\n" + StringUtil.getDump(x)); - Lfo.init(audioFormat.getSampleRate()); + Context context = Context.getInstance(audioFormat.getSampleRate()); - Lfo lfo = new Lfo(); - ResoFilter filter = new ResoFilter(); + ResoFilter filter = new ResoFilter(context); int[] filterControl = new int[3]; filterControl[0] = 258847126; filterControl[1] = 0; filterControl[2] = 0; - lfo.keydown(); - Note note = new Note(x, 50 + (r.nextInt(12)), 100); + context.lfo.keyDown(); + Note note = new Note(context, x, 50 + (r.nextInt(12)), 100); Note.Controllers controllers = new Note.Controllers(0x2000); int[] buf = new int[Note.N]; int[] buf2 = new int[Note.N]; - for (int i = 0; i < n_samples; i += Note.N) { - if (i >= n_samples * (7. / 8.)) { - note.keyup(); + for (int i = 0; i < nSamples; i += Note.N) { + if (i >= nSamples * (7. / 8.)) { + note.keyUp(); } - int lfoValue = lfo.getsample(); - int lfoDelay = lfo.getdelay(); + int lfoValue = context.lfo.getSample(); + int lfoDelay = context.lfo.getDelay(); note.compute(buf, lfoValue, lfoDelay, controllers); // note.compute(buf, 0, 0, controllers); - final int[][] bufs = { buf }; + int[][] bufs = { buf }; int[][] bufs2 = { buf2 }; filter.process(bufs, filterControl, filterControl, bufs2); for (int j = 0; j < Note.N; j++) { buf2[j] >>= 2; // buf[j] >>= 2; } - write_data(line, buf2, Note.N); + writeData(line, buf2, Note.N); } } line.drain(); @@ -384,7 +386,7 @@ public static void t1(String[] args) throws Exception { static byte[] sample_buf = new byte[128]; - static void write_data(SourceDataLine line, final int[] buf, int n) { + static void writeData(SourceDataLine line, int[] buf, int n) { int delta = 0x100; for (int i = 0; i < n; i++) { int val = buf[i]; @@ -396,5 +398,3 @@ static void write_data(SourceDataLine line, final int[] buf, int n) { line.write(sample_buf, 0, n * 2); } } - -/* */ diff --git a/src/test/java/vavi/sound/dx7/Dx7Test.java b/src/test/java/vavi/sound/dx7/Dx7Test.java index 2b0dc03..bb01f71 100644 --- a/src/test/java/vavi/sound/dx7/Dx7Test.java +++ b/src/test/java/vavi/sound/dx7/Dx7Test.java @@ -26,48 +26,48 @@ class Dx7Test { @Test void test_sin_accuracy() { - Debug.println("test_sin_accuracy ----"); +Debug.println("test_sin_accuracy ----"); Random random = new Random(); - double maxerr = 0; + double maxErr = 0; for (int i = 0; i < 1000000; i++) { int phase = random.nextInt() & ((1 << 24) - 1); int y = Sin.compute(phase); double yd = (1 << 24) * Math.sin(phase * (Math.PI / (1 << 23))); double err = Math.abs(y - yd); - if (err > maxerr) maxerr = err; + if (err > maxErr) maxErr = err; } - Debug.println("Max error: " + maxerr); - assertEquals(2.5, maxerr, 0.05); +Debug.println("Max error: " + maxErr); + assertEquals(2.5, maxErr, 0.05); } @Test void test_tanh_accuracy() { - Debug.println("test_tanh_accuracy ----"); +Debug.println("test_tanh_accuracy ----"); Random random = new Random(); - double maxerr = 0; + double maxErr = 0; for (int i = 0; i < 1000000; i++) { int x = (random.nextInt() & ((1 << 29) - 1)) - (1 << 28); int y = Tanh.lookup(x); double yd = (1 << 24) * Math.tanh(x * (1.0 / (1 << 24))); double err = Math.abs(y - yd); - if (err > maxerr) { - Debug.println("x = " + x + ", y = " + y + ", yd = " + (int) yd); - maxerr = err; + if (err > maxErr) { +Debug.println("x = " + x + ", y = " + y + ", yd = " + (int) yd); + maxErr = err; } } - Debug.println("Max error: " + maxerr); - assertEquals(25.8, maxerr, 0.1); +Debug.println("Max error: " + maxErr); + assertEquals(25.8, maxErr, 0.15); } @Test void test_exp2() { - Debug.println("test_exp2 --------"); +Debug.println("test_exp2 --------"); for (int i = -16 << 24; i < 6 << 24; i += 123) { int result = Exp2.lookup(i); int accurate = (int) Math.floor((1 << 24) * Math.pow(2, i * 1.0 / (1 << 24)) + .5); int error = accurate - result; if (Math.abs(error) > 1 && Math.abs(error) > accurate / 10000000) { - Debug.println(i + ": " + result + " " + accurate); +Debug.println(i + ": " + result + " " + accurate); fail(); } } @@ -75,18 +75,18 @@ void test_exp2() { @Test void test_pure_accuracy() { - Debug.println("test_pure_accuracy ----"); +Debug.println("test_pure_accuracy ----"); Random random = new Random(); - int worstfreq = 0; - int worstphase = 0; - int worsterr = 0; + int worstFreq = 0; + int worstPhase = 0; + int worstErr = 0; double errsum = 0; for (int i = 0; i < 1000000; i++) { int freq = random.nextInt() & 0x7fffff; int phase = random.nextInt() & 0xffffff; int gain = 1 << 24; int[] buf = new int[64]; - FmOpKernel.compute_pure(buf, phase, freq, gain, gain, false); + FmOpKernel.computePure(buf, phase, freq, gain, gain, false); int maxerr = 0; for (int j = 0; j < 64; j++) { double y = gain * Math.sin((phase + j * freq) * (2.0 * Math.PI / (1 << 24))); @@ -96,18 +96,17 @@ void test_pure_accuracy() { maxerr = err; } errsum += maxerr; - if (maxerr > worsterr) { - worsterr = maxerr; - worstfreq = freq; - worstphase = phase; + if (maxerr > worstErr) { + worstErr = maxerr; + worstFreq = freq; + worstPhase = phase; + } + if (i < 10) { +Debug.println(phase + " " + freq + " " + maxerr); } - if (i < 10) - Debug.println(phase + " " + freq + " " + maxerr); } - Debug.println(worstphase + " " + worstfreq + " " + worsterr); - Debug.println("Mean: " + (errsum * 1e-6)); - assertEquals(77.08, errsum * 1e-6, 0.01); +Debug.println(worstPhase + " " + worstFreq + " " + worstErr); +Debug.println("Mean: " + (errsum * 1e-6)); + assertEquals(77.08, errsum * 1e-6, 0.015); } } - -/* */ diff --git a/src/test/java/vavi/sound/dx7/FilerTest.java b/src/test/java/vavi/sound/dx7/FilerTest.java index 86cc646..4d0ae65 100644 --- a/src/test/java/vavi/sound/dx7/FilerTest.java +++ b/src/test/java/vavi/sound/dx7/FilerTest.java @@ -30,7 +30,7 @@ public class FilerTest { static long v = 0; - void condition_governor() { + void conditionGovernor() { // sleep for a bit to avoid thermal throttling try { Thread.sleep(900); @@ -49,7 +49,7 @@ void condition_governor() { v = x; } - float[] mkrandom(int size) { + float[] makeRandom(int size) { Random random = new Random(System.currentTimeMillis()); float[] result = new float[size]; for (int i = 0; i < size; i++) { @@ -58,26 +58,26 @@ float[] mkrandom(int size) { return result; } -// double test_accuracy(FirFilter f1, FirFilter f2, final float[] inp, int nblock) { -// float[] out1 = new float[nblock]; -// float[] out2 = new float[nblock]; -// f1.process(inp, 1, out1, nblock); -// f2.process(inp, 1, out2, nblock); +// double test_accuracy(FirFilter f1, FirFilter f2, final float[] inp, int nBlock) { +// float[] out1 = new float[nBlock]; +// float[] out2 = new float[nBlock]; +// f1.process(inp, 1, out1, nBlock); +// f2.process(inp, 1, out2, nBlock); // double err = 0; -// for (int i = 0; i < nblock; i++) { +// for (int i = 0; i < nBlock; i++) { // Debug.printf("#%d: %f %f\n", i, out1[i], out2[i]); // err += Math.abs(out1[i] - out2[i]); // } // return err; // } + +// void benchFir(int size, int experiment) { +// conditionGovernor(); // -// void benchfir(int size, int experiment) { -// condition_governor(); -// -// final int nblock = 64; -// float[] kernel = mkrandom(size); -// float[] inp = mkrandom(size + nblock); -// float[] out = new float[nblock]; +// final int nBlock = 64; +// float[] kernel = makeRandom(size); +// float[] in = makeRandom(size + nBlock); +// float[] out = new float[nBlock]; // FirFilter f; // // switch (experiment) { @@ -85,35 +85,35 @@ float[] mkrandom(int size) { // f = new SimpleFirFilter(kernel, size); // break; // case 4: -// f = new HalfRateFirFilter(kernel, size, nblock); +// f = new HalfRateFirFilter(kernel, size, nBlock); // break; // } // // double start = System.currentTimeMillis(); // for (int j = 0; j < 15625; j++) { -// f.process(inp, 1, out, nblock); +// f.process(in, 1, out, nBlock); // } // double elapsed = System.currentTimeMillis() - start; // Debug.printf("%i %f\n", size, 1e3 * elapsed); // // FirFilter fbase = new SimpleFirFilter(kernel, size); -// double accuracy = test_accuracy(fbase, f, inp, nblock); +// double accuracy = test_accuracy(fbase, f, in, nBlock); // Debug.printf("#accuracy = %g\n", accuracy); // } // @Test -// void runfirbench() { +// void runFirBench() { // Debug.printf("set style data linespoints\n" + "set xlabel 'FIR kernel size'\n" + "set ylabel 'ns per sample'\n" + // "plot '-' title 'scalar', '-' title '4x4 block', '-' title 'fixed16', '-' title 'fixed16 mirror', '-' title 'half rate'\n"); // for (int experiment = 0; experiment < 6; experiment++) { // for (int i = 16; i <= 256; i += 16) { -// benchfir(i, experiment); +// benchFir(i, experiment); // } // Debug.printf("e\n"); // } // } - void scalarbiquad(final float[] inp, float[] out, int n, float b0, float b1, float b2, float a1, float a2) { + void scalarBiQuad(float[] inp, float[] out, int n, float b0, float b1, float b2, float a1, float a2) { float x1 = 0, x2 = 0, y1 = 0, y2 = 0; for (int i = 0; i < n; i++) { float x = inp[i]; @@ -126,16 +126,16 @@ void scalarbiquad(final float[] inp, float[] out, int n, float b0, float b1, flo } } - void benchscalarbiquad() { - condition_governor(); + void benchScalarBiQuad() { + conditionGovernor(); final int nbuf = 1 << 10; - float[] inp = mkrandom(nbuf); + float[] inp = makeRandom(nbuf); float[] out = new float[nbuf]; double start = System.currentTimeMillis(); final int niter = 10000; for (int i = 0; i < niter; i++) { - scalarbiquad(inp, out, nbuf, 1.0207f, -1.7719f, .9376f, -1.7719f, 0.9583f); + scalarBiQuad(inp, out, nbuf, 1.0207f, -1.7719f, .9376f, -1.7719f, 0.9583f); } double elapsed = System.currentTimeMillis() - start; double ns_per_iir = 1e9 * elapsed / nbuf / niter; @@ -143,7 +143,7 @@ void benchscalarbiquad() { } // see "lab/biquadin two.ipynb" for why - void initbiquadmatrix(float[] matrix, double b0, double b1, double b2, double a1, double a2) { + void initBiquadMatrix(float[] matrix, double b0, double b1, double b2, double a1, double a2) { double c1 = b1 - a1 * b0; double c2 = b2 - a2 * b0; matrix[0] = (float) b0; @@ -165,15 +165,15 @@ void initbiquadmatrix(float[] matrix, double b0, double b1, double b2, double a1 } @Test - void runbiquad() { - benchscalarbiquad(); + void runBiQuad() { + benchScalarBiQuad(); } @Test void runfmbench() { - condition_governor(); - final int nbuf = 64; - int[] out = new int[nbuf]; + conditionGovernor(); + final int nBuf = 64; + int[] out = new int[nBuf]; int freq = (int) (440.0 / 44100.0 * (1 << 24)); double start = System.currentTimeMillis(); @@ -183,19 +183,18 @@ void runfmbench() { } double elapsed = System.currentTimeMillis() - start; - double ns_per_sample = 1e9 * elapsed / nbuf / niter; - Debug.printf("fm op kernel: %f ms/sample\n", ns_per_sample); + double nsPerSample = 1e9 * elapsed / nBuf / niter; + Debug.printf("fm op kernel: %f ms/sample\n", nsPerSample); } @Test - void runsawbench() { - condition_governor(); - double sample_rate = 44100.0; - Sawtooth.init(sample_rate); - final int nbuf = 64; - int[] out = new int[nbuf]; - Sawtooth s = new Sawtooth(); - int[] control_last = new int[1]; + void runSawBench() { + conditionGovernor(); + double sampleRate = 44100.0; + final int nBuf = 64; + int[] out = new int[nBuf]; + Sawtooth s = Sawtooth.getInstance(sampleRate); + int[] controlLast = new int[1]; int[] control = new int[1]; int[][] bufs = new int[1][]; bufs[0] = out; @@ -203,38 +202,38 @@ void runsawbench() { for (int i = 0; i < 1; i++) { double f = 440.0 * (i + 1); control[0] = (int) ((1 << 24) * Math.log(f) / Math.log(2)); - control_last[0] = control[0]; + controlLast[0] = control[0]; double start = System.currentTimeMillis(); final int niter = 1000000; for (int j = 0; j < niter; j++) { - s.process(null, control, control_last, bufs); + s.process(null, control, controlLast, bufs); } double elapsed = System.currentTimeMillis() - start; - double ns_per_sample = 1e9 * elapsed / nbuf / niter; - Debug.printf("sawtooth %gHz: %f ms/sample\n", f, ns_per_sample); + double nsPerSample = 1e9 * elapsed / nBuf / niter; + Debug.printf("sawtooth %gHz: %f ms/sample\n", f, nsPerSample); } } @Test - void runladderbench() { - ResoFilter.test_matrix(); - condition_governor(); - double sample_rate = 44100.0; - Freqlut.init(sample_rate); - final int nbuf = 64; - int[] in = new int[nbuf]; - int[] out = new int[nbuf]; - ResoFilter r = new ResoFilter(); - int[] control_last = new int[3]; + void runLadderBench() { + ResoFilter.testMatrix(); + conditionGovernor(); + float sampleRate = 44100.0f; + final int nBuf = 64; + int[] in = new int[nBuf]; + int[] out = new int[nBuf]; + Context context = Context.getInstance(sampleRate); + ResoFilter r = new ResoFilter(context); + int[] controlLast = new int[3]; int[] control = new int[3]; - int[][] inbufs = new int[1][]; - int[][] outbufs = new int[1][]; - inbufs[0] = in; - outbufs[0] = out; + int[][] inBufs = new int[1][]; + int[][] outBufs = new int[1][]; + inBufs[0] = in; + outBufs[0] = out; - for (int i = 0; i < nbuf; i++) { + for (int i = 0; i < nBuf; i++) { in[i] = (i - 32) << 18; } control[0] = 1 << 23; @@ -245,15 +244,13 @@ void runladderbench() { final int niter = 1000000; // for (float f : in) System.err.printf("%f, ", f); System.err.println(); for (int i = 0; i < niter; i++) { - r.process(inbufs, control, control_last, outbufs); + r.process(inBufs, control, controlLast, outBufs); } for (float f : out) System.err.printf("%f, ", f); System.err.println(); double elapsed = System.currentTimeMillis() - start; - double ns_per_sample = 1e9 * elapsed / nbuf / niter; - Debug.printf("ladder %s: %f ms/sample\n", nl != 0 ? "nonlinear" : "linear", ns_per_sample); + double nsPerSample = 1e9 * elapsed / nBuf / niter; + Debug.printf("ladder %s: %f ms/sample\n", nl != 0 ? "nonlinear" : "linear", nsPerSample); } } } - -/* */ diff --git a/src/test/java/vavi/sound/dx7/SawtoothTest.java b/src/test/java/vavi/sound/dx7/SawtoothTest.java index 400f729..e97c3e2 100644 --- a/src/test/java/vavi/sound/dx7/SawtoothTest.java +++ b/src/test/java/vavi/sound/dx7/SawtoothTest.java @@ -9,13 +9,14 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; -import javax.sound.sampled.FloatControl; import javax.sound.sampled.SourceDataLine; import org.junit.jupiter.api.Test; import vavi.util.Debug; +import static vavi.sound.SoundUtil.volume; + /** * SawtoothTest. @@ -25,39 +26,37 @@ */ class SawtoothTest { + static double volume = Double.parseDouble(System.getProperty("vavi.test.volume", "0.2")); + @Test void test() throws Exception { - double sample_rate = 44100.0; - final int n_samples = 400 * 1024; + float sampleRate = 44100.0f; + final int nSamples = 400 * 1024; - Sawtooth.init(sample_rate); - - Sawtooth s = new Sawtooth(); - int[] control_last = new int[1]; + Sawtooth s = Sawtooth.getInstance(sampleRate); + int[] controlLast = new int[1]; int[] control = new int[1]; - ResoFilter rf = new ResoFilter(); - int[] fc_last = new int[2]; + Context context = Context.getInstance(sampleRate); + ResoFilter rf = new ResoFilter(context); + int[] fcLast = new int[2]; int[] fc = new int[2]; fc[0] = 0; // TODO fc[1] = (int) (4.2 * (1 << 24)); - fc_last[0] = fc[0]; - fc_last[1] = fc[1]; + fcLast[0] = fc[0]; + fcLast[1] = fc[1]; double ramp = 1e-7; double f0 = ramp * (64 + 1); - control[0] = (int) ((1 << 24) * Math.log(f0 * sample_rate) / Math.log(2)); + control[0] = (int) ((1 << 24) * Math.log(f0 * sampleRate) / Math.log(2)); - AudioFormat audioFormat = new AudioFormat((float) sample_rate, 16, 1, true, false); + AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(lineInfo); // CountDownLatch cdl = new CountDownLatch(1); - line.addLineListener(event -> { Debug.println(event.getType()); }); + line.addLineListener(event -> Debug.println(event.getType())); line.open(); -FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); -double gain = .2d; // number between 0 and 1 (loudest) -float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); -gainControl.setValue(dB); + volume(line, volume); line.start(); int[] buf = new int[64]; @@ -67,40 +66,38 @@ void test() throws Exception { bufs[0] = buf; bufs2[0] = buf2; // int phase = 0; - for (int i = 0; i < n_samples; i += 64) { + for (int i = 0; i < nSamples; i += 64) { double f = ramp * (i + 64 + 1); - // f = 44.0 / sample_rate; - control_last[0] = control[0]; - control[0] = (int) ((1 << 24) * Math.log(f * sample_rate) / Math.log(2)); - fc_last[1] = fc[1]; - fc[1] = (int) (4.0 * i * (1 << 24) / n_samples); - s.process(null, control, control_last, bufs); - rf.process(bufs, fc, fc_last, bufs2); + // f = 44.0 / sampleRate; + controlLast[0] = control[0]; + control[0] = (int) ((1 << 24) * Math.log(f * sampleRate) / Math.log(2)); + fcLast[1] = fc[1]; + fc[1] = (int) (4.0 * i * (1 << 24) / nSamples); + s.process(null, control, controlLast, bufs); + rf.process(bufs, fc, fcLast, bufs2); for (int j = 0; j < 64; j++) { buf2[j] = buf[j] >> 1; // phase += 100000; // buf2[j] = (Sin.compute(phase) - (int)((1<< 24) * sin(phase * 2 * M_PI / (1 << 24)))) << 12; } - write_data(line, buf2, 64); + writeData(line, buf2, 64); } line.drain(); line.close(); } - static byte[] sample_buf = new byte[128]; + static byte[] sampleBuf = new byte[128]; - static void write_data(SourceDataLine line, final int[] buf, int n) { + static void writeData(SourceDataLine line, int[] buf, int n) { int delta = 0x100; for (int i = 0; i < n; i++) { int val = buf[i]; - int clip_val = val < -(1 << 24) ? 0x8000 : (val >= (1 << 24) ? 0x7fff : (val + delta) >> 9); + int clipVal = val < -(1 << 24) ? 0x8000 : (val >= (1 << 24) ? 0x7fff : (val + delta) >> 9); delta = (delta + val) & 0x1ff; - sample_buf[i * 2] = (byte) (clip_val & 0xff); - sample_buf[i * 2 + 1] = (byte) ((clip_val >> 8) & 0xff); + sampleBuf[i * 2] = (byte) (clipVal & 0xff); + sampleBuf[i * 2 + 1] = (byte) ((clipVal >> 8) & 0xff); } - line.write(sample_buf, 0, n * 2); + line.write(sampleBuf, 0, n * 2); } } - -/* */ diff --git a/src/test/java/vavi/sound/dx7/TestInstrument.java b/src/test/java/vavi/sound/dx7/TestInstrument.java index aebcc35..1ac2278 100644 --- a/src/test/java/vavi/sound/dx7/TestInstrument.java +++ b/src/test/java/vavi/sound/dx7/TestInstrument.java @@ -36,5 +36,3 @@ public ModelPerformer[] getPerformers() { return null; } } - -/* */ diff --git a/src/test/resources/logging.properties b/src/test/resources/logging.properties index 7d550e0..3b2a8ba 100644 --- a/src/test/resources/logging.properties +++ b/src/test/resources/logging.properties @@ -1,14 +1,6 @@ handlers=java.util.logging.ConsoleHandler .level=INFO -# Limit the message that are printed on the console to INFO and above. -java.util.logging.ConsoleHandler.level=INFO -#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter -# %1:date/time %2:className and methodName %3logName %4:level %5:message %6:errormessage -#java.util.logging.SimpleFormatter.format=%1$tY/%1$tm/%1$td %1$tH:%1$tM:%1$tS.%1$tL [%4$s] %5$s %6$s%n - -# HttpUrlConnection -#java.util.logging.ConsoleHandler.level=FINEST -#sun.net.www.protocol.http.HttpURLConnection.level=ALL - +java.util.logging.ConsoleHandler.level=ALL java.util.logging.ConsoleHandler.formatter=vavi.util.logging.VaviFormatter -#java.util.logging.ConsoleHandler.formatter=vavi.util.logging.BetterFormatter + +#vavi.util.level=FINE diff --git a/src/test/resources/test.mid b/src/test/resources/test.mid new file mode 100644 index 0000000..a52838c Binary files /dev/null and b/src/test/resources/test.mid differ