Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Save audio clip created after converting mp3 file by NAudio

Discussion in 'Audio & Video' started by slowDrag0n, Jun 8, 2020.

  1. slowDrag0n

    slowDrag0n

    Joined:
    Oct 10, 2017
    Posts:
    41
    Im using this script's
    FromMp3Data
    function to convert mp3 file that i take from streaming assets to wav and creating audio clip from it which i then play from my audiosource component.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.IO;
    3. using System;
    4. using NAudio;
    5. using NAudio.Wave;
    6.  
    7. public static class NAudioPlayer
    8. {
    9.     public static AudioClip FromMp3Data(byte[] data)
    10.     {
    11.         // Load the data into a stream
    12.         MemoryStream mp3stream = new MemoryStream(data);
    13.         // Convert the data in the stream to WAV format
    14.         Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);
    15.         WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(mp3audio);
    16.         // Convert to WAV data
    17.         WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
    18.  
    19.         AudioClip audioClip;
    20.         if (wav.ChannelCount == 2)
    21.         {
    22.             audioClip = AudioClip.Create("Audio File Name", wav.SampleCount, 2, wav.Frequency, false);
    23.             audioClip.SetData(wav.StereoChannel, 0);
    24.         }
    25.         else
    26.         {
    27.             audioClip = AudioClip.Create("Audio File Name", wav.SampleCount, 1, wav.Frequency, false);
    28.             audioClip.SetData(wav.LeftChannel, 0);
    29.         }
    30.         // Now return the clip
    31.         return audioClip;
    32.     }
    33.  
    34.     private static MemoryStream AudioMemStream(WaveStream waveStream)
    35.     {
    36.         MemoryStream outputStream = new MemoryStream();
    37.         using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
    38.         {
    39.             byte[] bytes = new byte[waveStream.Length];
    40.             waveStream.Position = 0;
    41.             waveStream.Read(bytes, 0, Convert.ToInt32(waveStream.Length));
    42.             waveFileWriter.Write(bytes, 0, bytes.Length);
    43.             waveFileWriter.Flush();
    44.         }
    45.         return outputStream;
    46.     }
    47. }
    48.  
    49. /* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
    50. public class WAV
    51. {
    52.  
    53.     // convert two bytes to one float in the range -1 to 1
    54.     static float bytesToFloat(byte firstByte, byte secondByte)
    55.     {
    56.         // convert two bytes to one short (little endian)
    57.         short s = (short)((secondByte << 8) | firstByte);
    58.         // convert to range from -1 to (just below) 1
    59.         return s / 32768.0F;
    60.     }
    61.  
    62.     static int bytesToInt(byte[] bytes, int offset = 0)
    63.     {
    64.         int value = 0;
    65.         for (int i = 0; i < 4; i++)
    66.         {
    67.             value |= ((int)bytes[offset + i]) << (i * 8);
    68.         }
    69.         return value;
    70.     }
    71.     // properties
    72.     public float[] LeftChannel { get; internal set; }
    73.     public float[] RightChannel { get; internal set; }
    74.     public float[] StereoChannel { get; internal set; }
    75.     public int ChannelCount { get; internal set; }
    76.     public int SampleCount { get; internal set; }
    77.     public int Frequency { get; internal set; }
    78.  
    79.     public WAV(byte[] wav)
    80.     {
    81.  
    82.         // Determine if mono or stereo
    83.         ChannelCount = wav[22];     // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels
    84.  
    85.         // Get the frequency
    86.         Frequency = bytesToInt(wav, 24);
    87.  
    88.         // Get past all the other sub chunks to get to the data subchunk:
    89.         int pos = 12;   // First Subchunk ID from 12 to 16
    90.  
    91.         // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))
    92.         while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97))
    93.         {
    94.             pos += 4;
    95.             int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
    96.             pos += 4 + chunkSize;
    97.         }
    98.         pos += 8;
    99.  
    100.         // Pos is now positioned to start of actual sound data.
    101.         SampleCount = (wav.Length - pos) / 2;     // 2 bytes per sample (16 bit sound mono)
    102.         if (ChannelCount == 2) SampleCount /= 2;        // 4 bytes per sample (16 bit stereo)
    103.  
    104.         // Allocate memory (right will be null if only mono sound)
    105.         LeftChannel = new float[SampleCount];
    106.         if (ChannelCount == 2) RightChannel = new float[SampleCount];
    107.         else RightChannel = null;
    108.  
    109.         // Write to double array/s:
    110.         int i = 0;
    111.         while (pos < wav.Length)
    112.         {
    113.             LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
    114.             pos += 2;
    115.             if (ChannelCount == 2)
    116.             {
    117.                 RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
    118.                 pos += 2;
    119.             }
    120.             i++;
    121.         }
    122.  
    123.         //Merge left and right channels for stereo sound
    124.         if (ChannelCount == 2)
    125.         {
    126.             StereoChannel = new float[SampleCount * 2];
    127.             //Current position in our left and right channels
    128.             int channelPos = 0;
    129.             //After we've changed two values for our Stereochannel, we want to increase our channelPos
    130.             short posChange = 0;
    131.  
    132.             for (int index = 0; index < (SampleCount * 2); index++)
    133.             {
    134.  
    135.                 if (index % 2 == 0)
    136.                 {
    137.                     StereoChannel[index] = LeftChannel[channelPos];
    138.                     posChange++;
    139.                 }
    140.                 else
    141.                 {
    142.                     StereoChannel[index] = RightChannel[channelPos];
    143.                     posChange++;
    144.                 }
    145.                 //Two values have been changed, so update our channelPos
    146.                 if (posChange % 2 == 0)
    147.                 {
    148.                     if (channelPos < SampleCount)
    149.                     {
    150.                         channelPos++;
    151.                         //Reset the counter for next iterations
    152.                         posChange = 0;
    153.                     }
    154.                 }
    155.             }
    156.         }
    157.         else
    158.         {
    159.             StereoChannel = null;
    160.         }
    161.     }
    162.  
    163.     public override string ToString()
    164.     {
    165.         return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel, RightChannel, ChannelCount, SampleCount, Frequency);
    166.     }
    167. }
    The problem is that it just returns the audioclip without saving it and keeps the file in memory as long as game is running. As stop the game, the RAM drops back to its previous level before the conversion process.

    What i'd like to do is save the generated audio clip as file (in streaming assets or persistent data path) so that i can use it later without having to convert it again and free up the memory after it is saved.

    Any pointers towards achieving this is much appreciated.
     
  2. DDAAACCC

    DDAAACCC

    Joined:
    Jul 8, 2020
    Posts:
    9
    i have to do that i
     
  3. jordanjc280

    jordanjc280

    Joined:
    Jul 30, 2022
    Posts:
    3
    i know this is an old post but did you ever find a solution?
     
  4. maguslin

    maguslin

    Joined:
    Mar 9, 2015
    Posts:
    9
    u can use savewav.cs,make audio easy to save and reload again