void Awake()
    {
        m_TuneOpen                = new TinyFileDialogs.OpenFileDialog( );
        m_TuneOpen.title          = "Open tune";
        m_TuneOpen.filterPatterns = fileFilters;
        m_TuneOpen.description    = filterDescription;
        m_TuneOpen.defaultPath    = UnityEngine.Application.dataPath;

        m_SampleOpen                = new TinyFileDialogs.OpenFileDialog( );
        m_SampleOpen.title          = "Load sample";
        m_SampleOpen.filterPatterns = new string [] { "*.wav" };
        m_SampleOpen.description    = "Wave-file (8-bit sample depth)";
        m_SampleOpen.defaultPath    = UnityEngine.Application.dataPath;

        m_TuneSave                = new TinyFileDialogs.SaveFileDialog( );
        m_TuneSave.title          = "Save tune";
        m_TuneSave.filterPatterns = fileFilters;
        m_TuneOpen.description    = filterDescription;
        m_TuneOpen.defaultPath    = UnityEngine.Application.dataPath;

        m_WavSave                = new TinyFileDialogs.SaveFileDialog( );
        m_WavSave.title          = "Save WAVE";
        m_WavSave.filterPatterns = new string [] { "*.wav" };
        m_WavSave.description    = "WAVE-file(s)";
        m_WavSave.defaultPath    = UnityEngine.Application.dataPath;

        m_VgmSave                = new TinyFileDialogs.SaveFileDialog( );
        m_VgmSave.title          = "Save VGM";
        m_VgmSave.filterPatterns = new string [] { "*.vgz", "*.vgm" };
        m_VgmSave.description    = "VGM-file(s)";
        m_VgmSave.defaultPath    = UnityEngine.Application.dataPath;
    }
    IEnumerator SaveVGMRoutine(TinyFileDialogs.SaveFileDialog sfd)
    {
        playback.Stop( );
        playback.psg.audioSource.enabled = false;
        playback.follow       = false;
        data.currentPattern   = 0;
        m_OperationInProgress = true;

        bool   isCompressed = sfd.filePath.Contains(".vgz");
        Stream fileStream   = isCompressed ? new MemoryStream( ) : sfd.OpenFile( );

        BinaryWriter bw = new BinaryWriter(fileStream);

        bw.Write(Encoding.ASCII.GetBytes("Vgm "));      //0x00
                                                        //wrote eof offset later when we know 0x04
        bw.Seek(0x08, SeekOrigin.Begin);
        bw.Write(( uint )0x00000170);                   //0x08
        bw.Write(( uint )playback.psg.chip.clock);      //0x0C
                                                        //gd3???? 0x14
                                                        //write wait values later when we know 0x18
                                                        //implement loop offset some rainy day 0x1C + 0x20
        bw.Seek(0x24, SeekOrigin.Begin);
        bw.Write(( uint )playback.playbackRate);        //0x24
        bw.Write(( ushort )SN76489.NOISE_TAPPED);       //0x28
        bw.Write(( byte )(SN76489.NOISE_SR_WIDTH + 1)); //0x2A
        bw.Write(( byte )0x00);

        bw.Seek(0x34, SeekOrigin.Begin);
        bw.Write(( uint )0x0C);

        bw.Seek(0x40, SeekOrigin.Begin);

        List <PSGWrapper.RegisterWrite> dataSamples = playback.psg.RecordRegisters( );

        playback.Play(false);
        int c = 0;

        while (playback.isPlaying)
        {
            playback.psg.ManualClock( );

            m_Progress = playback.songProgress * 50;

            c++;
            if (c > 44100)
            {
                c = 0;
                yield return(null);
            }
        }
        playback.psg.RecordRegisters(false);
        playback.psg.ResetChip( );

        int  loopWaitAmount = 0;
        int  waitAmount     = 0;
        int  loopOffset     = 0x40;
        int  bytesWritten   = 0;
        bool foundLoop      = false;

        for (int i = 0; i < dataSamples.Count; i++)
        {
            if (dataSamples [i].wait > 0)
            {
                switch (dataSamples [i].wait)
                {
                case 735:
                    bw.Write(( byte )VGMCommands.Wait735);
                    bytesWritten++;
                    break;

                case 882:
                    bw.Write(( byte )VGMCommands.Wait882);
                    bytesWritten++;
                    break;

                default:
                    int totalWait = dataSamples [i].wait;
                    do
                    {
                        bw.Write(( byte )VGMCommands.WaitSamples);
                        bw.Write(( ushort )System.Math.Min(65535, totalWait));
                        totalWait    -= 65535;
                        bytesWritten += 3;
                    } while (totalWait > 65535);
                    break;
                }

                if (dataSamples [i].pattern >= playback.patternLoop)
                {
                    loopWaitAmount += dataSamples [i].wait;
                }
                waitAmount += dataSamples [i].wait;

                c++;
                if (c > 44100)
                {
                    c = 0;
                    yield return(null);
                }

                m_Progress = 50 + (( float )i / dataSamples.Count) * 50;
            }

            bw.Write(( byte )dataSamples [i].command);
            bytesWritten++;
            if (dataSamples [i].command != VGMCommands.EOF)
            {
                bw.Write(( byte )dataSamples [i].data);
                bytesWritten++;
            }

            if (dataSamples [i].pattern == playback.patternLoop && i == 0)
            {
                foundLoop = true;
            }
            if (!foundLoop && dataSamples [i].pattern == playback.patternLoop)
            {
                loopOffset += bytesWritten;
                foundLoop   = true;
            }
        }

        //bw.Write((byte)0x66);

        int gd3Offset = ( int )bw.BaseStream.Position - 0x14;

        bw.Write(Encoding.ASCII.GetBytes("Gd3 "));
        bw.Write(( uint )0x00010000);
        int sizeOffset = ( int )bw.BaseStream.Position;

        bw.Write(( uint )0);
        bw.Write(Encoding.Unicode.GetBytes(SongData.songName + "\0"));                               //track name
        bw.Write(Encoding.Unicode.GetBytes("\0"));
        bw.Write(Encoding.Unicode.GetBytes("\0"));                                                   //game name
        bw.Write(Encoding.Unicode.GetBytes("\0"));
        bw.Write(Encoding.Unicode.GetBytes("Sega Game Gear\0"));                                     //system name
        bw.Write(Encoding.Unicode.GetBytes("\0"));
        bw.Write(Encoding.Unicode.GetBytes(SongData.artistName + "\0"));                             //artist name
        bw.Write(Encoding.Unicode.GetBytes("\0"));
        bw.Write(Encoding.Unicode.GetBytes(System.DateTime.Today.ToString(@"yyyy\/MM\/dd") + "\0")); //release date
        bw.Write(Encoding.Unicode.GetBytes("SnoozeTracker\0"));                                      //converter
        bw.Write(Encoding.Unicode.GetBytes("https://github.com/tEFFx/SnoozeTracker\0"));             //notes

        int eofOffset = ( int )bw.BaseStream.Position - 0x04;

        bw.Seek(sizeOffset, SeekOrigin.Begin);
        bw.Write(( uint )(eofOffset - sizeOffset));

        bw.Seek(0x04, SeekOrigin.Begin);
        bw.Write(( uint )(eofOffset));

        bw.Seek(0x14, SeekOrigin.Begin);
        bw.Write(( uint )(gd3Offset));

        bw.Seek(0x18, SeekOrigin.Begin);
        bw.Write(( uint )waitAmount);

        if (playback.patternLoop != 0)
        {
            bw.Write(( uint )(loopOffset - 0x1C));
            bw.Write(( uint )(loopWaitAmount));
        }

        if (isCompressed)
        {
            Stream     fs         = sfd.OpenFile( );
            GZipStream gzipStream = new GZipStream(fs, CompressionMode.Compress, CompressionLevel.BestCompression, true);
            byte []    buffer     = new byte [fileStream.Length];
            fileStream.Position = 0;
            fileStream.Read(buffer, 0, ( int )fileStream.Length);
            gzipStream.Write(buffer, 0, ( int )fileStream.Length);
            gzipStream.Close( );
        }

        bw.Close( );

        playback.psg.audioSource.enabled = true;
        playback.psg.enabled             = false;
        playback.psg.enabled             = true;
        playback.follow       = true;
        m_OperationInProgress = false;
        playback.Stop( );
    }