Advertisement
Kaelygon

terrible tone generator

Jul 3rd, 2023 (edited)
1,022
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.79 KB | None | 0 0
  1. //Tone Generator
  2. #include <SDL2/SDL.h>
  3. #include <fstream>
  4. #include "kaelWaveforms.h"
  5. #include <iostream>
  6. #include <vector>
  7. #include <algorithm>
  8.  
  9. uint8_t AMPLITUDE = 1<<sizeof(AMPLITUDE)*7;
  10. const uint channels = 2;
  11. const uint16_t SAMPLE_RATE = 32768;
  12. const uint16_t FREQUENCY = 1;
  13.  
  14.  
  15.  
  16. //order does not matter in enum or map
  17. enum class WaveformKey {
  18.     csine,
  19.     noise,
  20.     pulse,
  21.     saw,
  22.     sine,
  23.     square,
  24.     triangle
  25. };
  26.  
  27. std::map<std::string, WaveformKey> waveformKeyMap{
  28.     {"csine", WaveformKey::csine},
  29.     {"noise", WaveformKey::noise},
  30.     {"pulse", WaveformKey::pulse},
  31.     {"saw", WaveformKey::saw},
  32.     {"sine", WaveformKey::sine},
  33.     {"square", WaveformKey::square},
  34.     {"triangle", WaveformKey::triangle}
  35. };
  36.  
  37. //I gave up trying to get functional, lambdas, variadic and fucntion pointers to work
  38.  
  39. //Waveform functions
  40. template <typename T, typename T2>
  41. T waveformFunction(WaveformKey index, T2 num, T arg0 = 0, T arg1 = 0) {
  42.     switch (index) {
  43.         case WaveformKey::csine:
  44.             return ukaelCSine<T>(num);
  45.         case WaveformKey::noise:
  46.             return ukaelNoise<T, T2>(num);
  47.         case WaveformKey::pulse:
  48.             return ukaelPulse<T>(num, arg0);
  49.         case WaveformKey::saw:
  50.             return ukaelSaw<T>(num);
  51.         case WaveformKey::sine:
  52.             return ukaelSine<T>(num);
  53.         case WaveformKey::square:
  54.             return ukaelSquare<T>(num);
  55.         case WaveformKey::triangle:
  56.             return ukaelTriangle<T>(num);
  57.         default:
  58.             return T(0);
  59.     }
  60. }
  61.  
  62. //generate and store waveform to buffer. 16, 32 and 64 bit varaints require bug fixing
  63. //waveform template <return type, input type>
  64. template <typename T, typename U>
  65. void generateTone(T* buffer, const ufrac<uint32_t>& freq, uint64_t length, std::string waveformKey, T arg0=0, T arg1=0) {
  66.     WaveformKey enumKey = waveformKeyMap[waveformKey];  //find key index
  67.     T value;
  68.  
  69.     for (uint64_t i = 0; i < length; ++i) {
  70.         value = waveformFunction<T,U>(enumKey,(i/freq.a*freq.b),arg0,arg1); //call generator function for each sample
  71.         value = value * (T)AMPLITUDE / ((T)~0) + (((T)~0) - (T)AMPLITUDE) / 2; // amplitude
  72.         buffer[i] = static_cast<T>(value);  //store to buffer
  73.     }
  74.     return;
  75. }
  76.  
  77. int main() {
  78.     AMPLITUDE=1<<sizeof(AMPLITUDE)*5; //1/8 that your ears don't bleed in preview
  79.  
  80.     SDL_Init(SDL_INIT_AUDIO);
  81.  
  82.     SDL_AudioSpec auspec;
  83.     auspec.freq = SAMPLE_RATE;
  84.     auspec.format = AUDIO_U8;
  85.     auspec.channels = 2;
  86.     auspec.callback = nullptr;
  87.  
  88.     SDL_AudioSpec obtainedSpec;
  89.     SDL_OpenAudio(&auspec, &obtainedSpec);
  90.  
  91.     uint64_t csamples = 32768;  //generated samples per channel
  92.     uint64_t mixedSize = csamples*auspec.channels;  //mixed channel size
  93.     uint64_t channelSize = csamples;    //single channel size
  94.  
  95.     uint16_t mixChannels=7; //mixing channels
  96.     mixedSize*=mixChannels;
  97.  
  98.     //init vector
  99.     std::vector<std::vector<uint8_t>> channel(mixChannels);
  100.     for (uint i = 0; i < mixChannels; ++i) {
  101.         channel[i].resize(channelSize);
  102.     }
  103.  
  104.  
  105.     uint8_t arg0=32;    //argument for pulse tone
  106.     int ci=0;   //channel index
  107.     //generate 1 second of all functions
  108.     for (const auto& pair : waveformKeyMap) {
  109.         const std::string& key = pair.first;    //find tested function
  110.         generateTone<uint8_t,uint16_t>(channel[ci++].data(), ufrac{1U, 1U}, channelSize, key,arg0);
  111.     }
  112.  
  113.     //mixed channel
  114.     std::vector<uint8_t> mixed(mixedSize);
  115.  
  116.     //concat
  117.     for (const auto& c : channel) {
  118.         mixed.insert(mixed.end(), c.begin(), c.end());
  119.     }
  120.  
  121.     try {//clear file
  122.         std::ofstream audioRaw("audio.raw", std::ios::binary);
  123.         audioRaw<<0;  
  124.         audioRaw.close();
  125.     } catch (const std::exception& e) {
  126.         std::cerr << "Failed to write audio file: " << e.what() << std::endl;
  127.     }
  128.  
  129.     mixed.resize(auspec.channels*channelSize);
  130.     for (int k=0; k<mixChannels;k+=1) {
  131.  
  132.         // mono to stereo
  133.         for (uint64_t i = 0; i < channelSize; i++ ) {
  134.             for(int j=0;j<auspec.channels;j++){
  135.                 mixed[ auspec.channels * i + 0 ] = channel[k][i];
  136.                 mixed[ auspec.channels * i + j ] = channel[k][i];
  137.             }
  138.         }
  139.        
  140.         try {//print to file
  141.             std::ofstream audioRaw("audio.raw", std::ios::binary | std::ios::app);
  142.             audioRaw.write(reinterpret_cast<const char*>(mixed.data()), auspec.channels*channelSize);  
  143.             audioRaw.close();
  144.         } catch (const std::exception& e) {
  145.             std::cerr << "Failed to write audio file: " << e.what() << std::endl;
  146.         }
  147.  
  148.         // Queue the audio buffer
  149.         SDL_QueueAudio(1, mixed.data(), auspec.channels*channelSize);
  150.         // Start audio playback
  151.         SDL_PauseAudio(0);  
  152.  
  153.     }
  154.  
  155.     uint waitTime = 1000*channelSize*mixChannels;
  156.  
  157.     SDL_Delay(waitTime/SAMPLE_RATE);
  158.  
  159.     SDL_PauseAudio(1);
  160.  
  161.     // Delete the 2D vector
  162.     for (size_t i = 0; i < channel.size(); ++i) {
  163.         channel[i].clear();  // Clear the individual row vector
  164.     }
  165.     channel.clear();  // Clear the outer vector
  166.  
  167.     mixed.clear();
  168.  
  169.     return 0;
  170. }
  171.  
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement