Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // adapted from:
- // alsa090_pcm_seq_howto.txt 0.0.4 by Matthias Nagorni
- // compile/run with: gcc -o pcm pcm.c -lasound && ./pcm
- #include <stdio.h>
- #include <stdlib.h>
- #include <alsa/asoundlib.h>
- #include <math.h>
- int main() {
- /* Handle for the PCM device */
- snd_pcm_t *pcm_handle;
- /* Playback stream */
- snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
- /* This structure contains information about */
- /* the hardware and can be used to specify the */
- /* configuration to be used for the PCM stream. */
- snd_pcm_hw_params_t *hwparams;
- /* Name of the PCM device, like plughw:0,0 */
- /* The first number is the number of the soundcard, */
- /* the second number is the number of the device. */
- char *pcm_name = "plughw:0,0" ;
- /* Init pcm_name. Of course, later you */
- /* will make this configurable ;-) */
- //pcm_name = strdup("plughw:0,0");
- /* Allocate the snd_pcm_hw_params_t structure on the stack. */
- snd_pcm_hw_params_alloca(&hwparams);
- /* Open PCM. The last parameter of this function is the mode. */
- /* If this is set to 0, the standard mode is used. Possible */
- /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
- /* If SND_PCM_NONBLOCK is used, read / write access to the */
- /* PCM device will return immediately. If SND_PCM_ASYNC is */
- /* specified, SIGIO will be emitted whenever a period has */
- /* been completely processed by the soundcard. */
- if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
- fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
- return(-1);
- }
- /* Init hwparams with full configuration space */
- if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
- fprintf(stderr, "Can not configure this PCM device.\n");
- return(-1);
- }
- int rate = 44100; /* Sample rate */
- int exact_rate; /* Sample rate returned by */
- /* snd_pcm_hw_params_set_rate_near */
- int dir; /* exact_rate == rate --> dir = 0 */
- /* exact_rate < rate --> dir = -1 */
- /* exact_rate > rate --> dir = 1 */
- int periods = 2; /* Number of periods */
- snd_pcm_uframes_t periodsize = 8192; /* Periodsize (bytes) */
- /* Set access type. This can be either */
- /* SND_PCM_ACCESS_RW_INTERLEAVED or */
- /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
- /* There are also access types for MMAPed */
- /* access, but this is beyond the scope */
- /* of this introduction. */
- if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- fprintf(stderr, "Error setting access.\n");
- return(-1);
- }
- /* Set sample format */
- if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
- fprintf(stderr, "Error setting format.\n");
- return(-1);
- }
- /* Set sample rate. If the exact rate is not supported */
- /* by the hardware, use nearest possible rate. */
- exact_rate = rate;
- if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0) {
- fprintf(stderr, "Error setting rate.\n");
- return(-1);
- }
- if (rate != exact_rate) {
- fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n "
- " ==> Using %d Hz instead.\n", rate, exact_rate);
- }
- /* Set number of channels */
- if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
- fprintf(stderr, "Error setting channels.\n");
- return(-1);
- }
- /* Set number of periods. Periods used to be called fragments. */
- if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) {
- fprintf(stderr, "Error setting periods.\n");
- return(-1);
- }
- /* Set buffer size (in frames). The resulting latency is given by */
- /* latency = periodsize * periods / (rate * bytes_per_frame) */
- if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods)>>2) < 0) {
- fprintf(stderr, "Error setting buffersize.\n");
- return(-1);
- }
- /* Apply HW parameter settings to */
- /* PCM device and prepare device */
- if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
- fprintf(stderr, "Error setting HW params.\n");
- return(-1);
- }
- //~ /* Write num_frames frames from buffer data to */
- //~ /* the PCM device pointed to by pcm_handle. */
- //~ /* Returns the number of frames actually written. */
- //~ snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, num_frames);
- //~ /* Write num_frames frames from buffer data to */
- //~ /* the PCM device pointed to by pcm_handle. */
- //~ /* Returns the number of frames actually written. */
- //~ snd_pcm_sframes_t snd_pcm_writen(pcm_handle, data, num_frames);
- //envelopes
- // attack, decay, release are times. sustain is a level.
- // dur is the note duration at the sustain level. (ie. key hold time)
- double envelope(double t, double attack, double decay,
- double sustain, double dur, double release)
- {
- double t0;
- t0 = attack + decay + dur + release;
- if (t > t0) return(0.0);
- t0 = t0 - release;
- if (t > t0) return(sustain*(1.0-((t-t0)/release)));
- t0 = t0 - dur;
- if (t > t0) return(sustain);
- t0 = t0 - decay;
- if (t > t0) return(1.0 - (1.0-sustain)*(t-t0)/decay);
- return(t/attack);
- }
- //~ // unsigned char *data;
- int pcmreturn, l1, l2;
- short s1, s2;
- // alsa buffer frame number 4096 = 0.093 sec
- int frames = 4096;
- // ~5sec = ~50 alsa buffers
- int abn = 50;
- int totframes = abn * frames;
- // data is the global buffer (n * alsabuffer size)
- short data[abn * frames * 2];
- double gain = 25000.0;
- double freq=280.0;
- double twopi=(2.0*M_PI/44100.0);
- double pitch=freq*twopi;
- double env = 1.0;
- double mod = 1.0;
- double shift = 0.0;
- double envdecr = 1.0 *1 / 44100.0;
- printf("frames = %d\n", frames);
- double phi = 0.0;
- double phimod = 0.0;
- double dphi, dphimod;
- //~ double har = 7.0;
- //~ double subhar = 9.0;
- //~ double modn = 3.5;
- double har = 3.0;
- double subhar = 9.0;
- double modn = 0.5;
- double nt = 0.0;
- //fill buffer
- dphi = M_PI * freq / 22050.0;
- dphimod = dphi * har / subhar;
- short x = 0;
- for(l2 = 0; l2 < totframes; l2++) {
- if (l2%44100 == 0) {
- nt = 0.0;
- freq = freq - 20;
- dphi = M_PI * freq / 22050.0;
- dphimod = dphi * har / subhar;
- }
- nt = nt + 1.0/44100.0;
- env = envelope(nt, 0.03, 0.3, 0.6, 0.2, 0.4);
- // incr angle
- phi += dphi ;
- if (phi > 2.0 * M_PI) phi -= 2.0 * M_PI;
- phimod += dphimod ;
- if (phimod > 2.0 * M_PI) phimod -= 2.0 * M_PI;
- mod = 1.0 + 0.2*sin((1.0*l2)*12.0*twopi);
- shift = 0.01 * sin((1.0*l2)*1.0*twopi);
- s1 = (short) (gain * env * mod
- * sin(phi + modn * sin(phimod)));
- //~ s1 += 50; s1 = s1 % 15000;
- //~ s1 = (l2 % (100)) * 100 - 5000;
- //~ x = x % 55; x++ ; s1 = (x<50)? -5000 : +5000 ;
- //~ printf("%15.6f %15.6f\n", shift, freq*(1.0+shift));
- //~ data[2*l2] = s1 * (0.5 + mod/2.0);
- //~ data[2*l2+1] = s1 * (mod);
- data[2*l2] = s1;
- data[2*l2+1] = s1;
- }
- for(l1 = 0; l1 < 50; l1++) {
- //~ printf("l1 = %d\n", l1);
- while ((pcmreturn = snd_pcm_writei(pcm_handle,
- (data+(frames*l1*2)) , frames)) < 0) {
- snd_pcm_prepare(pcm_handle);
- fprintf(stderr, "<<<Buffer Underrun>>> l1 = %d\n", l1);
- }
- }
- /* Stop PCM device and drop pending frames */
- snd_pcm_drop(pcm_handle);
- /* Stop PCM device after pending frames have been played */
- snd_pcm_drain(pcm_handle);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement