How to access and decode sound files
I see literally no way of doing this without making use of some sort of program or script. So I wrote one.
Background:
- There is a .json file for each version of the game in the
%appData%\.minecraft\assets\indexes
folder that contains all the asset "mappings". For example, here is a snippet from it:
{
"objects": {
"minecraft/sounds/ambient/cave/cave1.ogg": {
"hash": "29d4dccf3353334c7aa2a49cb6fed3780a51a1ba",
"size": 33948
}
}
}
- Based off of this file, every sound in Minecraft appears to be a ".ogg" file. This is good news, because this format is supported on a variety of platforms, Windows included, which is what I wrote this script on.
The Script
This is a small C# console application. It's crude, but it got the job done. If you know a little about coding, you should have no problem creating a new console application using Visual Studio (you can download the Community Edition for free if you don't have it) and throwing this code into it to build/run.
Warning: There is no error checking in this code. It's a quick bodge I conjured up. After this runs, the "Minecraft Sounds" folder may take a while to load, since it will contain near ~1000 .ogg files.
Before executing the script, you'll need to do some setup:
- You'll need to copy the .json file and the objects folder found in
%appData%\.minecraft\assets\
out of the appData location and somewhere else (in the code, it references the files/folders inC:\
. - You'll need to create a new folder called "Minecraft Sounds". This is the destination folder that the converted sound files will be placed into.
Here is the code itself:
using System;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;
namespace Minecraft_Sound_Converter
{
class Program
{
static void Main(string[] args)
{
//you'll need to copy these files to this location (or some other location and then update the variables)
string pathToJsonFile = "C:\\1.14.json"; \\this what the latest verison I have on my computer
string pathToObjectsFolder = "C:\\Objects";
string pathToSoundFileFolder = "C:\\Minecraft Sounds";
//parse the json file into a JObject
JObject json = JObject.Parse(JsonConvert.DeserializeObject(File.ReadAllText(pathToJsonFile)).ToString());
//for each token in the json, perform the following operation
foreach (JToken token in (JEnumerable<JToken>)json.First.Children().Children<JToken>())
{
//it's a sound file
if (token.Path.Contains(".ogg"))
{
//get the "hash" property's value
string hashVal = token.First()["hash"].ToString();
//get the name of the file (this is a crude way of doing it, but it works)
string soundName = token.Path.Substring(token.Path.LastIndexOf("/"), (token.Path.Length - token.Path.LastIndexOf("/")) - 2).Replace("/", null);
//find the file via its hash value in the Objects folder by searching all the subdirectories in the directory
string fileName = Directory.GetFiles(pathToObjectsFolder, hashVal, SearchOption.AllDirectories).FirstOrDefault();
//Copy the file to the Minecraft Sounds folder. If it already exists in the folder, overwrite it.
File.Copy(fileName, Path.Combine(pathToSoundFileFolder, soundName), true);
Console.WriteLine($"Copied {soundName}");
}
}
Console.WriteLine("Operation compelte. Press any key to exit.");
Console.ReadLine();
}
}
}
The comments in the code should speak for itself, but if you run this script, it essentially does the following:
- Parses the .json file into a
JObject
. - Loops over all of the
JToken
s in theJEnumerable
object that is created in theforeach
expression. - For each
JToken
, check to see if itsPath
contains the string".ogg"
. If it does, then we know it is a sound file. - Now that we know we are dealing with a sound file, get the token's
hash
property value. This value is that cryptic file name you alluded to in your question. - Get the more "human friendly" name of the sound file. The
Path
contains this, but it needs some substring logic to be performed on it and cleaned up to actually get it. - With the file name (the variable
hashVal
), search the Objects directory that you copied somewhere and all of its sub-directories using thehashVal
and the search criteria. - Copy the sound file found in the Objects directory to the "Minecraft Sounds" directory with the name of the "human friendly" file name. If it already exists in the "Minecraft Sounds" folder, it will overwrite it.
This code is fairly messy (it was kind of meant to be since I had one thing in mind... speed), and it can certainly be cleaned up a lot. But in my tests, it worked, and it copied over 900 files (roughly 140Mb). Since the variable filename
already has the .ogg
extension on it, when Windows detects this, it realizes the file format is a format the it supports, and thus you should be able to play it back without any issues.