コード例 #1
0
        public WaveGenerator(List <Note> notes, float volume)
        {
            // Init chunks
            header = new WaveHeader();
            format = new WaveFormatChunk();
            data   = new WaveDataChunk();

            var  milliseconds = notes.Select((x) => x.Duration.TotalMilliseconds).Sum();
            uint numSamples   = (uint)(((format.dwSamplesPerSec * milliseconds) / 1000));
            int  amplitude    = 32760; // Max amplitude for 16-bit audio
            uint sampleCount  = 0;     // used as a "cursor" in the next Foreach

            // Initialize the 16-bit array and Calculate the repsective values
            data.shortArray = new short[numSamples];
            foreach (var n in notes)
            {
                // the time-steps the sine wave takes (period [2 pi f]) divided by the steps per period
                double t = (Math.PI * 2 * n.Frequency) / format.dwSamplesPerSec;

                // Calculate the amount of samples you will use for said Note
                var samplesThisNote = format.dwSamplesPerSec * n.Duration.TotalSeconds;

                // Loop over sampleCount as said before (it acts as u cursor)
                for (uint i = sampleCount; i < (samplesThisNote + sampleCount) - 1; i++)
                {
                    data.shortArray[i] = Convert.ToInt16(amplitude * Math.Sin(t * i) * volume);
                }
                sampleCount += (uint)samplesThisNote;
            }

            // Calculate data chunk size in bytes
            data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
        }
コード例 #2
0
        public fileSaver(WaveHeader header, WaveFormatChunk format, WaveDataChunk data, string filePath)
        {
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                using (var writer = new BinaryWriter(fileStream))
                {
                    // Write the header
                    writer.Write(header.sGroupID.ToCharArray());
                    writer.Write(header.dwFileLength);
                    writer.Write(header.sRiffType.ToCharArray());

                    // Write the format chunk
                    writer.Write(format.sChunkID.ToCharArray());
                    writer.Write(format.dwChunkSize);
                    writer.Write(format.wFormatTag);
                    writer.Write(format.wChannels);
                    writer.Write(format.dwSamplesPerSec);
                    writer.Write(format.dwAvgBytesPerSec);
                    writer.Write(format.wBlockAlign);
                    writer.Write(format.wBitsPerSample);

                    // Write the data chunk
                    writer.Write(data.sChunkID.ToCharArray());
                    writer.Write(data.dwChunkSize);
                    foreach (short dataPoint in data.shortArray)
                    {
                        writer.Write(dataPoint);
                    }

                    // Jump back to Header.FileLength and calculate the TOTAL filesize
                    writer.Seek(4, SeekOrigin.Begin);
                    writer.Write((uint)writer.BaseStream.Length - 8); // Header parts are ignore (-8)
                }
            }
        }
コード例 #3
0
	public void Write (float[] clipData, WaveFormatChunk format, FileStream stream)
	{
		WaveHeader header = new WaveHeader ();
		WaveDataChunk data = new WaveDataChunk ();
		
		data.shortArray = new short[clipData.Length];
		for (int i = 0; i < clipData.Length; i++)
			data.shortArray [i] = (short)(clipData [i] * 32767);
		
		data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
		
		BinaryWriter writer = new BinaryWriter (stream);
		writer.Write (header.sGroupID.ToCharArray ());
		writer.Write (header.dwFileLength);
		writer.Write (header.sRiffType.ToCharArray ());
		writer.Write (format.sChunkID.ToCharArray ());
		writer.Write (format.dwChunkSize);
		writer.Write (format.wFormatTag);
		writer.Write (format.wChannels);
		writer.Write (format.dwSamplesPerSec);
		writer.Write (format.dwAvgBytesPerSec);
		writer.Write (format.wBlockAlign);
		writer.Write (format.wBitsPerSample);
		writer.Write (data.sChunkID.ToCharArray ());
		writer.Write (data.dwChunkSize);
		foreach (short dataPoint in data.shortArray) {
			writer.Write (dataPoint);
		}
		writer.Seek (4, SeekOrigin.Begin);
		uint filesize = (uint)writer.BaseStream.Length;
		writer.Write (filesize - 8);
		writer.Close ();
	}
コード例 #4
0
    public SoundGenerator(List <SoundFragment> sound)
    {
        header = new WaveHeader();
        format = new WaveFormatChunk();
        data   = new WaveDataChunk();

        int numberOfSamples = sound.Sum(x => (int)(format.dwSamplesPerSec * format.wChannels * x.Duration));

        data.shortArray = new short[numberOfSamples];

        int amplitude = 32760;
        int counter   = 0;

        foreach (SoundFragment fragment in sound)
        {
            double t = (Math.PI * 2 * fragment.Frequency) / (format.dwSamplesPerSec * format.wChannels);
            uint   sampleCountForFragment = (uint)(format.dwSamplesPerSec * format.wChannels * fragment.Duration);
            for (uint i = 0; i < sampleCountForFragment - 1; i++)
            {
                for (int channel = 0; channel < format.wChannels; channel++)
                {
                    data.shortArray[counter + channel] = Convert.ToInt16(amplitude * Math.Sin(t * i));
                }

                counter++;
            }
        }

        data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
    }
コード例 #5
0
    double freq   = 220.0f; // Concert A: 440Hz

    public WaveGenerator()
    {
        // Init chunks
        header = new WaveHeader();
        format = new WaveFormatChunk();
        data   = new WaveDataChunk();
    }
コード例 #6
0
ファイル: WaveFile.cs プロジェクト: uotools/JuicyUO
        private long m_PcmDataOffset; // offset of 'pcm_data' in output file

        /// <summary>
        ///     Constructs a new WaveFile instance.
        /// </summary>
        public WaveFile()
        {
            m_PcmData        = new RiffChunkHeader(this);
            m_WaveFormat     = new WaveFormatChunk(this);
            m_PcmData.CkId   = FourCC("data");
            m_PcmData.CkSize = 0;
            m_NumSamples     = 0;
        }
コード例 #7
0
        private long _PcmDataOffset; // offset of 'pc_data' in output file

        /// <summary>
        /// Creates a new WaveFile instance.
        /// </summary>
        internal WaveFile()
        {
            _PcmData        = new RiffChunkHeader(this);
            _WaveFormat     = new WaveFormatChunk(this);
            _PcmData.CkId   = FourCC("data");
            _PcmData.CkSize = 0;
            _NumSamples     = 0;
        }
コード例 #8
0
ファイル: WaveFile.cs プロジェクト: jorsi/UltimaXNA
        private long m_PcmDataOffset; // offset of 'pcm_data' in output file

        #endregion Fields

        #region Constructors

        /// <summary>
        ///     Constructs a new WaveFile instance.
        /// </summary>
        public WaveFile()
        {
            m_PcmData = new RiffChunkHeader(this);
            m_WaveFormat = new WaveFormatChunk(this);
            m_PcmData.CkId = FourCC("data");
            m_PcmData.CkSize = 0;
            m_NumSamples = 0;
        }
コード例 #9
0
        /// <summary>
        /// Write the stored audio data as a WAVE file.
        /// </summary>
        public void SaveAsWav(string filePath)
        {
            // Make sure we have data.
            if (String.IsNullOrEmpty(_tempfile))
            {
                _cbWritten = 0;
                return;
            }
            if (!File.Exists(_tempfile))
            {
                _tempfile  = null;
                _cbWritten = 0;
                return;
            }
            if (_cbWritten == 0)
            {
                File.Delete(_tempfile);
                _tempfile = null;
                return;
            }
            FileInfo fi = new FileInfo(_tempfile);

            Debug.Assert(fi.Length == _cbWritten);
            WaveFileWriter writer = new WaveFileWriter(filePath);

            writer.WriteFileHeader((int)fi.Length);
            WaveFormatChunk format = new WaveFormatChunk();

            format.chunkId       = "fmt ";
            format.chunkSize     = 16;                                  // size of the struct in bytes - 8
            format.audioFormat   = WAV_FMT_PCM;
            format.channelCount  = _channelCount;
            format.sampleRate    = _sampleRate;
            format.byteRate      = (uint)(_sampleRate * _channelCount * _bitsPerFrame / 8);
            format.blockAlign    = (ushort)(_channelCount * _bitsPerFrame / 8);
            format.bitsPerSample = _bitsPerFrame;
            writer.WriteFormatChunk(format);
            writer.WriteDataHeader((int)fi.Length);
            byte[] data = File.ReadAllBytes(_tempfile);
            Debug.Assert(data.Length == _cbWritten);
            writer.WriteData(data);
            writer.Close();
            // Clean up the temporary data from the recording process.
            File.Delete(_tempfile);
            _tempfile  = null;
            _cbWritten = 0;
        }
コード例 #10
0
 /// <summary>
 /// Writes the WAVE format block.
 /// </summary>
 public void WriteFormatChunk(WaveFormatChunk format)
 {
     if (_writer == null)
     {
         return;
     }
     _writer.Write((byte)'f');
     _writer.Write((byte)'m');
     _writer.Write((byte)'t');
     _writer.Write((byte)' ');
     _writer.Write(format.chunkSize);
     _writer.Write(format.audioFormat);
     _writer.Write(format.channelCount);
     _writer.Write(format.sampleRate);
     _writer.Write(format.byteRate);
     _writer.Write(format.blockAlign);
     _writer.Write(format.bitsPerSample);
 }
