0
\$\begingroup\$

I'm working on a custom ScriptedImporter -- let's call it LmmsImporter -- that loads project files from the LMMS sequencer as AudioClips. I don't parse the project file; instead, I expect users to install LMMS, configure its location, then store their project files inside their Assets directory. After the asset settings are configured, the import process looks like this:

  1. Create command-line arguments based on the properties offered by LmmsImporter
  2. Get a temporary path inside the project's Temp directory (not the OS's equivalent)
  3. Spawn an LMMS process that renders the imported project file to the path given by (2), with the arguments given by (1).
  4. Wait for the process to complete.
  5. Load the AudioClip at "runtime" (i.e. in an editor script, not as an imported asset) with UnityWebRequestMultimedia.GetAudioClip
  6. Clone the AudioClip.
  7. Set the cloned AudioClip to be the LMMS project asset's main object, as described here.
  8. Save the imported asset, then delete the original audio file generated by (3).

Everything up to but not including step 7 works as expected. In fact, even step 7 appears to work as expected. But when I open up the imported AudioClip, it has no samples. When I try to play the preview in the editor, I get this error in the editor console:

Error: Cannot create FMOD::Sound instance for resource , (Error loading file. )
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

What makes this weird is that:

  • The sound is properly rendered by LMMS and saved to the filesystem. Nothing unusual happens here.
  • Playing the AudioClip inside the importer script immediately after it's loaded (i.e. while still in OnImportAsset) with AudioSource.PlayAtPoint works as expected.
  • The data is properly cloned; I checked, the arrays are equal.
  • I do not receive any errors or exceptions except those that I've already described, not even from LMMS.

This is an excerpt of my code with the parts I think are most relevant:

using System;
using System.Diagnostics;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEditor;
using UnityEditor.Experimental.AssetImporters;

[ScriptedImporter(1, new[] { "mmp", "mmpz" })]
public class LmmsImporter : ScriptedImporter
{
    // Properties omitted for brevity

    public override void OnImportAsset(AssetImportContext ctx)
    {
        var relativeTempPath = FileUtil.GetUniqueTempPathInProject();
        var projectDir = Path.GetDirectoryName(Application.dataPath);
        var absoluteAssetPath = Path.Combine(projectDir, assetPath);
        var tempPath = Path.Combine(projectDir, relativeTempPath);

        try
        {
            using (Process lmms = new Process())
            {
                // Process invocation details and error handling omitted for brevity
                // ...one successfully rendered WAV, OGG, or MP3 file later...

                using (var request = UnityWebRequestMultimedia.GetAudioClip(new Uri(tempPath), audioFormat))
                {
                    var handler = request.downloadHandler as DownloadHandlerAudioClip;
                    handler.compressed = false;
                    handler.streamAudio = false;
                    request.timeout = LOAD_MEDIA_TIMEOUT;

                    var operation = request.SendWebRequest();

                    while (!(request.isHttpError || request.isNetworkError || handler.isDone)) ;
                    // Let the request finish, unless we get an error (possibly including a timeout)

                    var clip = DownloadHandlerAudioClip.GetContent(request);

                    clip.LoadAudioData();

                    var assetName = Path.GetFileNameWithoutExtension(assetPath);
                    var clone = AudioClip.Create("Clip", clip.samples, clip.channels, clip.frequency, false);

                    using (var so = new SerializedObject(clone))
                    {
                        var samples = new float[clip.samples * clip.channels];

                        clip.GetData(samples, 0);
                        clone.SetData(samples, 0);

                        // Everything above this line works fine

                        ctx.AddObjectToAsset("AudioClip", clone);
                        ctx.SetMainObject(clone);

                        so.ApplyModifiedProperties();

                        EditorUtility.SetDirty(clone);
                    }
                }
            }
        }
        catch (Exception e)
        {
            ctx.LogImportError($"Failed import with {e.GetType()}: {e.Message}");
        }
    }
    private const int LOAD_MEDIA_TIMEOUT = 5; // seconds
}

I'm using Unity 2019.1.7f1 Personal, on Ubuntu 19.04. Is this a bug, or am I doing something wrong?

\$\endgroup\$
1
\$\begingroup\$

It appears that this is a bug. I've reported this to Unity and they have reproduced it. The ticket can be found here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.