声音合成器 1 基本噪音

简介: 声音合成器 1 基本噪音

一、准备工作

1.创建空工程,设置工程属性。链接器--输入--附加依赖项中添加winmm.lib;

2.在项目中添加头文件:olcNoiseMaker.h

https://github.com/OneLoneCoder/synth/blob/master/olcNoiseMaker.h

/* 
  OneLoneCoder.com - Simple Audio Noisy Thing
  "Allows you to simply listen to that waveform!" - @Javidx9
  License
  ~~~~~~~
  Copyright (C) 2018  Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it
  under certain conditions; See license for details. 
  Original works located at:
  https://www.github.com/onelonecoder
  https://www.onelonecoder.com
  https://www.youtube.com/javidx9
  GNU GPLv3
  https://github.com/OneLoneCoder/videos/blob/master/LICENSE
  From Javidx9 :)
  ~~~~~~~~~~~~~~~
  Hello! Ultimately I don't care what you use this for. It's intended to be 
  educational, and perhaps to the oddly minded - a little bit of fun. 
  Please hack this, change it and use it in any way you see fit. You acknowledge 
  that I am not responsible for anything bad that happens as a result of 
  your actions. However this code is protected by GNU GPLv3, see the license in the
  github repo. This means you must attribute me if you use it. You can view this
  license here: https://github.com/OneLoneCoder/videos/blob/master/LICENSE
  Cheers!
  Author
  ~~~~~~
  Twitter: @javidx9
  Blog: www.onelonecoder.com
  Versions
  ~~~~~~~~
  1.0 - 14/01/17
  - Controls audio output hardware behind the scenes so you can just focus
    on creating and listening to interesting waveforms.
  - Currently MS Windows only
  Documentation
  ~~~~~~~~~~~~~
  See video: https://youtu.be/tgamhuQnOkM
  This will improve as it grows!
*/
 
 
#pragma once
 
#pragma comment(lib, "winmm.lib")
 
#include <iostream>
#include <cmath>
#include <fstream>
#include <vector>
#include <string>
#include <thread>
#include <atomic>
#include <condition_variable>
using namespace std;
 
#include <Windows.h>
 
const double PI = 2.0 * acos(0.0);
 
template<class T>
class olcNoiseMaker
{
public:
  olcNoiseMaker(wstring sOutputDevice, unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512)
  {
    Create(sOutputDevice, nSampleRate, nChannels, nBlocks, nBlockSamples);
  }
 
  ~olcNoiseMaker()
  {
    Destroy();
  }
 
  bool Create(wstring sOutputDevice, unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512)
  {
    m_bReady = false;
    m_nSampleRate = nSampleRate;
    m_nChannels = nChannels;
    m_nBlockCount = nBlocks;
    m_nBlockSamples = nBlockSamples;
    m_nBlockFree = m_nBlockCount;
    m_nBlockCurrent = 0;
    m_pBlockMemory = nullptr;
    m_pWaveHeaders = nullptr;
 
    m_userFunction = nullptr;
 
    // Validate device
    vector<wstring> devices = Enumerate();
    auto d = std::find(devices.begin(), devices.end(), sOutputDevice);
    if (d != devices.end())
    {
      // Device is available
      int nDeviceID = distance(devices.begin(), d);
      WAVEFORMATEX waveFormat;
      waveFormat.wFormatTag = WAVE_FORMAT_PCM;
      waveFormat.nSamplesPerSec = m_nSampleRate;
      waveFormat.wBitsPerSample = sizeof(T) * 8;
      waveFormat.nChannels = m_nChannels;
      waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
      waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
      waveFormat.cbSize = 0;
 
      // Open Device if valid
      if (waveOutOpen(&m_hwDevice, nDeviceID, &waveFormat, (DWORD_PTR)waveOutProcWrap, (DWORD_PTR)this, CALLBACK_FUNCTION) != S_OK)
        return Destroy();
    }
 
    // Allocate Wave|Block Memory
    m_pBlockMemory = new T[m_nBlockCount * m_nBlockSamples];
    if (m_pBlockMemory == nullptr)
      return Destroy();
    ZeroMemory(m_pBlockMemory, sizeof(T) * m_nBlockCount * m_nBlockSamples);
 
    m_pWaveHeaders = new WAVEHDR[m_nBlockCount];
    if (m_pWaveHeaders == nullptr)
      return Destroy();
    ZeroMemory(m_pWaveHeaders, sizeof(WAVEHDR) * m_nBlockCount);
 
    // Link headers to block memory
    for (unsigned int n = 0; n < m_nBlockCount; n++)
    {
      m_pWaveHeaders[n].dwBufferLength = m_nBlockSamples * sizeof(T);
      m_pWaveHeaders[n].lpData = (LPSTR)(m_pBlockMemory + (n * m_nBlockSamples));
    }
 
    m_bReady = true;
 
    m_thread = thread(&olcNoiseMaker::MainThread, this);
 
    // Start the ball rolling
    unique_lock<mutex> lm(m_muxBlockNotZero);
    m_cvBlockNotZero.notify_one();
 
    return true;
  }
 