コード例 #11
0
        public WaveGenerator(WaveExampleType type)
        {
            // Init chunks
            header = new WaveHeader();
            format = new WaveFormatChunk();
            data = new WaveDataChunk();

            // Fill the data array with sample data
            switch (type)
            {
                case WaveExampleType.ExampleSineWave:

                    // Number of samples = sample rate * channels * bytes per sample
                    uint numSamples = format.dwSamplesPerSec * format.wChannels;

                    // Initialize the 16-bit array
                    data.shortArray = new short[numSamples];

                    int amplitude = 32760;  // Max amplitude for 16-bit audio
                    double freq = 440.0f;   // Concert A: 440Hz

                    // The "angle" used in the function, adjusted for the number of channels and sample rate.
                    // This value is like the period of the wave.
                    double t = (Math.PI * 2 * freq) / (format.dwSamplesPerSec * format.wChannels);

                    for (uint i = 0; i < numSamples - 1; i++)
                    {
                        // Fill with a simple sine wave at max amplitude
                        for (int channel = 0; channel < format.wChannels; channel++)
                        {
                            data.shortArray[i + channel] = Convert.ToInt16(amplitude * Math.Sin(t * i));
                        }
                    }

                    // Calculate data chunk size in bytes
                    data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));

                    break;
            }
        }
コード例 #12
0
    public void Write(float[] clipData, WaveFormatChunk format, FileStream stream)
    {
        WaveHeader    header = new WaveHeader();
        WaveDataChunk data   = new WaveDataChunk();

        data.shortArray = new short[clipData.Length];
        for (int i = 0; i < clipData.Length; i++)
        {
            data.shortArray [i] = (short)(clipData [i] * 32767);
        }

        data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));

        BinaryWriter writer = new BinaryWriter(stream);

        writer.Write(header.sGroupID.ToCharArray());
        writer.Write(header.dwFileLength);
        writer.Write(header.sRiffType.ToCharArray());
        writer.Write(format.sChunkID.ToCharArray());
        writer.Write(format.dwChunkSize);
        writer.Write(format.wFormatTag);
        writer.Write(format.wChannels);
        writer.Write(format.dwSamplesPerSec);
        writer.Write(format.dwAvgBytesPerSec);
        writer.Write(format.wBlockAlign);
        writer.Write(format.wBitsPerSample);
        writer.Write(data.sChunkID.ToCharArray());
        writer.Write(data.dwChunkSize);
        foreach (short dataPoint in data.shortArray)
        {
            writer.Write(dataPoint);
        }
        writer.Seek(4, SeekOrigin.Begin);
        uint filesize = (uint)writer.BaseStream.Length;

        writer.Write(filesize - 8);
        writer.Close();
    }
コード例 #13
0
            public WaveGenerator(List <short> Data)
            {
                header = new WaveHeader();
                format = new WaveFormatChunk();
                data   = new WaveDataChunk();

                int numSamples = Data.Count;

                data.shortArray = new short[numSamples];

                for (int i = 0; i < numSamples; i++)
                {
                    data.shortArray[i] = Data[i];
                }

                data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
                TimeSpan TS = new TimeSpan(0, 0, (int)((float)numSamples / (float)format.dwSamplesPerSec));

                if (Verbose)
                {
                    Console.WriteLine("");
                }
                Console.WriteLine("wave generated: {0} seconds: {1}", (float)numSamples / (float)format.dwSamplesPerSec, TS.ToString());
            }
コード例 #14
0
ファイル: WaveFile.cs プロジェクト: avs009/gsf
 public WaveFile(int sampleRate, short bitsPerSample, short channels, ushort audioFormat)
 {
     m_waveHeader = new RiffHeaderChunk("WAVE");
     m_waveFormat = new WaveFormatChunk(sampleRate, bitsPerSample, channels, audioFormat);
     m_waveData = new WaveDataChunk(m_waveFormat);
 }
コード例 #15
0
ファイル: WaveFile.cs プロジェクト: avs009/gsf
 public WaveFile(RiffHeaderChunk waveHeader, WaveFormatChunk waveFormat, WaveDataChunk waveData)
 {
     m_waveHeader = waveHeader;
     m_waveFormat = waveFormat;
     m_waveData = waveData;
 }
コード例 #16
0
ファイル: WaveFile.cs プロジェクト: avs009/gsf
        /// <summary>
        /// Creates a new in-memory wave loaded from an existing wave audio stream.
        /// </summary>
        /// <param name="source">Stream of WAV formatted audio data to load.</param>
        /// <returns>In-memory representation of wave file.</returns>
        public static WaveFile Load(Stream source)
        {
            RiffChunk riffChunk;
            RiffHeaderChunk waveHeader = null;
            WaveFormatChunk waveFormat = null;
            WaveDataChunk waveData = null;

            while (waveData == null)
            {
                riffChunk = RiffChunk.ReadNext(source);

                switch (riffChunk.TypeID)
                {
                    case RiffHeaderChunk.RiffTypeID:
                        waveHeader = new RiffHeaderChunk(riffChunk, source, "WAVE");
                        break;
                    case WaveFormatChunk.RiffTypeID:
                        if (waveHeader == null)
                            throw new InvalidDataException("WAVE format section encountered before RIFF header, wave file corrupted");

                        waveFormat = new WaveFormatChunk(riffChunk, source);
                        break;
                    case WaveDataChunk.RiffTypeID:
                        if (waveFormat == null)
                            throw new InvalidDataException("WAVE data section encountered before format section, wave file corrupted");

                        waveData = new WaveDataChunk(riffChunk, source, waveFormat);
                        break;
                    default:
                        // Skip unidentified section
                        source.Seek(riffChunk.ChunkSize, SeekOrigin.Current);
                        break;
                }
            }

            return new WaveFile(waveHeader, waveFormat, waveData);
        }
コード例 #17
0
ファイル: WaveFile.cs プロジェクト: avs009/gsf
 /// <summary>
 /// Creates a new empty in-memory wave file using standard CD quality settings.
 /// </summary>
 public WaveFile()
 {
     m_waveHeader = new RiffHeaderChunk("WAVE");
     m_waveFormat = new WaveFormatChunk(44100, 16, 2, 0x1);
     m_waveData = new WaveDataChunk(m_waveFormat);
 }
コード例 #18
0
		/// <summary>
		/// Write the stored audio data as a WAVE file.
		/// </summary>
		public void SaveAsWav(string filePath)
		{
			// Make sure we have data.
			if (String.IsNullOrEmpty(_tempfile))
			{
				_cbWritten = 0;
				return;
			}
			if (!File.Exists(_tempfile))
			{
				_tempfile = null;
				_cbWritten = 0;
				return;
			}
			if (_cbWritten == 0)
			{
				File.Delete(_tempfile);
				_tempfile = null;
				return;
			}
			FileInfo fi = new FileInfo(_tempfile);
			Debug.Assert(fi.Length == _cbWritten);
			WaveFileWriter writer = new WaveFileWriter(filePath);
			writer.WriteFileHeader((int)fi.Length);
			WaveFormatChunk format = new WaveFormatChunk();
			format.chunkId = "fmt ";
			format.chunkSize = 16;				// size of the struct in bytes - 8
			format.audioFormat = WAV_FMT_PCM;
			format.channelCount = _channelCount;
			format.sampleRate = _sampleRate;
			format.byteRate = (uint)(_sampleRate * _channelCount * _bitsPerFrame / 8);
			format.blockAlign = (ushort)(_channelCount * _bitsPerFrame / 8);
			format.bitsPerSample = _bitsPerFrame;
			writer.WriteFormatChunk(format);
			writer.WriteDataHeader((int)fi.Length);
			byte[] data = File.ReadAllBytes(_tempfile);
			Debug.Assert(data.Length == _cbWritten);
			writer.WriteData(data);
			writer.Close();
			// Clean up the temporary data from the recording process.
			File.Delete(_tempfile);
			_tempfile = null;
			_cbWritten = 0;
		}
コード例 #19
0
			/// <summary>
			/// Writes the WAVE format block.
			/// </summary>
			public void WriteFormatChunk(WaveFormatChunk format)
			{
				if (_writer == null)
					return;
				_writer.Write((byte)'f');
				_writer.Write((byte)'m');
				_writer.Write((byte)'t');
				_writer.Write((byte)' ');
				_writer.Write(format.chunkSize);
				_writer.Write(format.audioFormat);
				_writer.Write(format.channelCount);
				_writer.Write(format.sampleRate);
				_writer.Write(format.byteRate);
				_writer.Write(format.blockAlign);
				_writer.Write(format.bitsPerSample);
			}
コード例 #20
0
ファイル: WaveFile.cs プロジェクト: rmc00/gsf
        /// <summary>
        /// Creates a new in-memory wave loaded from an existing wave audio stream.
        /// </summary>
        /// <param name="source">Stream of WAV formatted audio data to load.</param>
        /// <param name="loadData">Determines if wave data should be loaded into memory.</param>
        /// <returns>In-memory representation of wave file.</returns>
        public static WaveFile Load(Stream source, bool loadData = true)
        {
            RiffChunk riffChunk;
            RiffHeaderChunk waveHeader = null;
            WaveFormatChunk waveFormat = null;
            WaveDataChunk waveData = null;
            ListInfoChunk listInfo = null;

            while (source.Position < source.Length)
            {
                riffChunk = RiffChunk.ReadNext(source);

                switch (riffChunk.TypeID)
                {
                    case RiffHeaderChunk.RiffTypeID:
                        waveHeader = new RiffHeaderChunk(riffChunk, source, "WAVE");
                        break;
                    case WaveFormatChunk.RiffTypeID:
                        if ((object)waveHeader == null)
                            throw new InvalidDataException("WAVE format section encountered before RIFF header, wave file corrupted");

                        waveFormat = new WaveFormatChunk(riffChunk, source);
                        break;
                    case WaveDataChunk.RiffTypeID:
                        if ((object)waveFormat == null)
                            throw new InvalidDataException("WAVE data section encountered before format section, wave file corrupted");

                        if (loadData)
                        {
                            waveData = new WaveDataChunk(riffChunk, source, waveFormat);
                        }
                        else
                        {
                            source.Seek(riffChunk.ChunkSize, SeekOrigin.Current);
                            waveData = new WaveDataChunk(waveFormat);
                            waveData.ChunkSize = riffChunk.ChunkSize;
                        }
                        break;
                    case ListInfoChunk.RiffTypeID:
                        listInfo = new ListInfoChunk(riffChunk, source);
                        break;
                    default:
                        // Skip unidentified section
                        source.Seek(riffChunk.ChunkSize, SeekOrigin.Current);
                        break;
                }
            }

            return new WaveFile(waveHeader, waveFormat, waveData, listInfo);
        }
コード例 #21
0
ファイル: WaveFile.cs プロジェクト: avs009/gsf
        /// <summary>Creates a new in-memory wave loaded from an existing wave file.</summary>
        /// <param name="waveFileName">File name of WAV file to load.</param>
        /// <returns>In-memory representation of wave file.</returns>
        public static WaveFile Load(string waveFileName)
        {
            FileStream source = File.Open(waveFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            RiffChunk riffChunk;
            RiffHeaderChunk waveHeader = null;
            WaveFormatChunk waveFormat = null;
            WaveDataChunk waveData = null;

            while (waveData == null)
            {
                riffChunk = RiffChunk.ReadNext(source);

                switch (riffChunk.TypeID)
                {
                    case RiffHeaderChunk.RiffTypeID:
                        waveHeader = new RiffHeaderChunk(riffChunk, source, "WAVE");
                        break;
                    case WaveFormatChunk.RiffTypeID:
                        if (waveHeader == null)
                            throw new InvalidDataException("WAVE format section encountered before RIFF header, wave file corrupted.");

                        waveFormat = new WaveFormatChunk(riffChunk, source);
                        break;
                    case WaveDataChunk.RiffTypeID:
                        if (waveFormat == null)
                            throw new InvalidDataException("WAVE data section encountered before format section, wave file corrupted.");

                        waveData = new WaveDataChunk(riffChunk, source, waveFormat);
                        break;
                    default:
                        break;
                }
            }

            return new WaveFile(waveHeader, waveFormat, waveData);
        }
コード例 #22
0
    public WaveFormatChunk MakeFormat(AudioClip clip)
    {
        WaveFormatChunk format = new WaveFormatChunk(8000, 1);

        return(format);
    }
コード例 #23
0
    public WaveGenerator(WaveExampleType type, float frequency, float volume, float duration)
    {
        //Cap parameters
        if (frequency < 200)
        {
            frequency = 200;
        }
        else if (frequency > 2000)
        {
            frequency = 1200;
        }
        if (volume < 0f)
        {
            volume = 0f;
        }
        else if (volume > 1f)
        {
            volume = 1f;
        }
        if (duration < 0)
        {
            duration = 0f;
        }
        else if (duration > 2.5f)
        {
            duration = 1.0f;
        }

        // Init chunks
        header = new WaveHeader();
        format = new WaveFormatChunk();
        data   = new WaveDataChunk();

        // Fill the data array with sample data
        switch (type)
        {
        case WaveExampleType.Sine:

            // Number of samples = duration * sample rate * channels * bytes per sample
            uint numSamples = (uint)(duration * format.dwSamplesPerSec * format.wChannels);

            // Initialize the 16-bit array
            data.shortArray = new short[numSamples];

            float amplitude = volume * 32760;     // Max amplitude for 16-bit audio
            if (frequency == 0)
            {
                frequency = 440.0f;                       // Concert A: 440Hz
            }
            // The "angle" used in the function, adjusted for the number of channels and sample rate.
            // This value is like the period of the wave.
            double t = (Math.PI * 2 * frequency) / (format.dwSamplesPerSec * format.wChannels);

            for (uint i = 0; i < numSamples - 1; i++)
            {
                // Fill with a simple sine wave at max amplitude
                for (int channel = 0; channel < format.wChannels; channel++)
                {
                    data.shortArray[i + channel] = Convert.ToInt16(amplitude * Math.Sin(t * i));
                }
            }

            // Calculate data chunk size in bytes
            data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));

            break;
        } //switch
    }     //Constructor
コード例 #24
0
	public WaveFormatChunk MakeFormat (AudioClip clip)
	{
		WaveFormatChunk format = new WaveFormatChunk (8000, 1);
		return format;
	}
