Advertisement
Guest User

Untitled

a guest
Sep 19th, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.17 KB | None | 0 0
  1. // adapted from:
  2. // alsa090_pcm_seq_howto.txt 0.0.4 by Matthias Nagorni
  3. // compile/run with:  gcc -o pcm pcm.c -lasound && ./pcm
  4.  
  5. #include <stdio.h>  
  6. #include <stdlib.h>
  7. #include <alsa/asoundlib.h>
  8. #include <math.h>
  9.  
  10. int main() {
  11.    
  12. /* Handle for the PCM device */
  13.  
  14. snd_pcm_t *pcm_handle;          
  15.  
  16. /* Playback stream */
  17.  
  18. snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
  19.  
  20. /* This structure contains information about    */
  21. /* the hardware and can be used to specify the  */      
  22. /* configuration to be used for the PCM stream. */
  23.  
  24. snd_pcm_hw_params_t *hwparams;
  25.  
  26. /* Name of the PCM device, like plughw:0,0          */
  27. /* The first number is the number of the soundcard, */
  28. /* the second number is the number of the device.   */
  29.  
  30. char *pcm_name = "plughw:0,0" ;
  31.  
  32. /* Init pcm_name. Of course, later you */
  33. /* will make this configurable ;-)     */
  34. //pcm_name = strdup("plughw:0,0");
  35.  
  36.  
  37. /* Allocate the snd_pcm_hw_params_t structure on the stack. */
  38. snd_pcm_hw_params_alloca(&hwparams);
  39.  
  40.  
  41. /* Open PCM. The last parameter of this function is the mode. */
  42. /* If this is set to 0, the standard mode is used. Possible   */
  43. /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
  44. /* If SND_PCM_NONBLOCK is used, read / write access to the    */
  45. /* PCM device will return immediately. If SND_PCM_ASYNC is    */
  46. /* specified, SIGIO will be emitted whenever a period has     */
  47. /* been completely processed by the soundcard.                */
  48. if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
  49.   fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
  50.   return(-1);
  51. }
  52.  
  53. /* Init hwparams with full configuration space */
  54. if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
  55.   fprintf(stderr, "Can not configure this PCM device.\n");
  56.   return(-1);
  57. }
  58.  
  59. int rate = 44100; /* Sample rate */
  60. int exact_rate;   /* Sample rate returned by */
  61.                   /* snd_pcm_hw_params_set_rate_near */
  62. int dir;          /* exact_rate == rate --> dir = 0 */
  63.                   /* exact_rate < rate  --> dir = -1 */
  64.                   /* exact_rate > rate  --> dir = 1 */
  65. int periods = 2;       /* Number of periods */
  66. snd_pcm_uframes_t periodsize = 8192; /* Periodsize (bytes) */
  67.  
  68.  
  69. /* Set access type. This can be either    */
  70. /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
  71. /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
  72. /* There are also access types for MMAPed */
  73. /* access, but this is beyond the scope   */
  74. /* of this introduction.                  */
  75. if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
  76.   fprintf(stderr, "Error setting access.\n");
  77.   return(-1);
  78. }
  79.  
  80. /* Set sample format */
  81. if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
  82.   fprintf(stderr, "Error setting format.\n");
  83.   return(-1);
  84. }
  85.  
  86. /* Set sample rate. If the exact rate is not supported */
  87. /* by the hardware, use nearest possible rate.         */
  88. exact_rate = rate;
  89. if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0) {
  90.   fprintf(stderr, "Error setting rate.\n");
  91.   return(-1);
  92. }
  93. if (rate != exact_rate) {
  94.   fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n "
  95.                   " ==> Using %d Hz instead.\n", rate, exact_rate);
  96. }
  97.  
  98. /* Set number of channels */
  99. if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
  100.   fprintf(stderr, "Error setting channels.\n");
  101.   return(-1);
  102. }
  103.  
  104. /* Set number of periods. Periods used to be called fragments. */
  105. if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) {
  106.   fprintf(stderr, "Error setting periods.\n");
  107.   return(-1);
  108. }
  109.  
  110.  
  111. /* Set buffer size (in frames). The resulting latency is given by */
  112. /* latency = periodsize * periods / (rate * bytes_per_frame)     */
  113. if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods)>>2) < 0) {
  114.   fprintf(stderr, "Error setting buffersize.\n");
  115.   return(-1);
  116. }
  117.  
  118.  
  119. /* Apply HW parameter settings to */
  120. /* PCM device and prepare device  */
  121. if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
  122.   fprintf(stderr, "Error setting HW params.\n");
  123.   return(-1);
  124. }
  125.  
  126. //~ /* Write num_frames frames from buffer data to    */
  127. //~ /* the PCM device pointed to by pcm_handle.       */
  128. //~ /* Returns the number of frames actually written. */
  129. //~ snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, num_frames);
  130.  
  131.  
  132. //~ /* Write num_frames frames from buffer data to    */
  133. //~ /* the PCM device pointed to by pcm_handle.       */
  134. //~ /* Returns the number of frames actually written. */
  135. //~ snd_pcm_sframes_t snd_pcm_writen(pcm_handle, data, num_frames);
  136.  
  137. //envelopes
  138. // attack, decay, release are times. sustain is a level.
  139. // dur is the note duration at the sustain level. (ie. key hold time)
  140. double envelope(double t, double attack, double decay,
  141.     double sustain, double dur, double release)
  142. {
  143.     double t0;
  144.     t0 = attack + decay + dur + release;
  145.     if (t > t0) return(0.0);
  146.     t0 = t0 - release;
  147.     if (t > t0) return(sustain*(1.0-((t-t0)/release)));
  148.     t0 = t0 - dur;
  149.     if (t > t0) return(sustain);
  150.     t0 = t0 - decay;
  151.     if (t > t0) return(1.0 - (1.0-sustain)*(t-t0)/decay);
  152.     return(t/attack);
  153. }
  154.  
  155. //~ // unsigned char *data;
  156. int pcmreturn, l1, l2;
  157. short s1, s2;
  158. // alsa buffer frame number 4096 = 0.093 sec
  159. int frames = 4096;
  160. // ~5sec = ~50 alsa buffers
  161. int abn = 50;
  162. int totframes = abn * frames;
  163. // data is the global buffer (n * alsabuffer size)
  164. short data[abn * frames * 2];
  165.  
  166. double gain = 25000.0;
  167. double freq=280.0;
  168. double twopi=(2.0*M_PI/44100.0);
  169. double pitch=freq*twopi;
  170. double env = 1.0;
  171. double mod = 1.0;
  172. double shift = 0.0;
  173. double envdecr = 1.0 *1 / 44100.0;
  174. printf("frames = %d\n", frames);
  175. double phi = 0.0;
  176. double phimod = 0.0;
  177. double dphi, dphimod;
  178. //~ double har = 7.0;
  179. //~ double subhar = 9.0;
  180. //~ double modn = 3.5;
  181. double har = 3.0;
  182. double subhar = 9.0;
  183. double modn = 0.5;
  184. double nt = 0.0;
  185.  
  186. //fill buffer
  187. dphi = M_PI * freq / 22050.0;
  188. dphimod = dphi * har / subhar;
  189. short x = 0;
  190.   for(l2 = 0; l2 < totframes; l2++) {
  191.     if (l2%44100 == 0) {
  192.         nt = 0.0;
  193.         freq = freq - 20;
  194.         dphi = M_PI * freq / 22050.0;  
  195.         dphimod = dphi * har / subhar;
  196.     }
  197.     nt = nt + 1.0/44100.0;
  198.     env = envelope(nt, 0.03, 0.3, 0.6, 0.2, 0.4);
  199.     // incr angle
  200.     phi += dphi ;  
  201.     if (phi > 2.0 * M_PI) phi -= 2.0 * M_PI;
  202.     phimod += dphimod ;    
  203.     if (phimod > 2.0 * M_PI) phimod -= 2.0 * M_PI;
  204.     mod = 1.0 + 0.2*sin((1.0*l2)*12.0*twopi);
  205.     shift = 0.01 * sin((1.0*l2)*1.0*twopi);
  206.     s1 = (short) (gain * env * mod
  207.                 * sin(phi + modn * sin(phimod)));
  208.     //~ s1 += 50; s1 = s1 % 15000;
  209.     //~ s1 = (l2 % (100)) * 100 - 5000;
  210.     //~ x = x % 55; x++ ; s1 = (x<50)? -5000 : +5000 ;
  211.     //~ printf("%15.6f  %15.6f\n", shift, freq*(1.0+shift));
  212.     //~ data[2*l2] = s1 * (0.5 + mod/2.0);
  213.     //~ data[2*l2+1] = s1 * (mod);
  214.     data[2*l2] = s1;
  215.     data[2*l2+1] = s1;
  216.   }
  217.  
  218. for(l1 = 0; l1 < 50; l1++) {
  219.   //~ printf("l1 = %d\n", l1);
  220.   while ((pcmreturn = snd_pcm_writei(pcm_handle,
  221.                     (data+(frames*l1*2)) , frames)) < 0) {
  222.     snd_pcm_prepare(pcm_handle);
  223.            
  224.     fprintf(stderr, "<<<Buffer Underrun>>> l1 = %d\n", l1);
  225.   }
  226. }
  227.  
  228.  
  229. /* Stop PCM device and drop pending frames */
  230. snd_pcm_drop(pcm_handle);
  231.  
  232. /* Stop PCM device after pending frames have been played */
  233. snd_pcm_drain(pcm_handle);
  234.  
  235.  
  236. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement