1 /*
2 * $Id: debug_sine.c,v 1.1 2006/04/30 16:23:59 jcr13 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
47 #define MSEC_PER_BUFFER (1000 * FRAMES_PER_BUFFER / SAMPLE_RATE)
48
49 #if 0
50 #define MIN_LATENCY_MSEC (200)
51 #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
52 #else
53 #define NUM_BUFFERS (0)
54 #endif
55
56 #define MIN_FREQ (100.0f)
57 #define MAX_FREQ (4000.0f)
58 #define FREQ_SCALAR (1.00002f)
59 #define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
60 #ifndef M_PI
61 #define M_PI (3.14159265)
62 #endif
63 #define TABLE_SIZE (400)
64 typedef struct
65 {
66 float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
67 float phase_increment;
68 float left_phase;
69 float right_phase;
70 unsigned int framesToGo;
71 }
72 paTestData;
73 /* Convert phase between and 1.0 to sine value
74 * using linear interpolation.
75 */
76 float LookupSine( paTestData *data, float phase );
LookupSine(paTestData * data,float phase)77 float LookupSine( paTestData *data, float phase )
78 {
79 float fIndex = phase*TABLE_SIZE;
80 int index = (int) fIndex;
81 float fract = fIndex - index;
82 float lo = data->sine[index];
83 float hi = data->sine[index+1];
84 float val = lo + fract*(hi-lo);
85 return val;
86 }
87 /* This routine will be called by the PortAudio engine when audio is needed.
88 ** It may called at interrupt level on some machines so don't do anything
89 ** that could mess up the system like calling malloc() or free().
90 */
patestCallback(void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,PaTimestamp outTime,void * userData)91 static int patestCallback( void *inputBuffer, void *outputBuffer,
92 unsigned long framesPerBuffer,
93 PaTimestamp outTime, void *userData )
94 {
95 paTestData *data = (paTestData*)userData;
96 float *out = (float*)outputBuffer;
97 int framesToCalc;
98 int i;
99 int finished = 0;
100 (void) outTime; /* Prevent unused variable warnings. */
101 (void) inputBuffer;
102
103 if( data->framesToGo < framesPerBuffer )
104 {
105 framesToCalc = data->framesToGo;
106 data->framesToGo = 0;
107 finished = 1;
108 }
109 else
110 {
111 framesToCalc = framesPerBuffer;
112 data->framesToGo -= framesPerBuffer;
113 }
114
115 for( i=0; i<framesToCalc; i++ )
116 {
117 *out++ = LookupSine(data, data->left_phase); /* left */
118 *out++ = LookupSine(data, data->right_phase); /* right */
119 data->left_phase += data->phase_increment;
120 if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
121 data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
122 if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
123 /* sweep frequency then start over. */
124 data->phase_increment *= FREQ_SCALAR;
125 if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
126 }
127 /* zero remainder of final buffer */
128 for( ; i<(int)framesPerBuffer; i++ )
129 {
130 *out++ = 0; /* left */
131 *out++ = 0; /* right */
132 }
133 // Pa_Sleep( 3 * MSEC_PER_BUFFER / 4 );
134 // Pa_Sleep( MSEC_PER_BUFFER / 3 );
135
136 return finished;
137 }
138 /*******************************************************************/
139 int main(void);
main(void)140 int main(void)
141 {
142 PortAudioStream *stream;
143 PaError err;
144 paTestData data;
145 int i;
146 int totalSamps;
147 printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS );
148 printf("MSEC_PER_BUFFER = %d\n", MSEC_PER_BUFFER );
149
150 /* initialise sinusoidal wavetable */
151 for( i=0; i<TABLE_SIZE; i++ )
152 {
153 data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
154 }
155 data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
156 data.left_phase = data.right_phase = 0.0;
157 data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
158 data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
159 printf("totalSamps = %d\n", totalSamps );
160 err = Pa_Initialize();
161 if( err != paNoError ) goto error;
162 printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
163 err = Pa_OpenStream(
164 &stream,
165 paNoDevice,
166 0, /* no input */
167 paFloat32, /* 32 bit floating point input */
168 NULL,
169 OUTPUT_DEVICE,
170 2, /* stereo output */
171 paFloat32, /* 32 bit floating point output */
172 NULL,
173 SAMPLE_RATE,
174 FRAMES_PER_BUFFER,
175 NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
176 paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
177 patestCallback,
178 &data );
179 if( err != paNoError ) goto error;
180 err = Pa_StartStream( stream );
181 if( err != paNoError ) goto error;
182 printf("Is callback being called?\n");
183 for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
184 {
185 printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
186 Pa_Sleep( SLEEP_DUR );
187 }
188 /* Stop sound until ENTER hit. */
189 printf("Call Pa_StopStream()\n");
190 err = Pa_StopStream( stream );
191 if( err != paNoError ) goto error;
192 Pa_Terminate();
193 printf("Test finished.\n");
194 return err;
195 error:
196 Pa_Terminate();
197 fprintf( stderr, "An error occured while using the portaudio stream\n" );
198 fprintf( stderr, "Error number: %d\n", err );
199 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
200 return err;
201 }
202