コード例 #25
0
ファイル: Program.cs プロジェクト: JamesDunne/clicker
        /// <summary>
        /// Main program.
        /// </summary>
        /// <param name="args"></param>
        private void Run(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine(
            @"{0} [options ...] <path to MIDI.mid>

            Description:
            Clicker generates a WAVE file click track given a MIDI sequence with meter/key
            and tempo change messages. The click track serves as a solid, sample-accurate
            metronome that will line up with the MIDI sequence. You can import the
            generated click track into any MIDI-friendly DAW tool such as SONAR, Cubase,
            etc. to record with. You can even share the click track with other recording
            artists working on your project to serve as a timebase to help synchronize work
            across distances.

            Author:     James S. Dunne http://bittwiddlers.org/
            Copyright:  2011, bittwiddlers.org
            Source:     http://github.com/JamesDunne/clicker

            Options:
            -s <samplerate>      Set the output WAVE file's sample rate in Hz
                         (default 48000 Hz)
            -c <channels>        Set the output WAVE file's number of channels
                         (1 or 2, default 2)
            -d <click division>  Set the metronome to click on each (2^N)th note,
                         scaling meter signatures appropriately to match.
                         (default: off, click on meter beats only)
            -ao                  Attenuate meter's off-beats if meter is faster
                         than the metronome. (default: off)
            -ad                  Attenuate inserted beats if metronome is clicking
                         faster than the meter. (default: off)
            <path to MIDI.mid>   Path to the MIDI arrangement to generate the click
                         track for.

            Outputs:
            <path to MIDI.mid>.click.wav
            ", Process.GetCurrentProcess().ProcessName);
                return;
            }

            bool early = false;
            Queue<string> aq = new Queue<string>(args);
            while (!early && (aq.Count > 0))
            {
                string arg = aq.Peek();

                switch (arg.ToLower())
                {
                    case "-s":
                        aq.Dequeue();
                        if (!Int32.TryParse(aq.Dequeue(), out samplesPerSec))
                            samplesPerSec = 48000;
                        break;
                    case "-c":
                        aq.Dequeue();
                        if (!Int32.TryParse(aq.Dequeue(), out channels))
                            channels = 1;
                        break;
                    case "-d":
                        aq.Dequeue();
                        if (Int32.TryParse(aq.Dequeue(), out clickOnDivision))
                            forceClickDivision = true;
                        break;
                    case "-ao":
                        aq.Dequeue();
                        attenuateProperOffBeats = true;
                        break;
                    case "-ad":
                        aq.Dequeue();
                        attenuateDividedBeats = true;
                        break;
                    default:
                        early = true;
                        break;
                }
            }

            if (aq.Count < 1)
            {
                Console.WriteLine("Expected path to MIDI sequence.");
                return;
            }

            FileInfo midiFile = new FileInfo(aq.Dequeue());
            if (!midiFile.Exists)
            {
                Console.WriteLine("Could not find path '{0}'.", midiFile.FullName);
                return;
            }

            // Load the MIDI sequence:
            Sequence seq = new Sequence(midiFile.FullName);

            // Load our clicks (stereo 16-bit clips):
            var asm = System.Reflection.Assembly.GetExecutingAssembly();
            #if true
            byte[] pinghiraw = getAllBytes(asm.GetManifestResourceStream("Clicker.pinghi48k16b.raw"));
            #else
            byte[] pinghiraw = File.ReadAllBytes("pinghi48k16b.raw");
            #endif
            short[,] pinghi = new short[pinghiraw.Length / 4, 2];
            for (int i = 0, b = 0; i < pinghiraw.Length - 4; i += 4, ++b)
            {
                pinghi[b, 0] = unchecked((short)(pinghiraw[i + 0] | (pinghiraw[i + 1] << 8)));
                pinghi[b, 1] = unchecked((short)(pinghiraw[i + 2] | (pinghiraw[i + 3] << 8)));
            }
            int pinghiLength = pinghi.GetUpperBound(0) + 1;

            #if true
            byte[] pingloraw = getAllBytes(asm.GetManifestResourceStream("Clicker.pinglo48k16b.raw"));
            #else
            byte[] pingloraw = File.ReadAllBytes("pinglo48k16b.raw");
            #endif
            short[,] pinglo = new short[pingloraw.Length / 4, 2];
            for (int i = 0, b = 0; i < pingloraw.Length - 4; i += 4, ++b)
            {
                pinglo[b, 0] = unchecked((short)(pingloraw[i + 0] | (pingloraw[i + 1] << 8)));
                pinglo[b, 1] = unchecked((short)(pingloraw[i + 2] | (pingloraw[i + 3] << 8)));
            }
            int pingloLength = pinglo.GetUpperBound(0) + 1;

            // Grab meter and tempo changes from any track:
            var timeChanges =
                from tr in seq
                from ev in tr.Iterator()
                where ev.MidiMessage.MessageType == MessageType.Meta
                let mm = (MetaMessage)ev.MidiMessage
                where mm.MetaType == MetaType.TimeSignature || mm.MetaType == MetaType.Tempo
                orderby ev.AbsoluteTicks ascending
                select new { ev, mm };

            var lastEvent = (
                from tr in seq
                from ev in tr.Iterator()
                orderby ev.AbsoluteTicks ascending
                select ev
            ).Last();

            // Create a default tempo of 120 bpm (500,000 us/b):
            var tcb = new TempoChangeBuilder() { Tempo = 500000 };
            tcb.Build();
            currentTempo = new TempoMessage(tcb.Result);

            // Create a default time signature of 4/4:
            var tsb = new TimeSignatureBuilder() { Numerator = 4, Denominator = 4 };
            tsb.Build();
            currentTimeSignature = new TimeSignatureMessage(tsb.Result);

            ticksPerQuarter = seq.Division;
            calcUsecPerTick();
            calcBeatTicks();

            double sample = 0d;

            samplesPerUsec = (double)samplesPerSec / 1000000d;

            string outWaveFile = Path.Combine(midiFile.Directory.FullName, midiFile.Name + ".click.wav");
            Console.WriteLine("Writing click track to '{0}'", outWaveFile);

            var format = new WaveFormatChunk();
            format.dwSamplesPerSec = (uint)samplesPerSec;
            format.wChannels = (ushort)channels;
            format.wBitsPerSample = (ushort)bitsPerSample;
            Console.WriteLine(
                "Sample rate = {0,6} Hz; Channels = {1,1}; BitsPerSample = {2,2}",
                format.dwSamplesPerSec,
                format.wChannels,
                format.wBitsPerSample
            );

            // Open the WAVE for output:
            using (var wav = File.Open(outWaveFile, FileMode.Create, FileAccess.Write, FileShare.Read))
            using (var bs = new BufferedStream(wav))
            using (var bw = new BinaryWriter(bs))
            {
                var header = new WaveHeader();

                // Write the header
                bw.Write(header.sGroupID.ToCharArray());
                bw.Write(header.dwFileLength);
                bw.Write(header.sRiffType.ToCharArray());

                // Write the format chunk
                bw.Write(format.sChunkID.ToCharArray());
                bw.Write(format.dwChunkSize);
                bw.Write(format.wFormatTag);
                bw.Write(format.wChannels);
                bw.Write(format.dwSamplesPerSec);
                bw.Write(format.dwAvgBytesPerSec);
                bw.Write(format.wBlockAlign);
                bw.Write(format.wBitsPerSample);

                var data = new WaveDataChunk();

                // Write the data chunk
                bw.Write(data.sChunkID.ToCharArray());
                bw.Write(data.dwChunkSize);

                double lastSample = sample;
                int nextBeatTick = 0;
                int note = 0;
                int tick = 0;

                using (var en = timeChanges.GetEnumerator())
                {
                    MidiEvent nextEvent;
                    bool haveKeyOrTempoChange = en.MoveNext();
                    var me = en.Current;
                    nextEvent = me.ev;

                    while (tick < lastEvent.AbsoluteTicks)
                    {
                        for (; tick < nextEvent.AbsoluteTicks; ++tick)
                        {
                            // Start a click at this tick:
                            if (tick == nextBeatTick)
                            {
                                int beat = note;
                                //Debug.WriteLine("Click at tick {0,7}, sample {1,12:#######0.00}, beat {2,2}", tick, sample, beat);

                                // Copy in a click:
                                double vol = doAttenuateBeat(beat) ? 0.3d : 1d;

                                // Silence until start of this click:
                                int x = (int)((long)sample - (long)lastSample);
                                for (; x > 0; --x)
                                {
                                    for (int j = 0; j < channels; ++j)
                                        bw.Write((short)0);
                                }

                                // Choose the click sound based on the beat:
                                short[,] click = (beat == 0) ? pinglo : pinghi;
                                int clickLength = (beat == 0) ? pingloLength : pinghiLength;

                                // Write the portion of the click if we missed the start:
                                int samplesWritten = 0;
                                long delta = x;
                                for (x = -x; x < clickLength; ++x, ++samplesWritten)
                                {
                                    int y = (int)((double)x * 48000d / (double)samplesPerSec);
                                    if (y >= clickLength) break;

                                    for (int j = 0; j < channels; ++j)
                                        bw.Write((short)(click[y, j] * vol));
                                }

                                lastSample = sample + samplesWritten + delta;

                                // Set next beat tick:
                                nextBeatTick = tick + beatTicks;
                                note = (note + 1) % getNumerator();
                            }

                            sample += samplesPerTick;
                        }

                        if (haveKeyOrTempoChange)
                        {
                            if (me.mm.MetaType == MetaType.Tempo)
                            {
                                currentTempo = new TempoMessage(me.mm);
                                calcUsecPerTick();
                                Console.WriteLine(
                                    "{0,9}: tempo {1,8:###0.000} bpm = {2,9:#,###,##0} usec/qtr",
                                    me.ev.AbsoluteTicks,
                                    500000d / currentTempo.MicrosecondsPerQuarter * 120,
                                    currentTempo.MicrosecondsPerQuarter
                                );
                            }
                            else
                            {
                                currentTimeSignature = new TimeSignatureMessage(me.mm);
                                calcBeatTicks();
            #if false
                                // NOTE: Assume key change is on a beat tick; force a reset of beats anyway.
                                //nextBeatTick = tick;
                                //note = 0;
            #endif
                                Console.WriteLine(
                                    "{0,9}: meter {1,2}/{2,-2} treating as {3,2}/{4,-2}",
                                    me.ev.AbsoluteTicks,
                                    currentTimeSignature.Numerator, currentTimeSignature.Denominator,
                                    getNumerator(), getDenominator()
                                );
                            }

                            haveKeyOrTempoChange = en.MoveNext();
                            if (haveKeyOrTempoChange)
                            {
                                me = en.Current;
                                nextEvent = me.ev;
                            }
                            else
                            {
                                me = null;
                                nextEvent = lastEvent;
                            }
                        }
                    }
                }

                // Write RIFF file size:
                bw.Seek(4, SeekOrigin.Begin);
                uint filesize = (uint)wav.Length;
                bw.Write(filesize - 8);

                // Write "data" chunk size:
                bw.Seek(0x28, SeekOrigin.Begin);
                bw.Write(filesize - 0x2C);
            }

            Console.WriteLine("Click track written to '{0}'", outWaveFile);
            Console.WriteLine(
                "Sample rate = {0,6} Hz; Channels = {1,1}; BitsPerSample = {2,2}",
                format.dwSamplesPerSec,
                format.wChannels,
                format.wBitsPerSample
            );
        }
