Skip to content

Commit

Permalink
Rewrote some code parts
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphiMC committed Nov 13, 2024
1 parent ce98368 commit be56cc1
Show file tree
Hide file tree
Showing 35 changed files with 596 additions and 504 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ High performance Java audio mixing library.
- Stereo panning control
- Bass Boost
- Bit Crusher
- High performance (Mix thousands of simultaneously playing sounds in realtime)
- High performance (Mixes thousands of simultaneously playing sounds in realtime)

## Releases
### Gradle/Maven
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ org.gradle.configureondemand=true

maven_group=net.raphimc
maven_name=audio-mixer
maven_version=1.1.1-SNAPSHOT
maven_version=2.0.0-SNAPSHOT
52 changes: 6 additions & 46 deletions src/main/java/net/raphimc/audiomixer/AudioMixer.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,22 @@
package net.raphimc.audiomixer;

import net.raphimc.audiomixer.sound.Sound;
import net.raphimc.audiomixer.sound.SoundModifier;
import net.raphimc.audiomixer.sound.special.SubMixSound;
import net.raphimc.audiomixer.soundmodifier.SoundModifiers;

import javax.sound.sampled.AudioFormat;
import java.util.List;
import java.util.function.Predicate;

public class AudioMixer {

private final AudioFormat audioFormat;
private final SubMixSound masterMixSound;
private final SubMixSound masterMixSound = new SubMixSound();

public AudioMixer(final AudioFormat audioFormat) {
this(audioFormat, 512);
}

public AudioMixer(final AudioFormat audioFormat, final int maxSounds) {
if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
throw new IllegalArgumentException("Unsupported audio format: " + audioFormat);
}

this.audioFormat = audioFormat;
this.masterMixSound = new SubMixSound(maxSounds);
}

public void playSound(final Sound sound) {
Expand All @@ -55,28 +48,8 @@ public void stopAllSounds() {
this.masterMixSound.stopAllSounds();
}

public List<SoundModifier> getSoundModifiers(final Predicate<SoundModifier> predicate) {
return this.masterMixSound.getSoundModifiers(predicate);
}

public void appendSoundModifier(final SoundModifier soundModifier) {
this.masterMixSound.appendSoundModifier(soundModifier);
}

public void prependSoundModifier(final SoundModifier soundModifier) {
this.masterMixSound.prependSoundModifier(soundModifier);
}

public boolean insertSoundModifierBefore(final SoundModifier soundModifier, final SoundModifier other) {
return this.masterMixSound.insertSoundModifierBefore(soundModifier, other);
}

public boolean insertSoundModifierAfter(final SoundModifier soundModifier, final SoundModifier other) {
return this.masterMixSound.insertSoundModifierAfter(soundModifier, other);
}

public void removeSoundModifier(final SoundModifier soundModifier) {
this.masterMixSound.removeSoundModifier(soundModifier);
public SoundModifiers getSoundModifiers() {
return this.masterMixSound.getSoundModifiers();
}

public int[] mix(final float millis) {
Expand All @@ -96,21 +69,8 @@ public AudioFormat getAudioFormat() {
return this.audioFormat;
}

public int getMaxSounds() {
return this.masterMixSound.getMaxSounds();
}

public int getMixedSounds() {
return this.masterMixSound.getMixedSounds();
}

public int getActiveSounds() {
return this.masterMixSound.getActiveSounds();
}

@Deprecated(forRemoval = true)
public void addSoundModifier(final SoundModifier soundModifier) {
this.masterMixSound.appendSoundModifier(soundModifier);
public SubMixSound getMasterMixSound() {
return this.masterMixSound;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,22 @@
*/
package net.raphimc.audiomixer;

import net.raphimc.audiomixer.sound.Sound;
import net.raphimc.audiomixer.sound.SoundModifier;

import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;

public class BackgroundSourceDataLineAudioMixer extends SourceDataLineAudioMixer {

private final ScheduledExecutorService mixingScheduler;

public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine) throws LineUnavailableException {
this(sourceDataLine, 4000);
}

public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int decayPeriodMillis) throws LineUnavailableException {
this(sourceDataLine, 512, decayPeriodMillis);
this(sourceDataLine, 20);
}

public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int maxSounds, final int decayPeriodMillis) throws LineUnavailableException {
this(sourceDataLine, maxSounds, decayPeriodMillis, 20);
}

public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int maxSounds, final int decayPeriodMillis, final int updatePeriodMillis) throws LineUnavailableException {
super(sourceDataLine, maxSounds, decayPeriodMillis, (int) Math.ceil(sourceDataLine.getFormat().getSampleRate() / 1000F * updatePeriodMillis) * sourceDataLine.getFormat().getChannels());
public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int updatePeriodMillis) throws LineUnavailableException {
super(sourceDataLine, (int) Math.ceil(sourceDataLine.getFormat().getSampleRate() / 1000F * updatePeriodMillis) * sourceDataLine.getFormat().getChannels());

this.mixingScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
final Thread thread = new Thread(r, "AudioMixer-MixingThread");
Expand All @@ -55,61 +42,6 @@ public BackgroundSourceDataLineAudioMixer(final SourceDataLine sourceDataLine, f
this.mixingScheduler.scheduleAtFixedRate(this::mixSlice, updatePeriodMillis, updatePeriodMillis, TimeUnit.MILLISECONDS);
}

@Override
public synchronized void playSound(final Sound sound) {
super.playSound(sound);
}

@Override
public synchronized void stopSound(final Sound sound) {
super.stopSound(sound);
}

@Override
public synchronized void stopAllSounds() {
super.stopAllSounds();
}

@Override
public synchronized List<SoundModifier> getSoundModifiers(final Predicate<SoundModifier> predicate) {
return super.getSoundModifiers(predicate);
}

@Override
public synchronized void appendSoundModifier(final SoundModifier soundModifier) {
super.appendSoundModifier(soundModifier);
}

@Override
public synchronized void prependSoundModifier(final SoundModifier soundModifier) {
super.prependSoundModifier(soundModifier);
}

@Override
public synchronized boolean insertSoundModifierBefore(final SoundModifier soundModifier, final SoundModifier other) {
return super.insertSoundModifierBefore(soundModifier, other);
}

@Override
public synchronized boolean insertSoundModifierAfter(final SoundModifier soundModifier, final SoundModifier other) {
return super.insertSoundModifierAfter(soundModifier, other);
}

@Override
public synchronized void removeSoundModifier(final SoundModifier soundModifier) {
super.removeSoundModifier(soundModifier);
}

@Override
public synchronized int[] mix(final int sampleCount) {
return super.mix(sampleCount);
}

@Override
public synchronized int getActiveSounds() {
return super.getActiveSounds();
}

@Override
public void setMixSliceSampleCount(final int mixSliceSampleCount) {
throw new UnsupportedOperationException("Cannot change mix slice sample count for auto-mixing audio mixer");
Expand All @@ -128,11 +60,4 @@ public void close() {
super.close();
}

@Override
@Deprecated(forRemoval = true)
@SuppressWarnings("removal")
public synchronized void addSoundModifier(final SoundModifier soundModifier) {
super.addSoundModifier(soundModifier);
}

}
34 changes: 16 additions & 18 deletions src/main/java/net/raphimc/audiomixer/SourceDataLineAudioMixer.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*/
package net.raphimc.audiomixer;

import net.raphimc.audiomixer.sound.modifier.NormalizationModifier;
import net.raphimc.audiomixer.sound.modifier.VolumeModifier;
import net.raphimc.audiomixer.soundmodifier.impl.NormalizationModifier;
import net.raphimc.audiomixer.soundmodifier.impl.VolumeModifier;
import net.raphimc.audiomixer.util.io.SampleOutputStream;

import javax.sound.sampled.LineUnavailableException;
Expand All @@ -31,19 +31,11 @@ public class SourceDataLineAudioMixer extends AudioMixer {
private final SourceDataLine sourceDataLine;
private final int sampleByteSize;
private int mixSliceSampleCount;
private final NormalizationModifier normalizationModifier;
private final VolumeModifier volumeModifier;
private final NormalizationModifier normalizationModifier = new NormalizationModifier();
private final VolumeModifier volumeModifier = new VolumeModifier(1F);

public SourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int mixSampleCount) throws LineUnavailableException {
this(sourceDataLine, 512, mixSampleCount);
}

public SourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int maxSounds, final int mixSampleCount) throws LineUnavailableException {
this(sourceDataLine, maxSounds, 4000, mixSampleCount);
}

public SourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int maxSounds, final int decayPeriodMillis, final int mixSliceSampleCount) throws LineUnavailableException {
super(sourceDataLine.getFormat(), maxSounds);
public SourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int mixSliceSampleCount) throws LineUnavailableException {
super(sourceDataLine.getFormat());
this.sourceDataLine = sourceDataLine;
if (!sourceDataLine.isOpen()) {
sourceDataLine.open(sourceDataLine.getFormat(), (int) sourceDataLine.getFormat().getSampleRate());
Expand All @@ -53,10 +45,8 @@ public SourceDataLineAudioMixer(final SourceDataLine sourceDataLine, final int m
this.sampleByteSize = sourceDataLine.getFormat().getSampleSizeInBits() / 8;
this.mixSliceSampleCount = mixSliceSampleCount;

this.normalizationModifier = new NormalizationModifier(decayPeriodMillis);
this.volumeModifier = new VolumeModifier(1F);
this.appendSoundModifier(this.normalizationModifier);
this.appendSoundModifier(this.volumeModifier);
this.getSoundModifiers().append(this.normalizationModifier);
this.getSoundModifiers().append(this.volumeModifier);
}

@Override
Expand Down Expand Up @@ -101,6 +91,14 @@ public void setMixSliceSampleCount(final int mixSliceSampleCount) {
this.mixSliceSampleCount = mixSliceSampleCount;
}

public VolumeModifier getVolumeModifier() {
return this.volumeModifier;
}

public NormalizationModifier getNormalizationModifier() {
return this.normalizationModifier;
}

public void setMasterVolume(final int masterVolume) {
this.setMasterVolume(masterVolume / 100F);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.audiomixer.sound.pcmsource;
package net.raphimc.audiomixer.pcmsource;

public interface PcmSource {
public interface MonoPcmSource extends PcmSource {

int getCurrentSample();
int consumeSample(final float increment);

default int consumeSamples(final int[] buffer) {
return this.consumeSamples(buffer, 0, buffer.length);
Expand All @@ -28,15 +28,10 @@ default int consumeSamples(final int[] buffer) {
default int consumeSamples(final int[] buffer, final int offset, final int length) {
int i;
for (i = 0; i < length && !this.hasReachedEnd(); i++) {
buffer[offset + i] = this.getCurrentSample();
this.incrementPosition(1);
buffer[offset + i] = this.consumeSample(1);
}

return i;
}

void incrementPosition(final double increment);

boolean hasReachedEnd();

}
24 changes: 24 additions & 0 deletions src/main/java/net/raphimc/audiomixer/pcmsource/PcmSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* This file is part of AudioMixer - https://github.com/RaphiMC/AudioMixer
* Copyright (C) 2024-2024 RK_01/RaphiMC and contributors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.audiomixer.pcmsource;

public interface PcmSource {

boolean hasReachedEnd();

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.audiomixer.sound.pcmsource;
package net.raphimc.audiomixer.pcmsource;

public interface StaticPcmSource extends PcmSource {
public interface StaticPcmSource {

int getSampleCount();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* This file is part of AudioMixer - https://github.com/RaphiMC/AudioMixer
* Copyright (C) 2024-2024 RK_01/RaphiMC and contributors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.audiomixer.pcmsource;

public interface StereoPcmSource extends PcmSource {

int[] consumeSample(final float increment);

default int consumeSamples(final int[] buffer) {
return this.consumeSamples(buffer, 0, buffer.length);
}

default int consumeSamples(final int[] buffer, final int offset, final int length) {
int i;
for (i = 0; i < length && !this.hasReachedEnd(); i += 2) {
final int index = offset * 2 + i;
final int[] sample = this.consumeSample(1);
buffer[index] = sample[0];
buffer[index + 1] = sample[1];
}

return i;
}

}
Loading

0 comments on commit be56cc1

Please sign in to comment.