diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65f5925..431eeca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,9 +33,9 @@ jobs: shell: pwsh run: | New-Item -ItemType Directory -Force release | Out-Null - Copy-Item staging/input/Kimusic.jar release/Kimusic-0.1.0.jar - jpackage --type exe --name Kimusic --app-version 0.1.0 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --icon logo.ico --dest release --win-shortcut --win-menu - jpackage --type msi --name Kimusic --app-version 0.1.0 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --icon logo.ico --dest release --win-shortcut --win-menu + Copy-Item staging/input/Kimusic.jar release/Kimusic-0.1.1.jar + jpackage --type exe --name Kimusic --app-version 0.1.1 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --icon logo.ico --dest release --win-shortcut --win-menu + jpackage --type msi --name Kimusic --app-version 0.1.1 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --icon logo.ico --dest release --win-shortcut --win-menu - uses: actions/upload-artifact@v4 with: name: windows-release @@ -62,9 +62,9 @@ jobs: - name: Build Debian package and app image run: | mkdir -p release - cp staging/input/Kimusic.jar release/Kimusic-0.1.0.jar - jpackage --type deb --name Kimusic --app-version 0.1.0 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --dest release - jpackage --type app-image --name Kimusic --app-version 0.1.0 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --dest staging + cp staging/input/Kimusic.jar release/Kimusic-0.1.1.jar + jpackage --type deb --name Kimusic --app-version 0.1.1 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --dest release + jpackage --type app-image --name Kimusic --app-version 0.1.1 --input staging/input --main-jar Kimusic.jar --main-class club.muimi.kimusic.Launcher --dest staging cp src/main/resources/club/muimi/kimusic/logo.png staging/Kimusic/kimusic.png cat > staging/Kimusic/Kimusic.desktop <<'EOF' [Desktop Entry] diff --git a/pom.xml b/pom.xml index e70a7cb..9719d6e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ club.muimi Kimusic - 0.1.0 + 0.1.1 Kimusic diff --git a/src/main/java/club/muimi/kimusic/service/playback/JavaSoundPlaybackEngine.java b/src/main/java/club/muimi/kimusic/service/playback/JavaSoundPlaybackEngine.java index 49650f0..5d1a3d5 100644 --- a/src/main/java/club/muimi/kimusic/service/playback/JavaSoundPlaybackEngine.java +++ b/src/main/java/club/muimi/kimusic/service/playback/JavaSoundPlaybackEngine.java @@ -320,21 +320,16 @@ private float[] spectrumOf(byte[] buffer, int length) { } fft(real, imaginary); - float[] spectrum = new float[64]; + // Return the positive-frequency FFT bins. WaveformView owns the only + // frequency-band projection so logarithmic scaling is not applied twice. int usableBins = fftSize / 2; - for (int band = 0; band < spectrum.length; band++) { - double fromRatio = band / (double) spectrum.length; - double toRatio = (band + 1) / (double) spectrum.length; - int from = Math.max(1, (int) Math.round(Math.pow(fromRatio, 2) * usableBins)); - int to = Math.max(from + 1, (int) Math.round(Math.pow(toRatio, 2) * usableBins)); - double peak = 0; - for (int bin = from; bin < Math.min(to, usableBins); bin++) { - peak = Math.max(peak, Math.hypot(real[bin], imaginary[bin])); - } + float[] spectrum = new float[usableBins]; + for (int bin = 1; bin < usableBins; bin++) { + double magnitude = Math.hypot(real[bin], imaginary[bin]); // Keep a little over-range so the view can normalize all bands against // the current maximum instead of flattening clipped peaks. - spectrum[band] = (float) Math.max(0, Math.min(4, - Math.log10(1 + peak * 18) / Math.log10(19))); + spectrum[bin] = (float) Math.max(0, Math.min(4, + Math.log10(1 + magnitude * 18) / Math.log10(19))); } return spectrum; } diff --git a/src/main/java/club/muimi/kimusic/view/component/WaveformView.java b/src/main/java/club/muimi/kimusic/view/component/WaveformView.java index 90fe4de..e96a5b8 100644 --- a/src/main/java/club/muimi/kimusic/view/component/WaveformView.java +++ b/src/main/java/club/muimi/kimusic/view/component/WaveformView.java @@ -63,10 +63,12 @@ private void pushSpectrum(float[] values) { return; } for (int index = 0; index < spectrum.length; index++) { - int source = Math.min(values.length - 1, - (int) ((long) index * values.length / spectrum.length)); + double normalized = (double) index / spectrum.length; + double freq = 20.0 * Math.pow(20000.0 / 20.0, normalized); + int source = (int) (freq / (20000.0 / values.length)); + source = Math.min(values.length - 1, Math.max(0, source)); // Preserve headroom so dense peaks can be normalized during drawing. - float value = Math.max(0, Math.min(4, values[source])); + float value = Math.max(0, Math.min(20, values[source])); spectrum[index] += (value - spectrum[index]) * (value > spectrum[index] ? 0.62f : 0.2f); spectrumPeaks[index] = Math.max(spectrum[index], spectrumPeaks[index] - 0.018f); } @@ -151,11 +153,17 @@ private void drawSpectrum(GraphicsContext graphics, double width, double height) displayScale = Math.max(0.35, Math.min(6.0, displayScale)); for (int index = 0; index < spectrum.length; index++) { double x = index * width / spectrum.length; - double magnitude = Math.max(0.025, Math.min(1.0, spectrum[index] * displayScale)); + float raw = (float) (spectrum[index] * displayScale); + double db = 20 * Math.log10(raw + 1e-12); + double normalized = (db + 120) / 120; + double magnitude = Math.max(0.025, Math.min(1.0, normalized)); double barHeight = Math.max(3, magnitude * (height - 13)); graphics.setFill(Color.web("#1aa79b", 0.9)); graphics.fillRoundRect(x, height - barHeight, bandWidth, barHeight, 3, 3); - double peakMagnitude = Math.min(1.0, spectrumPeaks[index] * displayScale); + float peakRaw = (float) (spectrumPeaks[index] * displayScale); + double peakDb = 20 * Math.log10(peakRaw + 1e-12); + double peakNormalized = (peakDb + 120) / 120; + double peakMagnitude = Math.max(0.025, Math.min(1.0, peakNormalized)); double peakY = height - Math.max(3, peakMagnitude * (height - 13)); graphics.setFill(Color.web("#8be0d5", 0.86)); graphics.fillRoundRect(x, peakY, bandWidth, 2, 2, 2);