Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio not playing first time through. #3

Open
TechniPoet opened this issue Mar 19, 2016 · 11 comments
Open

Audio not playing first time through. #3

TechniPoet opened this issue Mar 19, 2016 · 11 comments

Comments

@TechniPoet
Copy link

So I'm running into this issue in both my project and the examples. The first time I hit play or load sample bank, no audio is produced but if I load and unload before hand, everything plays fine...

Any thoughts? I've been digging through the code and can't seem to figure out what's going on.

@TechniPoet
Copy link
Author

Issue turned out to be in GATSoundBank::LoadSampleFromResources.

When using Resources.Load to generate a clip, the clips loadType was "Loading" instead of loaded and so the sound data grabbed was empty.

@jackalborn-sean
Copy link

TechniPoet, I'm running into this problem, is there a correction to issue I can make to correct it?

@jackalborn-sean
Copy link

Nothing will play for me unless i Load before I play, I've been putting Debug.Logs around trying to figure out what's happening to data, it all seems to be loading into memory but the default player shows no activity unless i Load the Sample Bank before Play.

@gregzo
Copy link
Owner

gregzo commented Mar 29, 2016

Hey guys,

I'm really sorry I can't help much here. As I mentioned elsewhere, I can't maintain G-Audio anymore: my current full time job does not use Unity, and 2 small kids tend to eat up any free time that's left ( great feeling by the way ).

I'd say you should make sure that the allocator is properly initilaized ( GATDataAllocator ), and that sample banks are loaded ( GATSampleBank and friends, which work with GATSoundBank ).

The whole editor audio thing was super shabby in Unity 4. I had a pretty rough time with it...

Important question: does it work the first time around in builds?

Another tip: add the GATDebug flag to get more info in the console.

I really loved working on this project. It's heart-breaking to have abandoned it, but heart warming to see it's being watched and used!

Finally. I just had news that Mini Metro won the IGF Award for Excellence in Audio and guess what? It uses G-Audio, albeit a heavily modified version. I'd say it's be worth a shot to get them to make their branch public if it isn't already!

@gregzo
Copy link
Owner

gregzo commented Mar 29, 2016

About that debug flag: GAT_DEBUG should be added to the define symbols

@jackalborn-sean
Copy link

Thank you gregzo, really appreciate you making the project public and for the direction. With that I will hopefully find the solution to what seems now to be a Unity5.3 issue.

Answer: I haven't had it working even the first time around in builds.

I really enjoy working with it and I'm glad others are too. :)

@jackalborn-sean
Copy link

I'm truly not seeing anything not working properly or not loading with all my debugging. Everything happens the same but audio only plays if I hit Load in the editor before I hit play. Hope TechniPoet has a lead on a solution, best I can think is rolling my projects back to 5.2 where everything still works.

@TechniPoet
Copy link
Author

I just saw these messages, sorry for the late response.

@gregzo Thanks for responding and for providing opening this project to be open source. Also congratulations on the Mini Metro news!

@jackalborn-sean I did indeed solve this issue. My fix is patch work but works for my purposes at the moment though in the next month or so I will probably clean it up for a pull request when I find some free time.

I'll post the code changes in the morning but if you are awake and eager, the quick trace explanation for finding the source is to go into the LoadAll() -> soundBank load call -> load clip I think -> loadFromResources -> here it loads the sound into a clip. The sound data is taken from the clip before it is fully loaded and unloaded if your application is playing. Because the data isn't loaded, you don't get any sound but the next time you load from resources the data is actually loaded, so we then have sound on the second attempt.

I pretty much changed several of those functions into coroutines so that data isn't read from the clips before they are done being loaded and the sound bank doesn't return data to the sample bank until all the sounds are loaded.

Better grammar, explanation, and code tomorrow when I'm less sleep deprived :)

@TechniPoet
Copy link
Author

OK, Here is what I did to fix the problem, it is VERY patchwork to get it working.

I use an empty singleton class called CoroutineMaster which is basically empty but allows me to bundle specific coroutines together.

In GATSampleBank

add

public delegate void LoadDone();
public LoadDone LoadFinished;

Replace LoadAll() with