  bool Destroy()
  {
    return false;
  }
 
  void Stop()
  {
    m_bReady = false;
    m_thread.join();
  }
 
  // Override to process current sample
  virtual double UserProcess(double dTime)
  {
    return 0.0;
  }
 
  double GetTime()
  {
    return m_dGlobalTime;
  }
 
  
 
public:
  static vector<wstring> Enumerate()
  {
    int nDeviceCount = waveOutGetNumDevs();
    vector<wstring> sDevices;
    WAVEOUTCAPS woc;
    for (int n = 0; n < nDeviceCount; n++)
      if (waveOutGetDevCaps(n, &woc, sizeof(WAVEOUTCAPS)) == S_OK)
        sDevices.push_back(woc.szPname);
    return sDevices;
  }
 
  void SetUserFunction(double(*func)(double))
  {
    m_userFunction = func;
  }
 
  double clip(double dSample, double dMax)
  {
    if (dSample >= 0.0)
      return fmin(dSample, dMax);
    else
      return fmax(dSample, -dMax);
  }
 
 
private:
  double(*m_userFunction)(double);
 
  unsigned int m_nSampleRate;
  unsigned int m_nChannels;
  unsigned int m_nBlockCount;
  unsigned int m_nBlockSamples;
  unsigned int m_nBlockCurrent;
 
  T* m_pBlockMemory;
  WAVEHDR *m_pWaveHeaders;
  HWAVEOUT m_hwDevice;
 
  thread m_thread;
  atomic<bool> m_bReady;
  atomic<unsigned int> m_nBlockFree;
  condition_variable m_cvBlockNotZero;
  mutex m_muxBlockNotZero;
 
  atomic<double> m_dGlobalTime;
 
  // Handler for soundcard request for more data
  void waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
  {
    if (uMsg != WOM_DONE) return;
 
    m_nBlockFree++;
    unique_lock<mutex> lm(m_muxBlockNotZero);
    m_cvBlockNotZero.notify_one();
  }
 
  // Static wrapper for sound card handler
  static void CALLBACK waveOutProcWrap(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
  {
    ((olcNoiseMaker*)dwInstance)->waveOutProc(hWaveOut, uMsg, dwParam1, dwParam2);
  }
 
  // Main thread. This loop responds to requests from the soundcard to fill 'blocks'
  // with audio data. If no requests are available it goes dormant until the sound
  // card is ready for more data. The block is fille by the "user" in some manner
  // and then issued to the soundcard.
  void MainThread()
  {
    m_dGlobalTime = 0.0;
    double dTimeStep = 1.0 / (double)m_nSampleRate;
 
    // Goofy hack to get maximum integer for a type at run-time
    T nMaxSample = (T)pow(2, (sizeof(T) * 8) - 1) - 1;
    double dMaxSample = (double)nMaxSample;
    T nPreviousSample = 0;
 
    while (m_bReady)
    {
      // Wait for block to become available
      if (m_nBlockFree == 0)
      {
        unique_lock<mutex> lm(m_muxBlockNotZero);
        m_cvBlockNotZero.wait(lm);
      }
 
      // Block is here, so use it
      m_nBlockFree--;
 
      // Prepare block for processing
      if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED)
        waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
 
      T nNewSample = 0;
      int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples;
      
      for (unsigned int n = 0; n < m_nBlockSamples; n++)
      {
        // User Process
        if (m_userFunction == nullptr)
          nNewSample = (T)(clip(UserProcess(m_dGlobalTime), 1.0) * dMaxSample);
        else
          nNewSample = (T)(clip(m_userFunction(m_dGlobalTime), 1.0) * dMaxSample);
 
        m_pBlockMemory[nCurrentBlock + n] = nNewSample;
        nPreviousSample = nNewSample;
        m_dGlobalTime = m_dGlobalTime + dTimeStep;
      }
 
      // Send block to sound device
      waveOutPrepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
      waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
      m_nBlockCurrent++;
      m_nBlockCurrent %= m_nBlockCount;
    }
  }
};

二、开始制造噪音

这里有一些和声音采样有关的知识,当然不知道也不影响继续。

2.1 声音测试(建议把声音先调低点,运行后应该听到呜呜的噪声)

#include <iostream>
using namespace std;
 
#include "olcNoiseMaker.h"
 
double MakeNoise(double dTime)
{
  return 0.5*sin(440.0 * 2 * 3.14159*dTime); //声音的频率440hz
}
 
int main()
{
  // Shameless self-promotion
  wcout << "www.OneLoneCoder.com - Synthesizer Part 1" << endl 
    << "Single Sine Wave Oscillator, No Polyphony" << endl << endl;
 
  // Get all sound hardware
  vector<wstring> devices = olcNoiseMaker<short>::Enumerate();
 
  // Display findings
  for (auto d : devices) wcout << "Found Output Device: " << d << endl;
  wcout << "Using Device: " << devices[0] << endl;
  //创建声音机器
  olcNoiseMaker<short> sound(devices[0], 44100, 1, 8, 512); //44100~奈奎斯特采样(记录的最高频率2倍),
 
  sound.SetUserFunction(MakeNoise);
 
  while (1)
  {
 
  }
  return 0;
}

2.2  控制声音

通过按键‘a’更改频率,来改变声音。

atomic<double> dFreequencyOutput = 0.0; //原子类,用来保证多进程同步
 
double MakeNoise(double dTime)
{
    //方波
  double dOutput = 1.0*sin(dFreequencyOutput * 2 * 3.14159*dTime);
  if (dOutput > 0.0)
    return 0.2;
  else
    return -0.2;
}
 
 
while (1)
  {
    //按键响应'a'
    if (GetAsyncKeyState('A') & 0x8000)
    {
      dFreequencyOutput = 440.0;
    }
    else 
    {
      dFreequencyOutput = 0;
 
    }
 
  }

更准确一些可以将一个基本音分为12个组...

double dOctaveBaseFrequency = 110.0; // A2    // frequency of octave represented by keyboard
  double d12thRootOf2 = pow(2.0, 1.0 / 12.0);   // assuming western 12 notes per ocatve
  while (1)
  {
    //按键响应'a'
    if (GetAsyncKeyState('A') & 0x8000)
    {
      dFreequencyOutput = dOctaveBaseFrequency * pow(d12thRootOf2,12);
    }
    else 
    {
      dFreequencyOutput = 0;
 
    }
 
  }

然后利用16个键来控制不同的调。

    bool bKeyPressed = false;
    for (int k = 0; k < 15; k++)
    {
      if (GetAsyncKeyState((unsigned char)("ZSXCFVGBNJMK\xbcL\xbe\xbf"[k])) & 0x8000)
      {
        dFreequencyOutput = dOctaveBaseFrequency * pow(d12thRootOf2, k);
        bKeyPressed = true;
      }
    }
    
    if(!bKeyPressed)
    {
      dFreequencyOutput = 0.0;
    }

2.3 完整代码,最后说的和弦没有做出来

#include <iostream>
using namespace std;
 
#include "olcNoiseMaker.h"
 
atomic<double> dFreequencyOutput = 0.0; //原子类,用来保证多进程同步
 
double MakeNoise(double dTime)
{
  //方波
  double dOutput = 1.0*sin(dFreequencyOutput * 2 * 3.14159*dTime);
  if (dOutput > 0.0)
    return 0.2;
  else
    return -0.2;
}
 
