Python和C++音调音符规划和算法

news/2024/9/22 15:37:49/

🎯要点

  1. 🎯音符表征和代码实现:🖊半音位置和索引之间的转换 | 🖊全音阶音调表征 | 🖊全音阶缓存 | 🖊全音阶音高表征。🎯音程表征和代码实现:🖊音程质量 | 🖊计算开始和结束音高。🎯情态和音调和代码实现:🖊创建情态:全音阶调式、五声音阶、八音调态、全音调态、布鲁斯调式 | 🖊构建模态 | 🖊音调表征 | 🖊生成基于音高的音阶。🎯音符时长代码实现:🖊时间线转换算法 | 🖊节拍时间转换算法 | 🖊全音符时间表征 | 🖊位置和时长算子 | 🖊节拍位置 | 🖊拍号和节奏 | 🖊时间转换算法。🎯音符及其连音代码实现:🖊梁和连音定义 | 🖊反转旋律的算法。🎯和弦代码实现:🖊文本规范构建和弦 | 🖊三级和弦 | 🖊次和弦 | 🖊四和弦 。🎯乐器模型代码实现:🖊演奏记号列表。🎯乐谱表征和代码实现:🖊声音中的嵌套音符 | 🖊节奏、节拍和调号序列 | 🖊基于时间的音符搜索方式:红黑树方式、音程树方式 | 🖊事件和观察者模式更新音程树。🎯MIDI 表征和代码实现:🖊MIDI消息定义 | 🖊乐谱和MIDI文件转换算法 | 🖊音符转换为MIDI文件。🎯音调约束规划 | 🎯音调移位变换 | 🎯旋律反转变换和重塑 | 🎯和声转录 | 🎯逆转旋律。
  2. 🎯音乐合成:🖊节拍自定义:🖊使用底鼓、军鼓和踩镲 | 🖊旋律创建:🖊贝多芬《致爱丽丝》混音版 | 🖊和弦创建:🖊观察音色、和声和时间的细微变化 | 🖊音阶、调和旋律构建 | 🖊全音阶和弦 | 🖊傅里叶变换创建音效 | 🖊 基于音符的音效 | 🖊歌曲编辑。
  3. 🎯Python数字声音合成 | 🎯C++数字声音合成

🍇C++多抽头混响音效

混响与延迟类似,都为声音添加了回声。 不过,它的不同之处在于,延迟会添加一个回声(即使该回声会重复出现,每次都会更安静),而混响会在声音中添加多个回声。 基本上,混响使声音听起来像是在教堂、深洞或小浴室中演奏的。 延迟只会让事情听起来有点回声。

该技术非常简单。 您有一个样本缓冲区来保存最后 N 个样本,然后当您处理传入样本时,您添加来自延迟缓冲区的多个样本,每个样本乘以不同的音量(幅度)并将其添加到传入样本中以获得输出样本。 然后,您还将该传出样本放入循环缓冲区中当前索引处的混响缓冲区中。

这是一些关于如何实现它的伪代码:


reverbBuffer[reverbSamples] = 0;reverbIndex= 0;for (i = 0; i < numSamples; ++i)
{outSample[i] = inSample[i];for (j = 0; j < numTaps; ++j)outSample[i] += reverbBuffer[reverbIndex - taps[j].tapTime] * taps[j].feedbackMultiplier; reverbBuffer[reverbIndex] = outSample[i];reverbIndex++;if (reverbIndex>= reverbSamples)reverbIndex= 0;
}

在下面的示例代码以及上面的混响处理示例中,以下是所使用的拍子的时间和幅度。幅度以 dB 和幅度的形式给出,因此您可以看到您更喜欢的那个。
Time (ms)  d B Amplitude  79 − 25 0.0562 130 − 23 0.0707 230 − 15 0.1778 340 − 23 0.0707 470 − 17 0.1412 532 − 21 0.0891 662 − 13 0.2238 \begin{array}{lll} \text { Time (ms) } & dB & \text { Amplitude } \\ 79 & -25 & 0.0562 \\ 130 & -23 & 0.0707 \\ 230 & -15 & 0.1778 \\ 340 & -23 & 0.0707 \\ 470 & -17 & 0.1412 \\ 532 & -21 & 0.0891 \\ 662 & -13 & 0.2238 \end{array}  Time (ms) 79130230340470532662dB25231523172113 Amplitude 0.05620.07070.17780.07070.14120.08910.2238
通过更多的努力,您可能会想出一些更好的抽头值来使混响听起来更好。下面的示例代码加载 in.wav,使用上面提到的 Tap 对其进行处理,并将其写出为 out.wav。 与往常一样,波形加载代码对于某些波形格式存在一些问题。

#define _CRT_SECURE_NO_WARNINGS#include <array>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <cmath>
#include <vector>#define _USE_MATH_DEFINES
#include <math.h>template <typename T, typename PHANTOM_TYPE>
struct SNumeric
{
public:explicit SNumeric(const T &value) : m_value(value) { }SNumeric() : m_value() { }inline T& Value() { return m_value; }inline const T& Value() const { return m_value; }typedef SNumeric<T, PHANTOM_TYPE> TType;typedef T TInnerType;// Math OperationsTType operator+ (const TType &b) const{return TType(this->Value() + b.Value());}TType operator- (const TType &b) const{return TType(this->Value() - b.Value());}TType operator* (const TType &b) const{return TType(this->Value() * b.Value());}TType operator/ (const TType &b) const{return TType(this->Value() / b.Value());}TType& operator+= (const TType &b){Value() += b.Value();return *this;}TType& operator-= (const TType &b){Value() -= b.Value();return *this;}TType& operator*= (const TType &b){Value() *= b.Value();return *this;}TType& operator/= (const TType &b){Value() /= b.Value();return *this;}TType& operator++ (){Value()++;return *this;}TType& operator-- (){Value()--;return *this;}// Extended Math Operationstemplate <typename T>T Divide(const TType &b){return ((T)this->Value()) / ((T)b.Value());}// Logic Operationsbool operator< (const TType &b) const {return this->Value() < b.Value();}bool operator<= (const TType &b) const {return this->Value() <= b.Value();}bool operator> (const TType &b) const {return this->Value() > b.Value();}bool operator>= (const TType &b) const {return this->Value() >= b.Value();}bool operator== (const TType &b) const {return this->Value() == b.Value();}bool operator!= (const TType &b) const {return this->Value() != b.Value();}private:T m_value;
};typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef int16_t int16;
typedef int32_t int32;typedef SNumeric<float, struct S__Frequency>      TFrequency;
typedef SNumeric<uint32, struct S__TimeMs>        TTimeMs;
typedef SNumeric<uint32, struct S__Samples>       TSamples;
typedef SNumeric<float, struct S__FractSamples>   TFractionalSamples;
typedef SNumeric<float, struct S__Decibels>       TDecibels;
typedef SNumeric<float, struct S__Amplitude>      TAmplitude;
typedef SNumeric<float, struct S__Phase>          TPhase;static const float c_pi = (float)M_PI;
static const float c_twoPi = c_pi * 2.0f;//=====================================================================================
// Structs
//=====================================================================================struct SSoundSettings
{TSamples        m_sampleRate;TTimeMs         m_lengthMs;TSamples        m_currentSample;
};struct SReverbTap
{TSamples    m_timeOffset;TAmplitude  m_feedback;
};class CMultitapReverb
{
public:CMultitapReverb(const std::vector<SReverbTap>& taps): m_sampleIndex(0){m_taps = taps;TSamples largestTimeOffset(0);std::for_each(m_taps.begin(), m_taps.end(),[&largestTimeOffset](const SReverbTap& tap){if (tap.m_timeOffset > largestTimeOffset)largestTimeOffset = tap.m_timeOffset;});if (largestTimeOffset.Value() == 0)return;m_samples.resize(largestTimeOffset.Value()+1);std::fill(m_samples.begin(), m_samples.end(), TAmplitude(0.0f));}TAmplitude ProcessSample(TAmplitude sample){if (m_samples.size() == 0)return sample;TAmplitude outSample = sample;std::for_each(m_taps.begin(), m_taps.end(),[&outSample, this](const SReverbTap& tap){size_t tapSampleIndex;if (tap.m_timeOffset.Value() > m_sampleIndex)tapSampleIndex = m_samples.size() - 1 - (tap.m_timeOffset.Value() - m_sampleIndex);elsetapSampleIndex = m_sampleIndex - tap.m_timeOffset.Value();outSample += m_samples[tapSampleIndex] * tap.m_feedback;});m_samples[m_sampleIndex] = outSample;m_sampleIndex++;if (m_sampleIndex >= m_samples.size())m_sampleIndex = 0;return outSample;}private:std::vector<SReverbTap> m_taps;std::vector<TAmplitude> m_samples;size_t                  m_sampleIndex;
};inline TDecibels AmplitudeToDB(TAmplitude volume)
{return TDecibels(log10(volume.Value()));
}inline TAmplitude DBToAmplitude(TDecibels dB)
{return TAmplitude(pow(10.0f, dB.Value() / 20.0f));
}TSamples SecondsToSamples(const SSoundSettings &s, float seconds)
{return TSamples((int)(seconds * (float)s.m_sampleRate.Value()));
}TSamples MilliSecondsToSamples(const SSoundSettings &s, float milliseconds)
{return SecondsToSamples(s, milliseconds / 1000.0f);
}TTimeMs SecondsToMilliseconds(float seconds)
{return TTimeMs((uint32)(seconds * 1000.0f));
}TFrequency Frequency(float octave, float note)
{return TFrequency((float)(440 * pow(2.0, ((double)((octave - 4) * 12 + note)) / 12.0)));
}template <typename T>
T AmplitudeToAudioSample(const TAmplitude& in)
{const T c_min = std::numeric_limits<T>::min();const T c_max = std::numeric_limits<T>::max();const float c_minFloat = (float)c_min;const float c_maxFloat = (float)c_max;float ret = in.Value() * c_maxFloat;if (ret < c_minFloat)return c_min;if (ret > c_maxFloat)return c_max;return (T)ret;
}TAmplitude GetLerpedAudioSample(const std::vector<TAmplitude>& samples, TFractionalSamples& index)
{uint32 a = (uint32)floor(index.Value());uint32 b = a + 1;float fract = index.Value() - floor(index.Value());float ampA = 0.0f;if (a >= 0 && a < samples.size())ampA = samples[a].Value();float ampB = 0.0f;if (b >= 0 && b < samples.size())ampB = samples[b].Value();return TAmplitude(fract * ampB + (1.0f - fract) * ampA);
}void NormalizeSamples(std::vector<TAmplitude>& samples, TAmplitude maxAmplitude)
{if (samples.size() == 0)return;TAmplitude largestAbsVal = TAmplitude(abs(samples.front().Value()));std::for_each(samples.begin() + 1, samples.end(), [&largestAbsVal](const TAmplitude &a){TAmplitude absVal = TAmplitude(abs(a.Value()));if (absVal > largestAbsVal)largestAbsVal = absVal;});largestAbsVal /= maxAmplitude;if (largestAbsVal <= TAmplitude(0.0f))return;std::for_each(samples.begin(), samples.end(), [&largestAbsVal](TAmplitude &a){a /= largestAbsVal;if (a >= TAmplitude(1.0f)){int ijkl = 0;}});
}void ResampleData(std::vector<TAmplitude>& samples, int srcSampleRate, int destSampleRate)
{if (srcSampleRate == destSampleRate)return;float fResampleRatio = (float)destSampleRate / (float)srcSampleRate;int nNewDataNumSamples = (int)((float)samples.size() * fResampleRatio);std::vector<TAmplitude> newSamples;newSamples.resize(nNewDataNumSamples);for (int nIndex = 0; nIndex < nNewDataNumSamples; ++nIndex)newSamples[nIndex] = GetLerpedAudioSample(samples, TFractionalSamples((float)nIndex / fResampleRatio));std::swap(samples, newSamples);
}void ChangeNumChannels(std::vector<TAmplitude>& samples, int nSrcChannels, int nDestChannels)
{if (nSrcChannels == nDestChannels ||nSrcChannels < 1 || nSrcChannels > 2 ||nDestChannels < 1 || nDestChannels > 2){return;}if (nDestChannels == 2){std::vector<TAmplitude> newSamples;newSamples.resize(samples.size() * 2);for (size_t index = 0; index < samples.size(); ++index){newSamples[index * 2] = samples[index];newSamples[index * 2 + 1] = samples[index];}std::swap(samples, newSamples);}else{std::vector<TAmplitude> newSamples;newSamples.resize(samples.size() / 2);for (size_t index = 0; index < samples.size() / 2; ++index)newSamples[index] = samples[index * 2] + samples[index * 2 + 1];std::swap(samples, newSamples);}
}float PCMToFloat(unsigned char *pPCMData, int nNumBytes)
{switch (nNumBytes){case 1:{uint8 data = pPCMData[0];return (float)data / 255.0f;}case 2:{int16 data = pPCMData[1] << 8 | pPCMData[0];return ((float)data) / ((float)0x00007fff);}case 3:{int32 data = pPCMData[2] << 16 | pPCMData[1] << 8 | pPCMData[0];return ((float)data) / ((float)0x007fffff);}case 4:{int32 data = pPCMData[3] << 24 | pPCMData[2] << 16 | pPCMData[1] << 8 | pPCMData[0];return ((float)data) / ((float)0x7fffffff);}default:{return 0.0f;}}
}struct SMinimalWaveFileHeader
{unsigned char m_szChunkID[4];      //0uint32        m_nChunkSize;        //4unsigned char m_szFormat[4];       //8unsigned char m_szSubChunk1ID[4];  //12uint32        m_nSubChunk1Size;    //16uint16        m_nAudioFormat;      //18uint16        m_nNumChannels;      //20uint32        m_nSampleRate;       //24uint32        m_nByteRate;         //28uint16        m_nBlockAlign;       //30uint16        m_nBitsPerSample;    //32unsigned char m_szSubChunk2ID[4];  //36uint32        m_nSubChunk2Size;    //40};template <typename T>
bool WriteWaveFile(const char *fileName, const std::vector<TAmplitude> &samples, const SSoundSettings &sound)
{//open the file if we canFILE *file = fopen(fileName, "w+b");if (!file)return false;//calculate bits per sample and the data sizeconst int32 bitsPerSample = sizeof(T) * 8;const int dataSize = samples.size() * sizeof(T);SMinimalWaveFileHeader waveHeader;//fill out the main chunkmemcpy(waveHeader.m_szChunkID, "RIFF", 4);waveHeader.m_nChunkSize = dataSize + 36;memcpy(waveHeader.m_szFormat, "WAVE", 4);//fill out sub chunk 1 "fmt "memcpy(waveHeader.m_szSubChunk1ID, "fmt ", 4);waveHeader.m_nSubChunk1Size = 16;waveHeader.m_nAudioFormat = 1;waveHeader.m_nNumChannels = 1;waveHeader.m_nSampleRate = sound.m_sampleRate.Value();waveHeader.m_nByteRate = sound.m_sampleRate.Value() * 1 * bitsPerSample / 8;waveHeader.m_nBlockAlign = 1 * bitsPerSample / 8;waveHeader.m_nBitsPerSample = bitsPerSample;//fill out sub chunk 2 "data"memcpy(waveHeader.m_szSubChunk2ID, "data", 4);waveHeader.m_nSubChunk2Size = dataSize;//write the headerfwrite(&waveHeader, sizeof(SMinimalWaveFileHeader), 1, file);//write the wave data itself, converting it from float to the type specifiedstd::vector<T> outSamples;outSamples.resize(samples.size());for (size_t index = 0; index < samples.size(); ++index)outSamples[index] = AmplitudeToAudioSample<T>(samples[index]);fwrite(&outSamples[0], dataSize, 1, file);//close the file and return successfclose(file);return true;
}bool ReadWaveFile(const char *fileName, std::vector<TAmplitude>& samples, int32 sampleRate)
{//open the file if we canFILE *File = fopen(fileName, "rb");if (!File){return false;}//read the main chunk ID and make sure it's "RIFF"char buffer[5];buffer[4] = 0;if (fread(buffer, 4, 1, File) != 1 || strcmp(buffer, "RIFF")){fclose(File);return false;}//read the main chunk sizeuint32 nChunkSize;if (fread(&nChunkSize, 4, 1, File) != 1){fclose(File);return false;}//read the format and make sure it's "WAVE"if (fread(buffer, 4, 1, File) != 1 || strcmp(buffer, "WAVE")){fclose(File);return false;}long chunkPosFmt = -1;long chunkPosData = -1;while (chunkPosFmt == -1 || chunkPosData == -1){//read a sub chunk id and a chunk size if we canif (fread(buffer, 4, 1, File) != 1 || fread(&nChunkSize, 4, 1, File) != 1){fclose(File);return false;}//if we hit a fmtif (!strcmp(buffer, "fmt ")){chunkPosFmt = ftell(File) - 8;}//else if we hit a dataelse if (!strcmp(buffer, "data")){chunkPosData = ftell(File) - 8;}//skip to the next chunkfseek(File, nChunkSize, SEEK_CUR);}//we'll use this handy struct to load in SMinimalWaveFileHeader waveData;//load the fmt part if we canfseek(File, chunkPosFmt, SEEK_SET);if (fread(&waveData.m_szSubChunk1ID, 24, 1, File) != 1){fclose(File);return false;}//load the data part if we canfseek(File, chunkPosData, SEEK_SET);if (fread(&waveData.m_szSubChunk2ID, 8, 1, File) != 1){fclose(File);return false;}//verify a couple things about the file dataif (waveData.m_nAudioFormat != 1 ||       //only pcm datawaveData.m_nNumChannels < 1 ||        //must have a channelwaveData.m_nNumChannels > 2 ||        //must not have more than 2waveData.m_nBitsPerSample > 32 ||     //32 bits per sample maxwaveData.m_nBitsPerSample % 8 != 0 || //must be a multiple of 8 biteswaveData.m_nBlockAlign > 8)           //blocks must be 8 bytes or lower{fclose(File);return false;}//figure out how many samples and blocks there are total in the source dataint nBytesPerBlock = waveData.m_nBlockAlign;int nNumBlocks = waveData.m_nSubChunk2Size / nBytesPerBlock;int nNumSourceSamples = nNumBlocks * waveData.m_nNumChannels;//allocate space for the source samplessamples.resize(nNumSourceSamples);//maximum size of a block is 8 bytes.  4 bytes per samples, 2 channelsunsigned char pBlockData[8];memset(pBlockData, 0, 8);//read in the source samples at whatever sample rate / number of channels it might be inint nBytesPerSample = nBytesPerBlock / waveData.m_nNumChannels;for (int nIndex = 0; nIndex < nNumSourceSamples; nIndex += waveData.m_nNumChannels){//read in a blockif (fread(pBlockData, waveData.m_nBlockAlign, 1, File) != 1){fclose(File);return false;}//get the first samplesamples[nIndex].Value() = PCMToFloat(pBlockData, nBytesPerSample);//get the second sample if there is oneif (waveData.m_nNumChannels == 2){samples[nIndex + 1].Value() = PCMToFloat(&pBlockData[nBytesPerSample], nBytesPerSample);}}//re-sample the sample rate up or down as neededResampleData(samples, waveData.m_nSampleRate, sampleRate);//handle switching from mono to stereo or vice versaChangeNumChannels(samples, waveData.m_nNumChannels, 1);return true;
}

参阅一:python-he-c++-yin-tiao-yin-fu-gui-hua-he-suan-fa" rel="nofollow">计算思维

参阅二:亚图跨际


http://www.ppmy.cn/news/1437700.html

相关文章

visionTransformer window平台下报错

错误&#xff1a; KeyError: Transformer/encoderblock_0/MlpBlock_3/Dense_0kernel is not a file in the archive解决方法&#xff1a; 修改这个函数即可&#xff0c;主要原因是Linux系统与window系统路径分隔符不一样导致 def load_from(self, weights, n_block):ROOT f&…

使用rust学习基本算法(三)

使用rust学习基本算法&#xff08;三&#xff09; 动态规划 动态规划算法是一种在数学、管理科学、计算机科学和经济学中广泛使用的方法&#xff0c;用于解决具有重叠子问题和最优子结构特性的问题。它通过将复杂问题分解为更小的子问题来解决问题&#xff0c;这些子问题被称为…

第7章 面向对象基础-下(内部类)

7.6 内部类(了解) 7.6.1 概述 1、什么是内部类&#xff1f; 将一个类A定义在另一个类B里面&#xff0c;里面的那个类A就称为内部类&#xff0c;B则称为外部类。 2、为什么要声明内部类呢&#xff1f; 总的来说&#xff0c;遵循高内聚低耦合的面向对象开发总原则。便于代码…

使用Azure AI Search和LlamaIndex构建高级RAG应用

RAG 是一种将公司信息合并到基于大型语言模型 &#xff08;LLM&#xff09; 的应用程序中的常用方法。借助 RAG&#xff0c;AI 应用程序可以近乎实时地访问最新信息&#xff0c;团队可以保持对其数据的控制。 在 RAG 中&#xff0c;您可以评估和修改各个阶段以改进结果&#x…

Node.js -- path模块

path.resolve(常用) // 导入fs const fs require(fs); // 写入文件 fs.writeFileSync(_dirname /index.html,love); console.log(_dirname /index.html);// D:\nodeJS\13-path\代码/index.html 我们之前使用的__dirname 路径 输出的结果前面是正斜杠/ &#xff0c;后面部分是…

acwing算法提高之图论--欧拉回路和欧拉路径

目录 1 介绍2 训练 1 介绍 本专题用来记录欧拉回路和欧拉路径相关的题目。 相关结论&#xff1a; &#xff08;1&#xff09;对于无向图&#xff0c;所有边都是连通的。 &#xff08;1.1&#xff09;存在欧拉路径的充要条件&#xff1a;度数为奇数的结点只能是0个或者2个。 &…

【银角大王——Django课程——创建项目+部门表的基本操作】

Django框架员工管理系统——创建项目部门表管理 员工管理系统创建项目命令行的形式创建Django项目——创建app注册app——在sttings中的INSTALLED_APPS [ ]数组中注册 设计表结构&#xff08;django&#xff09;连接数据库——在settings里面改写DATABASESDjango命令执行生成数…

网贷大数据黑名单要多久才能变正常?

网贷大数据黑名单是指个人在网贷平台申请贷款时&#xff0c;因为信用记录较差而被列入黑名单&#xff0c;无法获得贷款或者贷款额度受到限制的情况。网贷大数据黑名单的具体时间因个人信用状况、所属平台政策以及银行审核标准不同而异&#xff0c;一般来说&#xff0c;需要一定…