Skip to content

Commit

Permalink
parse sound files in Minecraft
Browse files Browse the repository at this point in the history
  • Loading branch information
Pixaurora committed Sep 27, 2024
1 parent 4b2b1c8 commit 8f0a6ef
Show file tree
Hide file tree
Showing 24 changed files with 217 additions and 18 deletions.
2 changes: 2 additions & 0 deletions projects/catculator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ mod {
dependencies {
implementation(libs.annotations)
implementation(libs.quilt.loader)

implementation(project(":projects:kit-tunes-api"))
}

tasks.register("buildDevNatives") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.pixaurora.catculator.impl.music;

import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;

public class SoundFile {
public static Duration parseDuration(Path path) throws IOException {
long nanos = parseDuration0(path.toString());

return Duration.ofNanos(nanos);
}

private static native long parseDuration0(String path) throws IOException;
}
1 change: 1 addition & 0 deletions projects/catculator/src/main/rust/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::Result;
use jni::{objects::JObject, sys::jlong, JNIEnv};

mod http;
mod sound_parsing;

fn get_pointer<'local>(env: &mut JNIEnv<'local>, object: &JObject<'local>) -> Result<jlong> {
Ok(env.get_field(object, "pointer", "J")?.try_into()?)
Expand Down
31 changes: 31 additions & 0 deletions projects/catculator/src/main/rust/bridge/sound_parsing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use jni::{
objects::{JClass, JString},
sys::jlong,
JNIEnv,
};

use crate::sound_parsing::audio_length;
use crate::Result;

fn parse_duration<'local>(env: &mut JNIEnv<'local>, path: &JString<'local>) -> Result<jlong> {
let path: String = env.get_string(path)?.into();

let duration = audio_length(path)?;

Ok(duration.as_nanos().try_into()?)
}

#[no_mangle]
pub extern "system" fn Java_net_pixaurora_catculator_impl_music_SoundFile_parseDuration0<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
path: JString<'local>,
) -> jlong {
match parse_duration(&mut env, &path) {
Ok(duration) => duration,
Err(error) => {
error.throw(&mut env);
jlong::default()
}
}
}
9 changes: 9 additions & 0 deletions projects/catculator/src/main/rust/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt::Display;
use std::num::TryFromIntError;

use jni::errors::Error as JNIError;
use jni::JNIEnv;
Expand All @@ -17,6 +18,7 @@ pub enum Error {
Join(JoinError),
Server(String),
Lofty(LoftyError),
TryFromInt(TryFromIntError),
}

pub type Result<T> = core::result::Result<T, Error>;
Expand All @@ -41,6 +43,7 @@ impl Display for Error {
Error::Join(error) => error.fmt(f),
Error::Server(message) => write!(f, "Server Error: {}", message),
Error::Lofty(error) => error.fmt(f),
Error::TryFromInt(error) => error.fmt(f),
}
}
}
Expand Down Expand Up @@ -80,3 +83,9 @@ impl From<LoftyError> for Error {
Error::Lofty(value)
}
}