int main()
{
  // Shameless self-promotion
  wcout << "www.OneLoneCoder.com - Synthesizer Part 1" << endl 
    << "Single Sine Wave Oscillator, No Polyphony" << endl << endl;
 
  // Get all sound hardware
  vector<wstring> devices = olcNoiseMaker<short>::Enumerate();
 
  // Display findings
  for (auto d : devices) wcout << "Found Output Device: " << d << endl;
  wcout << "Using Device: " << devices[0] << endl;
  //创建声音机器
  olcNoiseMaker<short> sound(devices[0], 44100, 1, 8, 512); //44100~奈奎斯特采样(记录的最高频率2倍),
 
  sound.SetUserFunction(MakeNoise);
  double dOctaveBaseFrequency = 110.0; // A2    // frequency of octave represented by keyboard
  double d12thRootOf2 = pow(2.0, 1.0 / 12.0);   // assuming western 12 notes per ocatve
  while (1)
  {
    bool bKeyPressed = false;
    for (int k = 0; k < 15; k++)
    {
      if (GetAsyncKeyState((unsigned char)("ZSXCFVGBNJMK\xbcL\xbe\xbf"[k])) & 0x8000)
      {
        dFreequencyOutput = dOctaveBaseFrequency * pow(d12thRootOf2, k);
        bKeyPressed = true;
      }
    }
    
    if(!bKeyPressed)
    {
      dFreequencyOutput = 0.0;
    }
 
  }
  return 0;
}



相关文章
什么是音频降噪处理中的降噪强度参数
什么是音频降噪处理中的降噪强度参数
|
4月前
|
算法
什么是音频降噪处理中的灵敏度参数
什么是音频降噪处理中的灵敏度参数
|
机器学习/深度学习 传感器 算法
【红外图像增强】基于引力和侧向抑制网络的红外图像增强模型(Matlab代码实现)
【红外图像增强】基于引力和侧向抑制网络的红外图像增强模型(Matlab代码实现)
|
算法
【Vuvuzela 声音去噪算法】基于流行的频谱减法技术的声音去噪算法研究(Matlab代码实现)
【Vuvuzela 声音去噪算法】基于流行的频谱减法技术的声音去噪算法研究(Matlab代码实现)
|
算法
通过EEMD进行心脏频率和心电图信号去噪(Matlab代码实现)
通过EEMD进行心脏频率和心电图信号去噪(Matlab代码实现)
140 0
检测使用校准的立体摄像头拍摄的视频中的人物并确定其与摄像头的距离
检测使用校准的立体摄像头拍摄的视频中的人物,并确定他们与摄像头的距离。
132 0
|
机器学习/深度学习 传感器 算法
【车道检测】基于帧差法结合hough实现车道检测含播报声音附GUI界面
【车道检测】基于帧差法结合hough实现车道检测含播报声音附GUI界面
|
传感器 机器学习/深度学习 编解码
最新鱼眼BEV感知 | FPNet:面向泊车场景的失真不敏感多任务算法(TIV 2022)(上)
本文介绍了一种新的大规模鱼眼数据集 FPD,旨在促进对现实环境中各种环视泊车情况的研究。值得注意的是,作者的FPD对不同的环视感知任务都显示出优秀的特点。此外,作者还提出了实时的失真不敏感的多任务鱼眼感知网络(FPNet) ,通过增强鱼眼失真操作和多任务轻量级设计来改善环视鱼眼 BEV 感知。大量的实验验证了作者的方法的有效性和数据集的异常可推广性。
最新鱼眼BEV感知 | FPNet:面向泊车场景的失真不敏感多任务算法(TIV 2022)(上)
|
机器学习/深度学习 数据可视化 自动驾驶
最新鱼眼BEV感知 | FPNet:面向泊车场景的失真不敏感多任务算法(TIV 2022)(下)
本文介绍了一种新的大规模鱼眼数据集 FPD,旨在促进对现实环境中各种环视泊车情况的研究。值得注意的是,作者的FPD对不同的环视感知任务都显示出优秀的特点。此外,作者还提出了实时的失真不敏感的多任务鱼眼感知网络(FPNet) ,通过增强鱼眼失真操作和多任务轻量级设计来改善环视鱼眼 BEV 感知。大量的实验验证了作者的方法的有效性和数据集的异常可推广性。
最新鱼眼BEV感知 | FPNet:面向泊车场景的失真不敏感多任务算法(TIV 2022)(下)
|
传感器
红外热成像仪 红外图像伪彩色编码
什么是红外成像伪彩编码 红外成像的最终目的是用图像来表现温度变化,并且可以通过颜色来区分出不同热量的物体轮廓和形状。那么,到底用什么颜色来表示什么温度呢?是否有什么标准规范呢?
红外热成像仪  红外图像伪彩色编码