Skip to content

Commit

Permalink
Merge pull request #4808 from Tzenchor/Vorbis-BitRate-WorkAround
Browse files Browse the repository at this point in the history
Workaround for converting variable bitrate audio files
  • Loading branch information
KonajuGames committed Apr 27, 2016
2 parents 43b70d3 + 4ec953a commit 414773d
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 23 deletions.
91 changes: 71 additions & 20 deletions MonoGame.Framework.Content.Pipeline/Audio/AudioContent.cs
Expand Up @@ -27,44 +27,86 @@ public class AudioContent : ContentItem
/// Gets the raw audio data.
/// </summary>
/// <value>If unprocessed, the source data; otherwise, the processed data.</value>
public ReadOnlyCollection<byte> Data { get { return data.AsReadOnly(); } }
public ReadOnlyCollection<byte> Data
{
get
{
return data.AsReadOnly();
}
}

/// <summary>
/// Gets the duration (in milliseconds) of the audio data.
/// </summary>
/// <value>Duration of the audio data.</value>
public TimeSpan Duration { get { return duration; } }
public TimeSpan Duration
{
get
{
return duration;
}
}

/// <summary>
/// Gets the file name containing the audio data.
/// </summary>
/// <value>The name of the file containing this data.</value>
[ContentSerializerAttribute]
public string FileName { get { return fileName; } }
public string FileName
{
get
{
return fileName;
}
}

/// <summary>
/// Gets the AudioFileType of this audio source.
/// </summary>
/// <value>The AudioFileType of this audio source.</value>
public AudioFileType FileType { get { return fileType; } }
public AudioFileType FileType
{
get
{
return fileType;
}
}

/// <summary>
/// Gets the AudioFormat of this audio source.
/// </summary>
/// <value>The AudioFormat of this audio source.</value>
public AudioFormat Format { get { return format; } }
public AudioFormat Format
{
get
{
return format;
}
}

/// <summary>
/// Gets the loop length, in samples.
/// </summary>
/// <value>The number of samples in the loop.</value>
public int LoopLength { get { return loopLength; } }
public int LoopLength
{
get
{
return loopLength;
}
}

/// <summary>
/// Gets the loop start, in samples.
/// </summary>
/// <value>The number of samples to the start of the loop.</value>
public int LoopStart { get { return loopStart; } }
public int LoopStart
{
get
{
return loopStart;
}
}

/// <summary>
/// Initializes a new instance of AudioContent.
Expand Down Expand Up @@ -123,7 +165,7 @@ int QualityToBitRate(ConversionQuality quality)
/// the audio is stored external to the XNB file. If this is null, then the converted audio is stored in
/// the Data property.
/// </param>
public void ConvertFormat(ConversionFormat formatType, ConversionQuality quality, string saveToFile)
public ConversionQuality ConvertFormat(ConversionFormat formatType, ConversionQuality quality, string saveToFile)
{
var temporarySource = Path.GetTempFileName();
var temporaryOutput = Path.GetTempFileName();
Expand Down Expand Up @@ -185,17 +227,25 @@ public void ConvertFormat(ConversionFormat formatType, ConversionQuality quality
}

string ffmpegStdout, ffmpegStderr;
var ffmpegExitCode = ExternalTool.Run(
"ffmpeg",
string.Format(
"-y -i \"{0}\" -vn -c:a {1} -b:a {2} -f:a {3} -strict experimental \"{4}\"",
temporarySource,
ffmpegCodecName,
QualityToBitRate(quality),
ffmpegMuxerName,
temporaryOutput),
out ffmpegStdout,
out ffmpegStderr);
int ffmpegExitCode = 0;
do
{
ffmpegExitCode = ExternalTool.Run(
"ffmpeg",
string.Format(
"-y -i \"{0}\" -vn -c:a {1} -b:a {2} -f:a {3} -strict experimental \"{4}\"",
temporarySource,
ffmpegCodecName,
QualityToBitRate(quality),
ffmpegMuxerName,
temporaryOutput),
out ffmpegStdout,
out ffmpegStderr);
if (ffmpegExitCode != 0)
{
quality--;
}
} while (quality >= 0 && ffmpegExitCode!=0);
if (ffmpegExitCode != 0)
{
throw new InvalidOperationException("ffmpeg exited with non-zero exit code: \n" + ffmpegStdout + "\n" + ffmpegStderr);
Expand Down Expand Up @@ -310,6 +360,7 @@ public void ConvertFormat(ConversionFormat formatType, ConversionQuality quality
File.Delete(temporarySource);
File.Delete(temporaryOutput);
}
return quality;
}

private void Read(string filename)
Expand Down Expand Up @@ -383,5 +434,5 @@ private static byte[] GetRawWavData(BinaryReader reader, ref int blockAlign)

return audioData;
}
}
}
}
Expand Up @@ -61,10 +61,12 @@ public override SongContent Process(AudioContent input, ContentProcessorContext
Directory.CreateDirectory(Path.GetDirectoryName(songFileName));

// Convert and write out the song media file.
input.ConvertFormat(targetFormat, quality, songFileName);
ConversionQuality finalQuality = input.ConvertFormat(targetFormat, quality, songFileName);

// Let the pipeline know about the song file so it can clean things up.
context.AddOutputFile(songFileName);
if (quality != finalQuality)
context.Logger.LogMessage("Failed to convert using \"{0}\" quality, used \"{1}\" quality", quality, finalQuality);

// Return the XNB song content.
return new SongContent(PathHelper.GetRelativePath(Path.GetDirectoryName(context.OutputFilename) + Path.DirectorySeparatorChar, songFileName), input.Duration);
Expand Down
Expand Up @@ -49,14 +49,16 @@ public override SoundEffectContent Process(AudioContent input, ContentProcessorC
else
{
// TODO: For some reason this doesn't work on Windows
// so we fallback to plain PCM and depend on the
// so we fallback to plain PCM and depend on the
// bitrate reduction only.
//targetFormat = ConversionFormat.Adpcm;
}
break;
}

input.ConvertFormat(targetFormat, quality, null);
var finalQuality= input.ConvertFormat(targetFormat, quality, null);
if (quality != finalQuality)
context.Logger.LogMessage("Failed to convert using \"{0}\" quality, used \"{1}\" quality", quality, finalQuality);

return new SoundEffectContent(input.Format.NativeWaveFormat, input.Data, input.LoopStart, input.LoopLength, (int)input.Duration.TotalMilliseconds);
}
Expand Down

0 comments on commit 414773d

Please sign in to comment.