impl From<TryFromIntError> for Error {
fn from(value: TryFromIntError) -> Self {
Error::TryFromInt(value)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.pixaurora.kit_tunes.api.music;

import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.Random;
Expand All @@ -24,4 +25,6 @@ public default Optional<Album> album() {
}

public List<Album> albums();

public Duration duration();
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package net.pixaurora.kitten_cube.impl;

import java.io.IOException;

import net.pixaurora.kit_tunes.api.resource.ResourcePath;
import net.pixaurora.kitten_cube.impl.math.Size;
import net.pixaurora.kitten_cube.impl.text.Component;
import net.pixaurora.kitten_cube.impl.ui.screen.Screen;
import net.pixaurora.kitten_cube.impl.ui.sound.Sound;
import net.pixaurora.kitten_heart.impl.KitTunes;
import net.pixaurora.kitten_heart.impl.resource.temp.FileAccess;
import net.pixaurora.kitten_heart.impl.service.MinecraftUICompat;

public final class MinecraftClient {
Expand Down Expand Up @@ -39,4 +43,8 @@ public static void setScreen(Screen screen) {
public static void openURL(String url) {
impl().openURL(url);
}

public static FileAccess accessResource(ResourcePath resource) throws IOException {
return impl().accessResource(resource);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.pixaurora.kitten_heart.impl;

import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -8,15 +10,19 @@
import java.util.function.Consumer;
import java.util.Optional;

import net.pixaurora.catculator.impl.music.SoundFile;
import net.pixaurora.kit_tunes.api.event.TrackEndEvent;
import net.pixaurora.kit_tunes.api.event.TrackStartEvent;
import net.pixaurora.kit_tunes.api.listener.MusicEventListener;
import net.pixaurora.kit_tunes.api.music.ListeningProgress;
import net.pixaurora.kit_tunes.api.music.Track;
import net.pixaurora.kit_tunes.api.resource.ResourcePath;
import net.pixaurora.kitten_cube.impl.MinecraftClient;
import net.pixaurora.kitten_heart.impl.error.UnhandledKitTunesException;
import net.pixaurora.kitten_heart.impl.event.TrackEventImpl;
import net.pixaurora.kitten_heart.impl.music.metadata.MusicMetadata;
import net.pixaurora.kitten_heart.impl.music.progress.PolledListeningProgress;
import net.pixaurora.kitten_heart.impl.resource.temp.FileAccess;
import net.pixaurora.kitten_heart.impl.util.Pair;

public class EventHandling {
Expand Down Expand Up @@ -73,11 +79,23 @@ public static synchronized void stop() {
private static synchronized TrackStartEvent createStartEvent(ResourcePath path, ListeningProgress progress) {
Optional<Track> track = MusicMetadata.matchTrack(path);

if (track.isPresent()) {
Duration songDuration = UnhandledKitTunesException.runOrThrow(() -> songDuration(path));

MusicMetadata.asMutable().giveDuration(track.get(), songDuration);
}

PLAYING_TRACKS.put(progress, Pair.of(path, track));

return new TrackEventImpl(path, track, progress);
}

private static Duration songDuration(ResourcePath path) throws IOException {
try (FileAccess resource = MinecraftClient.accessResource(path)) {
return SoundFile.parseDuration(resource.path());
}
}

private static synchronized Pair<ResourcePath, Optional<Track>> getTrackInfo(ListeningProgress progress,
boolean flushFromMap) {
Pair<ResourcePath, Optional<Track>> trackInfo = Objects.requireNonNull(PLAYING_TRACKS.get(progress));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@ public void onTrackEnd(TrackEndEvent event) {
Track track = event.track().get();
ListeningProgress progress = event.progress();

boolean longEnoughToScrobble = progress.amountPlayed().compareTo(Duration.ofMinutes(1)) > 0;
Duration requiredLength = track.duration().dividedBy(2);
boolean longEnoughToScrobble = progress.amountPlayed().compareTo(requiredLength) > 0;
// We use 60 seconds as the amount of time required to scrobble a song, for now.

if (longEnoughToScrobble) {
KitTunes.SCROBBLER_CACHE
.execute(scrobblers -> scrobblers.completeScrobbling(new ScrobbledTrack(track, progress)));
} else {
KitTunes.LOGGER.info("Skipping scrobbling " + track.name() + " because it only played for "
+ (float) progress.amountPlayed().toMillis() / 1000 + " seconds!");
float amountPlayed = (float) progress.amountPlayed().toMillis() / 1000;
float amountRequired = (float) requiredLength.toMillis() / 1000;
KitTunes.LOGGER.info("Skipping scrobbling " + track.name() + " because it only played for " +
amountPlayed + " out of " + amountRequired + " seconds!");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.pixaurora.kitten_heart.impl.music;

import java.lang.reflect.Type;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -64,6 +65,11 @@ public List<Album> albums() {
return MusicMetadata.albumsWithTrack(this);
}

@Override
public Duration duration() {
return MusicMetadata.trackDuration(this);
}

public static interface TransformsToTrack extends TransformsTo<Track> {
public static class Serializer implements JsonDeserializer<TrackImpl.TransformsToTrack> {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.pixaurora.kitten_heart.impl.music.metadata;

import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.Optional;

Expand All @@ -11,21 +12,20 @@
import net.pixaurora.kit_tunes.api.music.Track;
import net.pixaurora.kit_tunes.api.resource.ResourcePath;
import net.pixaurora.kitten_cube.impl.text.Component;
import net.pixaurora.kitten_heart.impl.service.MusicMetadataService;

public final class MusicMetadata {
private static final String METADATA_PREFIX = "kit_tunes.metadata";
private static final String SEPARATOR = ".";

private static @Nullable MusicMetadataService IMPL;
private static @Nullable MusicMetadataImpl IMPL;

public static void init(List<Path> albumFiles, List<Path> artistFiles, List<Path> trackFiles) {
IMPL = new MusicMetadataImpl();

IMPL.load(albumFiles, artistFiles, trackFiles);
}

private static MusicMetadataService impl() {
private static MusicMetadataImpl impl() {
if (IMPL == null) {
throw new RuntimeException("MusicMetadata was accessed too early!");
} else {
Expand All @@ -49,6 +49,10 @@ public static List<Album> albumsWithTrack(Track track) {
return impl().albumsWithTrack(track);
}

public static Duration trackDuration(Track track) {
return impl().trackDuration(track);
}

public static Component asComponent(Track track) {
return Component.translatableWithFallback(translationKey(track.path()), track.name());
}
Expand All @@ -66,4 +70,8 @@ private static String translationKey(ResourcePath path) {

return METADATA_PREFIX + SEPARATOR + specifier;
}

public static MutableMusicMetadata asMutable() {
return impl();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.pixaurora.kitten_heart.impl.music.metadata;

import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -21,6 +22,8 @@ public class MusicMetadataImpl implements MusicMetadataService, MutableMusicMeta
private final HashMap<String, Track> trackMatches = new HashMap<>();
private final HashMap<ResourcePath, List<Album>> trackToAlbums = new HashMap<>();

private final HashMap<ResourcePath, Duration> trackDurations = new HashMap<>();

@Override
public void add(Album album) {
this.albums.put(album.path(), album);
Expand All @@ -44,6 +47,11 @@ public void add(Track track) {
}
}

@Override
public void giveDuration(Track track, Duration duration) {
this.trackDurations.put(track.path(), duration);
}

@Override
public void load(List<Path> albumFiles, List<Path> artistFiles, List<Path> trackFiles) {
MusicMetadataLoader.load(this, albumFiles, artistFiles, trackFiles);
Expand Down Expand Up @@ -75,4 +83,14 @@ public Optional<Track> getTrack(ResourcePath path) {
return Optional.ofNullable(tracks.get(path));
}

@Override
public Duration trackDuration(Track track) {
Optional<Duration> duration = Optional.ofNullable(this.trackDurations.get(track.path()));

if (duration.isPresent()) {
return duration.get();
} else {
throw new RuntimeException("Track duration has not been initialized for Track `" + track.path() + "`!");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.pixaurora.kitten_heart.impl.music.metadata;

import java.time.Duration;

import net.pixaurora.kit_tunes.api.music.Album;
import net.pixaurora.kit_tunes.api.music.Artist;
import net.pixaurora.kit_tunes.api.music.Track;
Expand All @@ -10,4 +12,6 @@ public interface MutableMusicMetadata {
public void add(Artist artist);

public void add(Track track);

public void giveDuration(Track track, Duration duration);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package net.pixaurora.kitten_heart.impl.resource.temp;

import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import org.quiltmc.loader.api.QuiltLoader;

Expand All @@ -18,17 +18,12 @@ public static FileAccess create(Path staticFile) {

public static FileAccess create(InputStream data) throws IOException {
Files.createDirectories(TEMP_FILE_DIR);
// TODO: Make the workaround of adding `.ogg` unnecessary
Path tempFile = Files.createTempFile(TEMP_FILE_DIR, null, ".ogg");

Path tempFile = Files.createTempFile(TEMP_FILE_DIR, null, null);
Files.copy(data, tempFile, StandardCopyOption.REPLACE_EXISTING);

try (BufferedWriter writer = Files.newBufferedWriter(tempFile)) {
int nextByte = data.read();
while (nextByte != -1) {
writer.write((byte) nextByte);
}
}

return new TempFileAcces(tempFile);
return new TempFileAccess(tempFile);
}

public Path path();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import java.nio.file.Files;
import java.nio.file.Path;

public class TempFileAcces implements FileAccess {
public class TempFileAccess implements FileAccess {
private final Path file;

public TempFileAcces(Path file) {
public TempFileAccess(Path file) {
this.file = file;
}

Expand Down
Loading

0 comments on commit 8f0a6ef

Please sign in to comment.