/// <summary>
/// Loads all samples from the referenced SoundBank.
/// Sync operation
/// </summary>
public virtual void LoadAll()
{
        if( _soundBank == null )
    {
        return;
    }

    if( _allSamples == null )
    {
        InitCollections();
    }
    StopAllCoroutines();
    UnitySingleton<CoroutineMaster>.Instance.StopAllCoroutines();
    _soundBank.loadFinished += LoadNewSamples;
    StartCoroutine(_soundBank.LoadAll( _allocationMode ));
}

Add this function

void LoadNewSamples(Dictionary<string, GATData> loadedSamples)
{
    foreach (KeyValuePair<string, GATData> pair in loadedSamples)
    {
        AddSample(pair.Value, pair.Key);
    }
    _soundBank.loadFinished -= LoadNewSamples;
    _allKeys = null;
    if (LoadFinished != null)
    {
        LoadFinished();
    }
}

GATSoundBank

Add

public delegate void Finished(Dictionary<string, GATData> dict);
public Finished loadFinished;
int clipsLoaded = 0;

Change LoadAll() to

public IEnumerator LoadAll( GATDataAllocationMode allocationMode )
{
    clipsLoaded = 0;
    Dictionary< string, GATData > target = new Dictionary<string, GATData>( _sampleInfos.Count );
    int i;
    for( i = 0; i < _sampleInfos.Count; i++ )
    {
        LoadSample( _sampleInfos[ i ], target, allocationMode );
    }
    while (clipsLoaded != _sampleInfos.Count)
    {
        yield return null;
    }
    loadFinished(target);
}

In LoadSample()

LoadSampleFromResources(allocationMode, info, target) becomes UnitySingleton<CoroutineMaster>.Instance.StartCoroutine(LoadSampleFromResources(allocationMode, info, target));

LoadSampleFromResources

I commented a bunch of stuff out when searching for the error, sorry for gross commented out stuff

IEnumerator LoadSampleFromResources( GATDataAllocationMode mode, GATSampleInfo info, Dictionary< string, GATData > loadedSamples )
{
    AudioClip clip;
    /*
    #if UNITY_EDITOR
    if( Application.isPlaying ) //GZComment: simplifies memory management when trying things out in the editor, where performance is not crucial.
    {
        clip = Resources.Load( info.PathInResources ) as AudioClip;
        if( clip == null )
        {
            Debug.LogError( "No Clip at path: " + info.PathInResources);
        }
    }
    else
    {
        mode = GATDataAllocationMode.Unmanaged;
        string assetPath = AssetDatabase.GUIDToAssetPath( info.GUID );
        clip = AssetDatabase.LoadAssetAtPath( assetPath, typeof( AudioClip ) ) as AudioClip;
    }

    #else
    */
    clip = Resources.Load( info.PathInResources ) as AudioClip;
    //#endif

    while (clip.loadState != AudioDataLoadState.Loaded)
    {
        yield return null;
    }
    if( info.NumChannels == 1 )
    {
        GATData data;
        data = clip.ToGATData( mode );
        loadedSamples.Add( info.Name, data );
    }
    else
    {
        GATData[] channelsData = clip.ExtractChannels( mode );
        for( int i = 0; i < info.NumChannels; i++ )
        {
            loadedSamples.Add( string.Format( "{0}_{1}", info.Name, i ), channelsData[i] );
            //Debug.Log("loaded " + string.Format("{0}_{1}", info.Name, i));
        }
    }
    clipsLoaded++;


    #if UNITY_EDITOR
    if( Application.isPlaying )
    {
        Resources.UnloadAsset( ( Object )clip );
    }
    #else

    Resources.UnloadAsset( clip );
    #endif
}

Final notes

Once again I know this is bad but it works and I'm a working student with 4 projects currently so if it compiles I'm happy.
Basically make sure that you don't do anything until GATSampleBank invokes the LoadFinished() event.

Hope this is helpful because it took me HOURS of tearing through this entire codebase. Also I currently am using Active Sample Bank and am not using the allocator so once I start caring about memory, this will probably fall by the wayside.

@TechniPoet
Copy link
Author

@gregzo Any additional un-official documentation, examples, or literally anything else pertaining to this project would be super useful. I will very likely be using and modding this asset for months to come so any help is welcome help. Thanks!

@jackalborn-sean
Copy link

@TechniPoet Thank you so much for posting all that. I will get another chance to work with it tonight and I'll kick back anything I discover. I too had been digging through the codebase for some time so thanks again. I'll be using GAudio for my next few projects so I'll gladly try to contribute anything I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants