Skip to content

Commit

Permalink
support on-the-fly conversion of audio files to MP3
Browse files Browse the repository at this point in the history
  • Loading branch information
mullermarian committed Jan 8, 2021
1 parent f64e2bb commit 37e54e7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
5 changes: 5 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<scope>system</scope>
<systemPath>${project.basedir}/../libs/vorbis-java-1.0.0-beta.jar</systemPath>
</dependency>
<dependency>
<groupId>de.sciss</groupId>
<artifactId>jump3r</artifactId>
<version>1.0.5</version>
</dependency>
</dependencies>

</project>
67 changes: 67 additions & 0 deletions core/src/main/java/studio/core/v1/utils/AudioConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

package studio.core.v1.utils;

import de.sciss.jump3r.lowlevel.LameEncoder;
import de.sciss.jump3r.mp3.MPEGMode;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand All @@ -15,7 +18,9 @@ public class AudioConversion {

private static final float WAVE_SAMPLE_RATE = 32000.0f;
private static final float OGG_SAMPLE_RATE = 44100.0f;
private static final float MP3_SAMPLE_RATE = 44100.0f;
private static final int BITSIZE = 16;
private static final int MP3_BITSIZE = 32;
private static final int CHANNELS = 1;


Expand Down Expand Up @@ -94,4 +99,66 @@ public static byte[] waveToOgg(byte[] waveData) throws IOException {
throw new IOException("Audio compression to ogg format failed", e);
}
}

public static byte[] anyToMp3(byte[] data) throws IOException {
try {
AudioInputStream inputAudio = AudioSystem.getAudioInputStream(new ByteArrayInputStream(data));

// First, convert to PCM
AudioFormat pcmFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
inputAudio.getFormat().getSampleRate(),
BITSIZE,
inputAudio.getFormat().getChannels(),
inputAudio.getFormat().getChannels()*2,
inputAudio.getFormat().getSampleRate(),
false
);
AudioInputStream pcm = AudioSystem.getAudioInputStream(pcmFormat, inputAudio);

// Then, convert to mono **and oversample** (apparently the input stream in always empty unless the sample rate changes)
AudioFormat pcmOverSampledFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
inputAudio.getFormat().getSampleRate()*2,
BITSIZE,
CHANNELS,
CHANNELS*2,
inputAudio.getFormat().getSampleRate()*2,
false
);
AudioInputStream pcmOverSampled = AudioSystem.getAudioInputStream(pcmOverSampledFormat, pcm);

// Finally, convert sample rate to 44100Hz and sample bitsize to 32 bits
AudioFormat pcm44100Format = new AudioFormat(
AudioFormat.Encoding.PCM_FLOAT,
MP3_SAMPLE_RATE,
MP3_BITSIZE,
CHANNELS,
CHANNELS*4,
MP3_SAMPLE_RATE,
false
);
AudioInputStream pcm44100 = AudioSystem.getAudioInputStream(pcm44100Format, pcmOverSampled);

LameEncoder encoder = new LameEncoder(pcm44100.getFormat(), 64, MPEGMode.MONO.ordinal(), 1, false);

ByteArrayOutputStream mp3 = new ByteArrayOutputStream();
byte[] inputBuffer = new byte[encoder.getPCMBufferSize()];
byte[] outputBuffer = new byte[encoder.getPCMBufferSize()];

int bytesRead;
int bytesWritten;

while (0 < (bytesRead = pcm44100.read(inputBuffer))) {
bytesWritten = encoder.encodeBuffer(inputBuffer, 0, bytesRead, outputBuffer);
mp3.write(outputBuffer, 0, bytesWritten);
}

encoder.close();
return mp3.toByteArray();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
throw new IOException("Unsupported audio format", e);
}
}
}
5 changes: 4 additions & 1 deletion core/src/main/java/studio/core/v1/utils/ImageConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ private static BufferedImage redrawIndexedImage(BufferedImage inputImage) {
int[] rgb = outputImage.getRGB(0, 0, outputImage.getWidth(), outputImage.getHeight(), null, 0, outputImage.getWidth());
int[] cmap = Arrays.stream(rgb).distinct().toArray();

// Force 16-colors palette
int[] cmap16 = Arrays.copyOf(cmap, 16);

// Create indexed image with palette
BufferedImage redrawn = new BufferedImage(outputImage.getWidth(), outputImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, new IndexColorModel(4, cmap.length, cmap, 0, false, -1, 0));
BufferedImage redrawn = new BufferedImage(outputImage.getWidth(), outputImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, new IndexColorModel(4, cmap16.length, cmap16, 0, false, -1, 0));
Graphics2D g2d = redrawn.createGraphics();
g2d.fillRect(0, 0, redrawn.getWidth(), redrawn.getHeight());
g2d.drawImage(outputImage, 0, 0, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ public static StoryPack withPreparedAssetsFirmware2dot4(StoryPack pack) throws I
String assetHash = DigestUtils.sha1Hex(audioData);
if (assets.get(assetHash) == null) {
if (!"audio/mp3".equals(node.getAudio().getMimeType()) && !"audio/mpeg".equals(node.getAudio().getMimeType())) {
// FIXME Cannot convert to MP3, story pack MUST ALREADY be using MP3 audio files
throw new RuntimeException("Cannot convert to MP3, story pack MUST ALREADY be using MP3 audio files");
audioData = AudioConversion.anyToMp3(audioData);
}
assets.put(assetHash, audioData);
}
Expand Down

0 comments on commit 37e54e7

Please sign in to comment.