コード例 #26
0
            public WaveGenerator(Signal type, int amplitude, int frequency, int phaze, bool noize)
            {
                header = new WaveHeader();
                format = new WaveFormatChunk();
                data   = new WaveDataChunk();
                double sinValue;
                uint   numSamples;

                Amplitude = amplitude;
                Frequency = frequency;
                Phaze     = phaze;

                switch (type)
                {
                case Signal.syn:
                    numSamples      = format.dwSamplesPerSec * format.wChannels;
                    data.shortArray = new short[numSamples];

                    double t = (Math.PI * 2 * Frequency) / (format.dwSamplesPerSec * format.wChannels);

                    for (uint i = 0; i < numSamples - 1; i++)
                    {
                        for (int channel = 0; channel < format.wChannels; channel++)
                        {
                            data.shortArray[i + channel] = Convert.ToInt16(Amplitude * Math.Sin(t * i + Phaze));
                            data.shortArray[i + channel] = noize ? Convert.ToInt16(data.shortArray[i + channel] + NoizeStep) : data.shortArray[i + channel];
                        }
                    }
                    data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
                    break;

                case Signal.rectangle:
                    numSamples      = format.dwSamplesPerSec * format.wChannels;
                    data.shortArray = new short[numSamples];

                    for (uint i = 0; i < numSamples - 1; i++)
                    {
                        for (int channel = 0; channel < format.wChannels; channel++)
                        {
                            sinValue = (2 * Math.PI * Frequency) / (format.dwSamplesPerSec * format.wChannels);
                            data.shortArray[i + channel] = Convert.ToInt16(amplitude * Math.Sign(Math.Sin((i * sinValue + phaze))));
                            data.shortArray[i + channel] = noize ? Convert.ToInt16(data.shortArray[i + channel] + NoizeStep) : data.shortArray[i + channel];
                        }
                    }
                    data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
                    break;

                case Signal.triangle:
                    numSamples      = format.dwSamplesPerSec * format.wChannels;
                    data.shortArray = new short[numSamples];

                    for (uint i = 0; i < numSamples - 1; i++)
                    {
                        for (int channel = 0; channel < format.wChannels; channel++)
                        {
                            sinValue = (2 * Math.PI * Frequency) / (format.dwSamplesPerSec * format.wChannels);
                            data.shortArray[i + channel] = Convert.ToInt16(amplitude * Math.Asin(Math.Sin((i * sinValue + phaze))));
                            data.shortArray[i + channel] = noize ? Convert.ToInt16(data.shortArray[i + channel] + NoizeStep) : data.shortArray[i + channel];
                        }
                    }
                    data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
                    break;

                case Signal.saw:
                    numSamples      = format.dwSamplesPerSec * format.wChannels;
                    data.shortArray = new short[numSamples];

                    for (uint i = 0; i < numSamples - 1; i++)
                    {
                        for (int channel = 0; channel < format.wChannels; channel++)
                        {
                            sinValue = (Math.PI * Frequency) / (format.dwSamplesPerSec * format.wChannels);
                            data.shortArray[i + channel] = Convert.ToInt16(-2 * amplitude / Math.PI * Math.Atan(1 / Math.Tan((i * sinValue + phaze))));
                            data.shortArray[i + channel] = noize ? Convert.ToInt16(data.shortArray[i + channel] + NoizeStep) : data.shortArray[i + channel];
                        }
                    }
                    data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
                    break;
                }
            }
コード例 #27
0
ファイル: WaveFile.cs プロジェクト: rmc00/gsf
 public WaveFile(RiffHeaderChunk waveHeader, WaveFormatChunk waveFormat, WaveDataChunk waveData, ListInfoChunk listInfo = null)
 {
     m_waveHeader = waveHeader;
     m_waveFormat = waveFormat;
     m_waveData = waveData;
     m_listInfo = listInfo;
 }
コード例 #28
0
 public void save(WaveHeader h, WaveFormatChunk f, WaveDataChunk d, string path)
 {
     fileSaver fs = new fileSaver(h, f, d, path);
 }