1 /*
2 * $Id: debug_sine.c,v 1.1 2006/06/10 21:30:56 dmazzoni Exp $
3 * debug_sine.c
4 * Play a sine sweep using the Portable Audio api for several seconds.
5 * Hacked test for debugging PA.
6 *
7 * Author: Phil Burk <philburk@softsynth.com>
8 *
9 * This program uses the PortAudio Portable Audio Library.
10 * For more information see: http://www.portaudio.com
11 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files
15 * (the "Software"), to deal in the Software without restriction,
16 * including without limitation the rights to use, copy, modify, merge,
17 * publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so,
19 * subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * Any person wishing to distribute modifications to the Software is
25 * requested to send the modifications to the original developer so that
26 * they can be incorporated into the canonical version.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
32 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
33 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 *
36 */
37 #include <stdio.h>
38 #include <math.h>
39 #include "portaudio.h"
40 #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
41 //#define OUTPUT_DEVICE (11)
42 #define NUM_SECONDS (8)
43 #define SLEEP_DUR (800)
44 #define SAMPLE_RATE (44100)
45 #define FRAMES_PER_BUFFER (256)
46 #if 0
47 #define MIN_LATENCY_MSEC (200)
48 #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
49 #else
50 #define NUM_BUFFERS (0)
51 #endif
52 #define MIN_FREQ (100.0f)
53 #define MAX_FREQ (4000.0f)
54 #define FREQ_SCALAR (1.00002f)
55 #define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
56 #ifndef M_PI
57 #define M_PI (3.14159265)
58 #endif
59 #define TABLE_SIZE (400)
60 typedef struct
61 {
62 float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
63 float phase_increment;
64 float left_phase;
65 float right_phase;
66 unsigned int framesToGo;
67 }
68 paTestData;
69 /* Convert phase between and 1.0 to sine value
70 * using linear interpolation.
71 */
72 float LookupSine( paTestData *data, float phase );
LookupSine(paTestData * data,float phase)73 float LookupSine( paTestData *data, float phase )
74 {
75 float fIndex = phase*TABLE_SIZE;
76 int index = (int) fIndex;
77 float fract = fIndex - index;
78 float lo = data->sine[index];
79 float hi = data->sine[index+1];
80 float val = lo + fract*(hi-lo);
81 return val;
82 }
83 /* This routine will be called by the PortAudio engine when audio is needed.
84 ** It may called at interrupt level on some machines so don't do anything
85 ** that could mess up the system like calling malloc() or free().
86 */
patestCallback(void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,PaTimestamp outTime,void * userData)87 static int patestCallback( void *inputBuffer, void *outputBuffer,
88 unsigned long framesPerBuffer,
89 PaTimestamp outTime, void *userData )
90 {
91 paTestData *data = (paTestData*)userData;
92 float *out = (float*)outputBuffer;
93 int framesToCalc;
94 int i;
95 int finished = 0;
96 (void) outTime; /* Prevent unused variable warnings. */
97 (void) inputBuffer;
98
99 if( data->framesToGo < framesPerBuffer )
100 {
101 framesToCalc = data->framesToGo;
102 data->framesToGo = 0;
103 finished = 1;
104 }
105 else
106 {
107 framesToCalc = framesPerBuffer;
108 data->framesToGo -= framesPerBuffer;
109 }
110
111 for( i=0; i<framesToCalc; i++ )
112 {
113 *out++ = LookupSine(data, data->left_phase); /* left */
114 *out++ = LookupSine(data, data->right_phase); /* right */
115 data->left_phase += data->phase_increment;
116 if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
117 data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
118 if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
119 /* sweep frequency then start over. */
120 data->phase_increment *= FREQ_SCALAR;
121 if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
122 }
123 /* zero remainder of final buffer */
124 for( ; i<(int)framesPerBuffer; i++ )
125 {
126 *out++ = 0; /* left */
127 *out++ = 0; /* right */
128 }
129 return finished;
130 }
131 /*******************************************************************/
132 int main(void);
main(void)133 int main(void)
134 {
135 PortAudioStream *stream;
136 PaError err;
137 paTestData data;
138 int i;
139 int totalSamps;
140 printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS );
141 /* initialise sinusoidal wavetable */
142 for( i=0; i<TABLE_SIZE; i++ )
143 {
144 data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
145 }
146 data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
147 data.left_phase = data.right_phase = 0.0;
148 data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
149 data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
150 printf("totalSamps = %d\n", totalSamps );
151 err = Pa_Initialize();
152 if( err != paNoError ) goto error;
153 printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
154 err = Pa_OpenStream(
155 &stream,
156 paNoDevice,
157 0, /* no input */
158 paFloat32, /* 32 bit floating point input */
159 NULL,
160 OUTPUT_DEVICE,
161 2, /* stereo output */
162 paFloat32, /* 32 bit floating point output */
163 NULL,
164 SAMPLE_RATE,
165 FRAMES_PER_BUFFER,
166 NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
167 paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
168 patestCallback,
169 &data );
170 if( err != paNoError ) goto error;
171 err = Pa_StartStream( stream );
172 if( err != paNoError ) goto error;
173 printf("Is callback being called?\n");
174 for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
175 {
176 printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
177 Pa_Sleep( SLEEP_DUR );
178 }
179 /* Stop sound until ENTER hit. */
180 printf("Call Pa_StopStream()\n");
181 err = Pa_StopStream( stream );
182 if( err != paNoError ) goto error;
183 Pa_Terminate();
184 printf("Test finished.\n");
185 return err;
186 error:
187 Pa_Terminate();
188 fprintf( stderr, "An error occured while using the portaudio stream\n" );
189 fprintf( stderr, "Error number: %d\n", err );
190 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
191 return err;
192 }
193