├── .gitignore ├── LICENSE ├── NodeCoreAudio ├── .vs │ └── NodeCoreAudio │ │ └── v15 │ │ ├── .suo │ │ └── Browse.VC.db ├── AudioEngine.cpp ├── AudioEngine.h ├── NodeCoreAudio.cpp ├── NodeCoreAudio.vcxproj ├── NodeCoreAudio.vcxproj.filters ├── NodeCoreAudio.vcxproj.user ├── dllmain.cpp ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── README.md ├── binding.gyp ├── examples └── standalone_waveform_visualizer │ ├── app.js │ └── package.json ├── gyp └── lib │ ├── libportaudio.a │ ├── win32 │ ├── portaudio_x86.dll │ ├── portaudio_x86.exp │ └── portaudio_x86.lib │ └── win64 │ ├── portaudio_x64.dll │ ├── portaudio_x64.exp │ └── portaudio_x64.lib ├── node-core-audio.js ├── package-lock.json ├── package.json └── portaudio └── portaudio.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | Debug/ 3 | Release/ 4 | ipch/ 5 | Test/ 6 | node_modules/ 7 | NodeCoreAudio.suo 8 | NodeCoreAudio.opensdf 9 | NodeCoreAudio.sdf 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT license 2 | 3 | Copyright (c) by Mike Vegeto and contributors (see package.json) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /NodeCoreAudio/.vs/NodeCoreAudio/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/NodeCoreAudio/.vs/NodeCoreAudio/v15/.suo -------------------------------------------------------------------------------- /NodeCoreAudio/.vs/NodeCoreAudio/v15/Browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/NodeCoreAudio/.vs/NodeCoreAudio/v15/Browse.VC.db -------------------------------------------------------------------------------- /NodeCoreAudio/AudioEngine.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // AudioEngine.cpp: Core audio functionality 4 | // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | // DevStudio!namespace Audio DevStudio!class AudioEngine 7 | 8 | 9 | #include "AudioEngine.h" 10 | #include "portaudio.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef __linux__ 18 | #include 19 | #include 20 | #endif 21 | 22 | #ifdef __APPLE__ 23 | #include 24 | #endif 25 | 26 | using namespace v8; using namespace std; 27 | 28 | Persistent Audio::AudioEngine::constructor; 29 | 30 | static void do_work( void* arg ) { 31 | Audio::AudioEngine* pEngine = (Audio::AudioEngine*)arg; 32 | pEngine->RunAudioLoop(); 33 | } 34 | 35 | 36 | ////////////////////////////////////////////////////////////////////////////// 37 | /*! Initialize */ 38 | 39 | Audio::AudioEngine::AudioEngine( Local options ) : 40 | m_uSampleSize(4), 41 | m_pIsolate(Isolate::GetCurrent()), 42 | m_pLocker(new Locker(Isolate::GetCurrent())) { 43 | 44 | 45 | PaError openStreamErr; 46 | m_pPaStream = NULL; 47 | 48 | //set defaults 49 | m_uInputChannels = 2; 50 | m_uOutputChannels = 2; 51 | m_uSamplesPerBuffer = DEFAULT_FRAMES_PER_BUFFER; 52 | m_uNumCachedOutputSamples = 0; 53 | m_uSampleFormat = 1; 54 | m_uNumBuffers = DEFAULT_NUM_BUFFERS; 55 | m_bInterleaved = false; 56 | m_bReadMicrophone = true; 57 | 58 | m_uSampleRate = DEFAULT_SAMPLE_RATE; 59 | 60 | m_cachedInputSampleBlock = NULL; 61 | m_cachedOutputSampleBlock = NULL; 62 | m_cachedOutputSampleBlockForWriting = NULL; 63 | 64 | m_bInputOverflowed = 0; 65 | m_bOutputUnderflowed = 0; 66 | 67 | m_uCurrentWriteBuffer = 0; 68 | m_uCurrentReadBuffer = 0; 69 | 70 | // Create V8 objects to hold our buffers 71 | m_hInputBuffer = Nan::New( m_uInputChannels ); 72 | for( int iChannel=0; iChannelSet(this->m_pIsolate->GetCurrentContext(), iChannel, Nan::New(m_uSamplesPerBuffer) ); 74 | 75 | // Initialize our audio core 76 | PaError initErr = Pa_Initialize(); 77 | 78 | m_uInputDevice = Pa_GetDefaultInputDevice(); 79 | if( m_uInputDevice == paNoDevice ) { 80 | Nan::ThrowTypeError("Error: No default input device"); 81 | }; 82 | 83 | m_uOutputDevice = Pa_GetDefaultOutputDevice(); 84 | if( m_uOutputDevice == paNoDevice ) { 85 | Nan::ThrowTypeError("Error: No default output device"); 86 | } 87 | 88 | if( initErr != paNoError ) 89 | Nan::ThrowTypeError("Failed to initialize audio engine"); 90 | 91 | applyOptions( options ); 92 | 93 | fprintf( stderr, "input :%d\n", m_uInputDevice ); 94 | fprintf( stderr, "output :%d\n", m_uOutputDevice ); 95 | fprintf( stderr, "rate :%d\n", m_uSampleRate ); 96 | fprintf( stderr, "format :%d\n", m_uSampleFormat ); 97 | fprintf( stderr, "size :%ld\n", sizeof(float) ); 98 | fprintf( stderr, "inputChannels :%d\n", m_uInputChannels ); 99 | fprintf( stderr, "outputChannels :%d\n", m_uOutputChannels ); 100 | fprintf( stderr, "interleaved :%d\n", m_bInterleaved ); 101 | fprintf( stderr, "uses input: %d\n", m_bReadMicrophone); 102 | 103 | // Open an audio I/O stream. 104 | openStreamErr = Pa_OpenStream( &m_pPaStream, 105 | &m_inputParams, 106 | &m_outputParams, 107 | m_uSampleRate, 108 | m_uSamplesPerBuffer, 109 | paClipOff, 110 | NULL, 111 | NULL ); 112 | 113 | if( openStreamErr != paNoError ) 114 | Nan::ThrowTypeError("Failed to open audio stream"); 115 | 116 | // Start the audio stream 117 | PaError startStreamErr = Pa_StartStream( m_pPaStream ); 118 | 119 | if( startStreamErr != paNoError ) 120 | Nan::ThrowTypeError("Failed to start audio stream"); 121 | 122 | uv_mutex_init( &m_mutex ); 123 | uv_thread_create( &ptStreamThread, do_work, (void*)this ); 124 | 125 | } // end Constructor 126 | 127 | 128 | ////////////////////////////////////////////////////////////////////////////// 129 | /*! Gets options */ 130 | void Audio::AudioEngine::getOptions(const Nan::FunctionCallbackInfo& info) { 131 | Local options = Nan::New(); 132 | 133 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 134 | 135 | Nan::Set( options, Nan::New("inputChannels").ToLocalChecked(), Nan::New(pEngine->m_uInputChannels) ); 136 | Nan::Set( options, Nan::New("outputChannels").ToLocalChecked(), Nan::New(pEngine->m_uOutputChannels) ); 137 | 138 | Nan::Set( options, Nan::New("inputDevice").ToLocalChecked(), Nan::New(pEngine->m_uInputDevice) ); 139 | Nan::Set( options, Nan::New("outputDevice").ToLocalChecked(), Nan::New(pEngine->m_uOutputDevice) ); 140 | 141 | Nan::Set( options, Nan::New("sampleRate").ToLocalChecked(), Nan::New(pEngine->m_uSampleRate) ); 142 | Nan::Set( options, Nan::New("sampleFormat").ToLocalChecked(), Nan::New(pEngine->m_uSampleFormat) ); 143 | Nan::Set( options, Nan::New("framesPerBuffer").ToLocalChecked(), Nan::New(pEngine->m_uSamplesPerBuffer) ); 144 | Nan::Set( options, Nan::New("numBuffers").ToLocalChecked(), Nan::New(pEngine->m_uNumBuffers) ); 145 | Nan::Set( options, Nan::New("interleaved").ToLocalChecked(), Nan::New(pEngine->m_bInterleaved) ); 146 | Nan::Set( options, Nan::New("useMicrophone").ToLocalChecked(), Nan::New(pEngine->m_bReadMicrophone) ); 147 | 148 | info.GetReturnValue().Set(options); 149 | } // end GetOptions 150 | 151 | 152 | ////////////////////////////////////////////////////////////////////////////// 153 | /*! Set options, restarts audio stream */ 154 | void Audio::AudioEngine::setOptions(const Nan::FunctionCallbackInfo& info) { 155 | Nan::HandleScope scope; 156 | //HandleScope scope; 157 | Local options; 158 | 159 | if( info.Length() > 0 ) { 160 | if( !info[0]->IsObject() ) { 161 | return Nan::ThrowTypeError("First argument should be an object."); 162 | } 163 | 164 | options = Local::Cast( info[0] ); 165 | } else { 166 | return Nan::ThrowTypeError("First argument does not exist."); 167 | } 168 | 169 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 170 | pEngine->applyOptions( options ); 171 | 172 | info.GetReturnValue().SetUndefined(); 173 | } // end AudioEngine::SetOptions()x 174 | 175 | 176 | ////////////////////////////////////////////////////////////////////////////// 177 | /*! Sets the given options and restarts the audio stream if necessary */ 178 | void Audio::AudioEngine::applyOptions( Local options ) { 179 | unsigned int oldBufferCount = m_uNumBuffers; 180 | if(Nan::HasOwnProperty(options, Nan::New("inputDevice").ToLocalChecked()).FromMaybe(false) ) 181 | m_uInputDevice = Nan::To(Nan::Get(options, Nan::New("inputDevice").ToLocalChecked()).ToLocalChecked()).FromJust(); 182 | if(Nan::HasOwnProperty(options, Nan::New("outputDevice").ToLocalChecked()).FromMaybe(false) ) 183 | m_uOutputDevice = Nan::To(Nan::Get(options, Nan::New("outputDevice").ToLocalChecked()).ToLocalChecked()).FromJust(); 184 | if(Nan::HasOwnProperty(options, Nan::New("inputChannels").ToLocalChecked()).FromMaybe(false) ) 185 | m_uInputChannels = Nan::To(Nan::Get(options, Nan::New("inputChannels").ToLocalChecked()).ToLocalChecked()).FromJust(); 186 | if(Nan::HasOwnProperty(options, Nan::New("outputChannels").ToLocalChecked()).FromMaybe(false) ) 187 | m_uOutputChannels = Nan::To(Nan::Get(options, Nan::New("outputChannels").ToLocalChecked()).ToLocalChecked()).FromJust(); 188 | if(Nan::HasOwnProperty(options, Nan::New("framesPerBuffer").ToLocalChecked()).FromMaybe(false) ) 189 | m_uSamplesPerBuffer = Nan::To(Nan::Get(options, Nan::New("framesPerBuffer").ToLocalChecked()).ToLocalChecked()).FromJust(); 190 | if (Nan::HasOwnProperty(options, Nan::New("numBuffers").ToLocalChecked()).FromMaybe(false) ) 191 | m_uNumBuffers = Nan::To(Nan::Get(options, Nan::New("numBuffers").ToLocalChecked()).ToLocalChecked()).FromJust(); 192 | if(Nan::HasOwnProperty(options, Nan::New("interleaved").ToLocalChecked()).FromMaybe(false) ) 193 | m_bInterleaved = Nan::To(Nan::Get(options, Nan::New("interleaved").ToLocalChecked()).ToLocalChecked()).FromJust(); 194 | if (Nan::HasOwnProperty(options, Nan::New("useMicrophone").ToLocalChecked()).FromMaybe(false) ) 195 | m_bReadMicrophone = Nan::To(Nan::Get(options, Nan::New("useMicrophone").ToLocalChecked()).ToLocalChecked()).FromJust(); 196 | if (Nan::HasOwnProperty(options, Nan::New("sampleRate").ToLocalChecked()).FromMaybe(false) ) 197 | m_uSampleRate = Nan::To(Nan::Get(options, Nan::New("sampleRate").ToLocalChecked()).ToLocalChecked()).FromJust(); 198 | if(Nan::HasOwnProperty(options, Nan::New("sampleFormat").ToLocalChecked()).FromMaybe(false) ) { 199 | switch(Nan::To(Nan::Get(options, Nan::New("sampleFormat").ToLocalChecked()).ToLocalChecked()).FromJust()){ 200 | case 0x01: m_uSampleFormat = paFloat32; m_uSampleSize = 4; break; 201 | case 0x02: m_uSampleFormat = paInt32; m_uSampleSize = 4; break; 202 | case 0x04: m_uSampleFormat = paInt24; m_uSampleSize = 3; break; 203 | case 0x08: m_uSampleFormat = paInt16; m_uSampleSize = 2; break; 204 | case 0x10: m_uSampleFormat = paInt8; m_uSampleSize = 1; break; 205 | case 0x20: m_uSampleFormat = paUInt8; m_uSampleSize = 1; break; 206 | } 207 | } 208 | 209 | // Setup our input and output parameters 210 | m_inputParams.device = m_uInputDevice; 211 | m_inputParams.channelCount = m_uInputChannels; 212 | m_inputParams.sampleFormat = m_uSampleFormat; 213 | m_inputParams.suggestedLatency = Pa_GetDeviceInfo(m_inputParams.device)->defaultLowInputLatency; 214 | m_inputParams.hostApiSpecificStreamInfo = NULL; 215 | 216 | m_outputParams.device = m_uOutputDevice; 217 | m_outputParams.channelCount = m_uOutputChannels; 218 | m_outputParams.sampleFormat = m_uSampleFormat; 219 | m_outputParams.suggestedLatency = Pa_GetDeviceInfo(m_outputParams.device)->defaultLowOutputLatency; 220 | m_outputParams.hostApiSpecificStreamInfo = NULL; 221 | 222 | // Clear out our temp buffer blocks 223 | if( m_cachedInputSampleBlock != NULL ) 224 | free( m_cachedInputSampleBlock ); 225 | if( m_cachedOutputSampleBlock != NULL ) { 226 | for (unsigned int i = 0; i < oldBufferCount; i++) { 227 | if ( m_cachedOutputSampleBlock[i] != NULL ) { 228 | free(m_cachedOutputSampleBlock[i]); 229 | } 230 | } 231 | free( m_cachedOutputSampleBlock ); 232 | } 233 | if ( m_cachedOutputSampleBlockForWriting != NULL) 234 | free (m_cachedOutputSampleBlockForWriting); 235 | 236 | // Allocate some new space for our temp buffer blocks 237 | m_cachedInputSampleBlock = (char*)malloc( m_uSamplesPerBuffer * m_uInputChannels * m_uSampleSize ); 238 | m_cachedOutputSampleBlock = (char**)malloc( sizeof(char*) * m_uNumBuffers); 239 | for (int i = 0; i < m_uNumBuffers; i++) { 240 | m_cachedOutputSampleBlock[i] = (char*)malloc( m_uSamplesPerBuffer * m_uOutputChannels * m_uSampleSize ); 241 | } 242 | m_cachedOutputSampleBlockForWriting = (char*)malloc( m_uSamplesPerBuffer * m_uOutputChannels * m_uSampleSize ); 243 | m_uNumCachedOutputSamples = (unsigned int*)calloc( sizeof(unsigned int), m_uNumBuffers ); 244 | 245 | if( m_pPaStream != NULL && Pa_IsStreamActive(m_pPaStream) ) 246 | restartStream(); 247 | 248 | } // end AudioEngine::applyOptions() 249 | 250 | ////////////////////////////////////////////////////////////////////////////// 251 | /*! Returns a v8 array filled with input samples */ 252 | Local Audio::AudioEngine::getInputBuffer() { 253 | Nan::EscapableHandleScope scope; 254 | 255 | if( m_bInterleaved ) { 256 | m_hInputBuffer = Nan::New( m_uInputChannels * m_uSamplesPerBuffer ); 257 | 258 | for( int iSample=0; iSampleSet( this->m_pIsolate->GetCurrentContext(), iSample, getSample(iSample) ); 260 | } 261 | } else { 262 | m_hInputBuffer = Nan::New( m_uInputChannels ); 263 | for( int iChannel=0; iChannel( Nan::New(m_uSamplesPerBuffer) ); 265 | 266 | for( int iSample=0; iSampleSet( this->m_pIsolate->GetCurrentContext(), iSample, getSample(iSample) ); 268 | } 269 | 270 | m_hInputBuffer->Set( this->m_pIsolate->GetCurrentContext(), iChannel, tempBuffer ); 271 | } 272 | } 273 | 274 | return scope.Escape( m_hInputBuffer ); 275 | } // end AudioEngine::getInputBuffer() 276 | 277 | 278 | ////////////////////////////////////////////////////////////////////////////// 279 | /*! Returns a sound card sample converted to a v8 Number */ 280 | Local Audio::AudioEngine::getSample( int position ) { 281 | Nan::EscapableHandleScope scope; 282 | 283 | Local sample; 284 | 285 | switch( m_uSampleFormat ) { 286 | case paFloat32: { 287 | float fValue = ((float*)m_cachedInputSampleBlock)[position]; 288 | 289 | sample = Nan::New( fValue ); 290 | break; 291 | } 292 | case paInt32: 293 | sample = Nan::New( ((int*)m_cachedInputSampleBlock)[position] ); 294 | break; 295 | 296 | case paInt24: 297 | sample = Nan::New( 298 | (m_cachedInputSampleBlock[3*position + 0] << 16) 299 | + (m_cachedInputSampleBlock[3*position + 1] << 8) 300 | + (m_cachedInputSampleBlock[3*position + 2]) ); 301 | break; 302 | 303 | case paInt16: 304 | sample = Nan::New( ((int16_t*)m_cachedInputSampleBlock)[position] ); 305 | break; 306 | 307 | default: 308 | sample = Nan::New( m_cachedInputSampleBlock[position]*-1 ); 309 | break; 310 | } 311 | 312 | return scope.Escape(sample); 313 | } // end AudioEngine::getSample() 314 | 315 | 316 | ////////////////////////////////////////////////////////////////////////////// 317 | /*! Sets a sample in the queued output buffer */ 318 | void Audio::AudioEngine::setSample( int position, Local sample ) { 319 | int temp; 320 | switch( m_uSampleFormat ) { 321 | case paFloat32: 322 | ((float *)m_cachedOutputSampleBlock[m_uCurrentWriteBuffer])[position] = (float)sample->NumberValue(this->m_pIsolate->GetCurrentContext()).FromJust(); 323 | break; 324 | 325 | case paInt32: 326 | ((int *)m_cachedOutputSampleBlock[m_uCurrentWriteBuffer])[position] = (int)sample->NumberValue(this->m_pIsolate->GetCurrentContext()).FromJust(); 327 | break; 328 | 329 | case paInt24: 330 | temp = (int)sample->NumberValue(this->m_pIsolate->GetCurrentContext()).FromJust(); 331 | m_cachedOutputSampleBlock[m_uCurrentWriteBuffer][3*position + 0] = temp >> 16; 332 | m_cachedOutputSampleBlock[m_uCurrentWriteBuffer][3*position + 1] = temp >> 8; 333 | m_cachedOutputSampleBlock[m_uCurrentWriteBuffer][3*position + 2] = temp; 334 | break; 335 | 336 | case paInt16: 337 | ((int16_t *)m_cachedOutputSampleBlock[m_uCurrentWriteBuffer])[position] = (int16_t)sample->NumberValue(this->m_pIsolate->GetCurrentContext()).FromJust(); 338 | break; 339 | 340 | default: 341 | m_cachedOutputSampleBlock[m_uCurrentWriteBuffer][position] = (char)sample->NumberValue(this->m_pIsolate->GetCurrentContext()).FromJust(); 342 | break; 343 | } 344 | } // end AudioEngine::setSample() 345 | 346 | 347 | ////////////////////////////////////////////////////////////////////////////// 348 | /*! Queues up an array to be sent to the sound card */ 349 | void Audio::AudioEngine::queueOutputBuffer( Local result ) { 350 | // Reset our record of the number of cached output samples 351 | m_uNumCachedOutputSamples[m_uCurrentWriteBuffer] = 0; 352 | 353 | if( m_bInterleaved ) { 354 | for( int iSample=0; iSampleGet(result->GetIsolate()->GetCurrentContext(), iSample).ToLocalChecked()); 357 | } 358 | 359 | m_uNumCachedOutputSamples[m_uCurrentWriteBuffer] = result->Length()/m_uOutputChannels; 360 | 361 | } else { 362 | // Validate the structure of the output buffer array 363 | if( !result->Get(result->GetIsolate()->GetCurrentContext(), 0).ToLocalChecked()->IsArray() ) { 364 | Nan::ThrowTypeError("Output buffer not properly setup, 0th channel is not an array"); 365 | return; 366 | } 367 | 368 | Local item; 369 | 370 | for( int iChannel=0; iChannel::Cast( result->Get(result->GetIsolate()->GetCurrentContext(), iChannel).ToLocalChecked() ); 374 | if( item->IsArray() ) { 375 | if( item->Length() > m_uNumCachedOutputSamples[m_uCurrentWriteBuffer] ) 376 | m_uNumCachedOutputSamples[m_uCurrentWriteBuffer] = item->Length(); 377 | 378 | setSample( iSample, item->Get(result->GetIsolate()->GetCurrentContext(), iSample).ToLocalChecked() ); 379 | } 380 | } // end for each sample 381 | } // end for each channel 382 | } 383 | m_uCurrentWriteBuffer = (m_uCurrentWriteBuffer + 1)%m_uNumBuffers; 384 | } // end AudioEngine::queueOutputBuffer() 385 | 386 | 387 | ////////////////////////////////////////////////////////////////////////////// 388 | /*! Run the main blocking audio loop */ 389 | void Audio::AudioEngine::RunAudioLoop(){ 390 | 391 | PaError error = 0; 392 | 393 | assert( m_pPaStream ); 394 | 395 | while( true ) { 396 | m_bInputOverflowed = (error != paNoError); 397 | 398 | int numSamples = 0; 399 | uv_mutex_lock( &m_mutex ); 400 | if (m_uNumCachedOutputSamples[m_uCurrentReadBuffer] > 0) { 401 | memcpy(m_cachedOutputSampleBlockForWriting, m_cachedOutputSampleBlock[m_uCurrentReadBuffer], m_uNumCachedOutputSamples[m_uCurrentReadBuffer] * m_uOutputChannels * m_uSampleSize); 402 | numSamples = m_uNumCachedOutputSamples[m_uCurrentReadBuffer]; 403 | m_uNumCachedOutputSamples[m_uCurrentReadBuffer] = 0; 404 | m_uCurrentReadBuffer = (m_uCurrentReadBuffer + 1)%m_uNumBuffers; 405 | } 406 | uv_mutex_unlock( &m_mutex ); 407 | 408 | if( numSamples > 0 ) { 409 | error = Pa_WriteStream( m_pPaStream, m_cachedOutputSampleBlockForWriting, numSamples ); 410 | m_bOutputUnderflowed = (error != paNoError); 411 | } else { 412 | m_bOutputUnderflowed = true; 413 | #if defined( __WINDOWS__ ) || defined( _WIN32 ) 414 | Sleep(1); 415 | #else 416 | sleep(1); 417 | #endif 418 | } 419 | } 420 | } // end AudioEngine::RunAudioLoop() 421 | 422 | 423 | ////////////////////////////////////////////////////////////////////////////// 424 | /*! Initialize our node object */ 425 | NAN_MODULE_INIT(Audio::AudioEngine::Init) { 426 | Isolate * isolate = target->GetIsolate(); 427 | v8::Local context = target->CreationContext(); 428 | 429 | // Prepare constructor template 430 | Local functionTemplate = Nan::New (Audio::AudioEngine::New ); 431 | functionTemplate->SetClassName( Nan::New("AudioEngine").ToLocalChecked() ); 432 | functionTemplate->InstanceTemplate()->SetInternalFieldCount( 1 ); 433 | 434 | 435 | //Local constructorHandle = Nan::New(constructor); 436 | //target->Set(Nan::New("AudioEngine"), functionTemplate->GetFunction()); 437 | 438 | // Get 439 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("isActive"), Nan::New(Audio::AudioEngine::isActive)->GetFunction() ); 440 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("getDeviceName"), Nan::New(Audio::AudioEngine::getDeviceName)->GetFunction() ); 441 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("getNumDevices"), Nan::New(Audio::AudioEngine::getNumDevices)->GetFunction() ); 442 | Nan::SetPrototypeMethod(functionTemplate, "isActive", Audio::AudioEngine::isActive); 443 | Nan::SetPrototypeMethod(functionTemplate, "getDeviceName", Audio::AudioEngine::getDeviceName); 444 | Nan::SetPrototypeMethod(functionTemplate, "getNumDevices", Audio::AudioEngine::getNumDevices); 445 | 446 | // Set 447 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("setOptions"), Nan::New(Audio::AudioEngine::setOptions)->GetFunction() ); 448 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("getOptions"), Nan::New(Audio::AudioEngine::getOptions)->GetFunction() ); 449 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("write"), Nan::New(Audio::AudioEngine::write)->GetFunction() ); 450 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("read"), Nan::New(Audio::AudioEngine::read)->GetFunction() ); 451 | //functionTemplate->PrototypeTemplate()->Set( this->m_pIsolate->GetCurrentContext(), Nan::New("isBufferEmpty"), Nan::New(Audio::AudioEngine::isBufferEmpty)->GetFunction() ); 452 | Nan::SetPrototypeMethod(functionTemplate, "setOptions", Audio::AudioEngine::setOptions); 453 | Nan::SetPrototypeMethod(functionTemplate, "getOptions", Audio::AudioEngine::getOptions); 454 | Nan::SetPrototypeMethod(functionTemplate, "write", Audio::AudioEngine::write); 455 | Nan::SetPrototypeMethod(functionTemplate, "read", Audio::AudioEngine::read); 456 | Nan::SetPrototypeMethod(functionTemplate, "isBufferEmpty", Audio::AudioEngine::isBufferEmpty); 457 | 458 | //constructor = Persistent::New( functionTemplate->GetFunction() ); 459 | //Local tpl = Nan::New(EOLFinder::New); 460 | // NanAssignPersistent(constructor, functionTemplate->GetFunction()); 461 | constructor.Reset(isolate, functionTemplate->GetFunction(context).ToLocalChecked()); 462 | } // end AudioEngine::Init() 463 | 464 | 465 | ////////////////////////////////////////////////////////////////////////////// 466 | /*! Create a new instance of the audio engine */ 467 | /*void Audio::AudioEngine::NewInstance(const v8::FunctionCallbackInfo& args) { 468 | args.GetReturnValue().Set( Nan::New("sampleFormatFloat32").ToLocalChecked()); 469 | }*/ 470 | //v8::Local Audio::AudioEngine::NewInstance(const v8::Arguments& info) { 471 | Nan::NAN_METHOD_RETURN_TYPE Audio::AudioEngine::NewInstance(const Nan::FunctionCallbackInfo& info){ 472 | Isolate* isolate = info.GetIsolate(); 473 | v8::Local context = info.GetIsolate()->GetCurrentContext(); 474 | Nan::HandleScope scope; 475 | //HandleScope scope; 476 | 477 | unsigned argc = info.Length(); 478 | 479 | if( argc > 2 ) 480 | argc = 2; 481 | 482 | Local* argv = new Local[argc]; 483 | 484 | argv[0] = info[0]; 485 | if( argc > 1 ) 486 | argv[1] = info[1]; 487 | 488 | //Local instance = constructor->NewInstance( argc, argv ); 489 | // auto instance = Nan::New(constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); 490 | fprintf( stdout, "step 2" ); 491 | Local cons = Nan::New(constructor); 492 | fprintf( stdout, "step 3" ); 493 | 494 | //Local instance = constructor->NewInstance(argc, argv); 495 | 496 | //info.GetReturnValue().Set( instance.ToLocalChecked() ); 497 | 498 | if (info.IsConstructCall()) { 499 | fprintf(stdout, "step 4.1"); 500 | // Invoked as constructor: `new MyObject(...)` 501 | 502 | Local options = info[0]->ToObject(context).ToLocalChecked(); 503 | AudioEngine* obj = new AudioEngine(options); 504 | obj->Wrap(info.This()); 505 | info.GetReturnValue().Set(info.This()); 506 | } else { 507 | fprintf(stdout, "step 4.2"); 508 | // Invoked as plain function `MyObject(...)`, turn into construct call. 509 | const int argc = 1; 510 | v8::Local argv[argc] = {info[0]}; 511 | v8::Local cons = Nan::New(constructor); 512 | info.GetReturnValue().Set( 513 | cons->NewInstance(context, argc, argv).ToLocalChecked()); 514 | } 515 | } // end AudioEngine::NewInstance() 516 | 517 | ////////////////////////////////////////////////////////////////////////////// 518 | /*! Create a v8 object */ 519 | void Audio::AudioEngine::New(const Nan::FunctionCallbackInfo& info) { 520 | Nan::HandleScope scope; 521 | //HandleScope scope; 522 | 523 | Local options; 524 | 525 | if( info.Length() > 0 ) { 526 | if( !info[0]->IsObject() ) 527 | return Nan::ThrowTypeError("First argument must be an object."); 528 | else 529 | options = Local::Cast( info[0] ); 530 | } else { 531 | options = Nan::New(); 532 | } 533 | 534 | AudioEngine* pEngine = new AudioEngine( options ); 535 | pEngine->Wrap( info.This() ); 536 | 537 | info.GetReturnValue().Set( info.This() ); 538 | } // end AudioEngine::New() 539 | 540 | 541 | ////////////////////////////////////////////////////////////////////////////// 542 | /*! Write samples to the current audio device */ 543 | void Audio::AudioEngine::write(const Nan::FunctionCallbackInfo& info) { 544 | Nan::HandleScope scope; 545 | //HandleScope scope; 546 | 547 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 548 | 549 | if (info.Length() > 1 || !info[0]->IsArray()){ 550 | return Nan::ThrowTypeError("First argument should be an array."); 551 | } 552 | 553 | uv_mutex_lock( &pEngine->m_mutex ); 554 | pEngine->queueOutputBuffer( Local::Cast(info[0]) ); 555 | uv_mutex_unlock( &pEngine->m_mutex ); 556 | 557 | info.GetReturnValue().Set( false ); 558 | } // end AudioEngine::Write() 559 | 560 | ////////////////////////////////////////////////////////////////////////////// 561 | /*! Checks if the current audio buffer has been fed to Port Audio */ 562 | void Audio::AudioEngine::isBufferEmpty(const Nan::FunctionCallbackInfo& info) { 563 | Nan::HandleScope scope; 564 | //HandleScope scope; 565 | 566 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 567 | 568 | uv_mutex_lock( &pEngine->m_mutex ); 569 | Local isEmpty = Nan::New(pEngine->m_uNumCachedOutputSamples[pEngine->m_uCurrentWriteBuffer] == 0); 570 | uv_mutex_unlock( &pEngine->m_mutex ); 571 | info.GetReturnValue().Set( isEmpty ); 572 | } // end AudioEngine::isBufferEmpty() 573 | 574 | ////////////////////////////////////////////////////////////////////////////// 575 | /*! Read samples from the current audio device */ 576 | void Audio::AudioEngine::read(const Nan::FunctionCallbackInfo& info) { 577 | Nan::HandleScope scope; 578 | //HandleScope scope; 579 | 580 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 581 | 582 | if (pEngine->m_bReadMicrophone) { 583 | Pa_ReadStream( pEngine->m_pPaStream, pEngine->m_cachedInputSampleBlock, pEngine->m_uSamplesPerBuffer ); 584 | } 585 | 586 | Local input = pEngine->getInputBuffer(); 587 | 588 | info.GetReturnValue().Set( input ); 589 | } // end AudioEngine::Read() 590 | 591 | 592 | ////////////////////////////////////////////////////////////////////////////// 593 | /*! Returns whether the PortAudio stream is active */ 594 | void Audio::AudioEngine::isActive(const Nan::FunctionCallbackInfo& info) { 595 | Nan::HandleScope scope; 596 | //HandleScope scope; 597 | 598 | AudioEngine* pEngine = AudioEngine::Unwrap( info.This() ); 599 | 600 | if( Pa_IsStreamActive(pEngine->m_pPaStream) ) 601 | info.GetReturnValue().Set( Nan::New(true) ); 602 | else 603 | info.GetReturnValue().Set( Nan::New(false) ); 604 | } // end AudioEngine::IsActive() 605 | 606 | 607 | ////////////////////////////////////////////////////////////////////////////// 608 | /*! Get the name of an audio device with a given ID number */ 609 | void Audio::AudioEngine::getDeviceName(const Nan::FunctionCallbackInfo& info) { 610 | Local context = info.GetIsolate()->GetCurrentContext(); 611 | Nan::HandleScope scope; 612 | //HandleScope scope; 613 | 614 | if( !info[0]->IsNumber() ) { 615 | return Nan::ThrowTypeError("getDeviceName() requires a device index"); 616 | } 617 | 618 | Local deviceIndex = Local::Cast( info[0] ); 619 | 620 | const PaDeviceInfo* pDeviceInfo = Pa_GetDeviceInfo( (PaDeviceIndex)deviceIndex->NumberValue(context).ToChecked() ); 621 | 622 | info.GetReturnValue().Set( Nan::New(pDeviceInfo->name).ToLocalChecked() ); 623 | } // end AudioEngine::GetDeviceName() 624 | 625 | 626 | ////////////////////////////////////////////////////////////////////////////// 627 | /*! Get the number of available devices */ 628 | void Audio::AudioEngine::getNumDevices(const Nan::FunctionCallbackInfo& info) { 629 | Nan::HandleScope scope; 630 | //HandleScope scope; 631 | 632 | int deviceCount = Pa_GetDeviceCount(); 633 | 634 | info.GetReturnValue().Set( Nan::New(deviceCount) ); 635 | } // end AudioEngine::GetNumDevices() 636 | 637 | 638 | ////////////////////////////////////////////////////////////////////////////// 639 | /*! Closes and reopens the PortAudio stream */ 640 | void Audio::AudioEngine::restartStream() { 641 | PaError error; 642 | 643 | // Stop the audio stream 644 | error = Pa_StopStream( m_pPaStream ); 645 | 646 | if( error != paNoError ) 647 | Nan::ThrowTypeError("Failed to stop audio stream"); 648 | 649 | // Close the audio stream 650 | error = Pa_CloseStream( m_pPaStream ); 651 | 652 | if( error != paNoError ) 653 | Nan::ThrowTypeError("Failed to close audio stream"); 654 | 655 | // Open an audio stream.`` 656 | error = Pa_OpenStream( &m_pPaStream, 657 | &m_inputParams, 658 | &m_outputParams, 659 | m_uSampleRate, 660 | m_uSamplesPerBuffer, 661 | paClipOff, // We won't output out of range samples so don't bother clipping them 662 | NULL, 663 | NULL ); 664 | 665 | if( error != paNoError ) { 666 | Nan::ThrowTypeError("Failed to open audio stream :("); 667 | } 668 | 669 | // Start the audio stream 670 | error = Pa_StartStream( m_pPaStream ); 671 | 672 | if( error != paNoError ) 673 | Nan::ThrowTypeError("Failed to start audio stream"); 674 | 675 | } // end AudioEngine::restartStream() 676 | 677 | 678 | ////////////////////////////////////////////////////////////////////////////// 679 | /*! Wraps a handle into an object */ 680 | void Audio::AudioEngine::wrapObject( v8::Local object ) { 681 | ObjectWrap::Wrap( object ); 682 | } // end AudioEngine::wrapObject() 683 | 684 | 685 | ////////////////////////////////////////////////////////////////////////////// 686 | /*! OOL Destructor */ 687 | Audio::AudioEngine::~AudioEngine() { 688 | // Kill PortAudio 689 | PaError err = Pa_Terminate(); 690 | 691 | if( err != paNoError ) 692 | fprintf( stderr, "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 693 | } // end AudioEngine::~AudioEngine() 694 | -------------------------------------------------------------------------------- /NodeCoreAudio/AudioEngine.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // AudioEngine.cpp: Core audio functionality 4 | // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | #include "portaudio.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace v8; using namespace std; 14 | 15 | #define DEFAULT_SAMPLE_RATE (44100) 16 | #define DEFAULT_SAMPLE_FORMAT paFloat32 17 | #define DEFAULT_FRAMES_PER_BUFFER (256) 18 | #define DEFAULT_NUM_BUFFERS (8) 19 | 20 | namespace Audio { 21 | 22 | ////////////////////////////////////////////////////////////////////////// 23 | //! Core audio functionality 24 | class AudioEngine : public Nan::ObjectWrap { 25 | public: 26 | 27 | AudioEngine( Local options ); 28 | 29 | //! Initialize our node object 30 | static void Init(v8::Local target); 31 | //! Create a new instance of the audio engine 32 | //static v8::v8::Local NewInstance(const v8::Arguments& args); 33 | static NAN_METHOD(NewInstance); 34 | 35 | Isolate* GetIsolate() { return m_pIsolate; } 36 | Locker* GetLocker() { return m_pLocker; } 37 | 38 | //! Run the main blocking audio loop 39 | void RunAudioLoop(); 40 | 41 | ~AudioEngine(); //!< OOL Destructor 42 | 43 | private: 44 | static v8::Persistent constructor; 45 | //static v8::v8::Local New( const v8::Arguments& args ); //!< Create a v8 object 46 | static NAN_METHOD(New); 47 | 48 | //! Returns whether the PortAudio stream is active 49 | //static v8::v8::Local isActive( const v8::Arguments& args ); 50 | static NAN_METHOD(isActive); 51 | //! Get the name of an audio device with a given ID number 52 | //static v8::v8::Local getDeviceName( const v8::Arguments& args ); 53 | static NAN_METHOD(getDeviceName); 54 | //! Get the number of available devices 55 | //static v8::v8::Local getNumDevices( const v8::Arguments& args ); 56 | static NAN_METHOD(getNumDevices); 57 | 58 | //! Closes and reopens the PortAudio stream 59 | void restartStream(); 60 | 61 | //static v8::v8::Local write( const v8::Arguments& args ); //!< Write samples to the current audio device 62 | static NAN_METHOD(write); 63 | //static v8::v8::Local read( const v8::Arguments& args ); //!< Read samples from the current audio device 64 | static NAN_METHOD(read); 65 | //static v8::v8::Local isBufferEmpty( const v8::Arguments& args ); //!< Returns whether the data buffer is empty 66 | static NAN_METHOD(isBufferEmpty); 67 | 68 | //static v8::v8::Local setOptions( const v8::Arguments& args ); //!< Set options, restarts audio stream 69 | static NAN_METHOD(setOptions); 70 | //static v8::v8::Local getOptions( const v8::Arguments& args ); //!< Gets options 71 | static NAN_METHOD(getOptions); 72 | 73 | static void afterWork(uv_work_t* handle, int status) {}; 74 | 75 | void applyOptions( Local options ); //!< Sets the given options and restarts the audio stream if necessary 76 | void wrapObject( v8::Local object ); //!< Wraps a handle into an object 77 | 78 | void queueOutputBuffer( v8::Local result ); //!< Queues up an array to be sent to the sound card 79 | void setSample( int position, v8::Local sample ); //!< Sets a sample in the queued output buffer 80 | 81 | Local getInputBuffer(); //!< Returns a v8 array filled with input samples 82 | v8::Local getSample( int position ); //!< Returns a sound card sample converted to a v8 Number 83 | 84 | PaStream *m_pPaStream; //!< The PortAudio stream object 85 | PaStreamParameters m_inputParams, //!< PortAudio stream parameters 86 | m_outputParams; 87 | 88 | Local m_hInputBuffer; //!< Our pre-allocated input buffer 89 | 90 | uv_thread_t ptStreamThread; //!< Our stream thread 91 | 92 | uv_mutex_t m_mutex; //!< A mutex for transferring data between the DSP and UI threads 93 | 94 | int m_uOutputChannels, //!< Number of input channels 95 | m_uInputChannels, //!< Number of output channels 96 | m_uInputDevice, //!< Index of the current input device 97 | m_uOutputDevice, //!< Index of the current output device 98 | m_uSampleRate, //!< Current sample rate 99 | m_uSamplesPerBuffer, //!< Number of sample frames per process buffers 100 | m_uNumBuffers, //!< Number of sample buffers to keep ahead 101 | m_uSampleFormat, //!< Index of the current sample format 102 | m_uSampleSize; //!< Number of bytes per sample frame 103 | 104 | unsigned int m_uCurrentWriteBuffer, m_uCurrentReadBuffer; 105 | unsigned int* m_uNumCachedOutputSamples; //!< Number of samples we've queued up, outgoing to the sound card 106 | 107 | bool m_bInputOverflowed, //!< Set when our buffers have overflowed 108 | m_bOutputUnderflowed, 109 | m_bReadMicrophone, 110 | m_bInterleaved; //!< Set when we're processing interleaved buffers 111 | 112 | char* m_cachedInputSampleBlock, //!< Temp buffer to hold buffer results 113 | ** m_cachedOutputSampleBlock, 114 | * m_cachedOutputSampleBlockForWriting; 115 | 116 | Isolate* m_pIsolate; 117 | 118 | Locker* m_pLocker; 119 | 120 | }; // end class AudioEngine 121 | 122 | } // end namespace Audio 123 | -------------------------------------------------------------------------------- /NodeCoreAudio/NodeCoreAudio.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // NodeCoreAudio.cpp : Main module source, declares all exports 4 | // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | using namespace v8; 9 | //#pragma comment(lib, "node") 10 | #include 11 | 12 | #include 13 | #include "AudioEngine.h" 14 | #include 15 | 16 | /* 17 | //Handle CreateEngine(const Arguments& args) 18 | NAN_METHOD(CreateEngine) 19 | { 20 | //HandleScope scope; 21 | NanScope(); 22 | //return scope.Close( Audio::AudioEngine::NewInstance(args) ); 23 | NanReturnValue(Audio::AudioEngine::NewInstance(args)); 24 | } // end CreateEngine() 25 | */ 26 | 27 | void InitAll(Local target) { 28 | 29 | fprintf( stdout, "step 1" ); 30 | Local context = target->GetIsolate()->GetCurrentContext(); 31 | Audio::AudioEngine::Init( target ); 32 | 33 | Nan::SetMethod(target, "createAudioEngine", Audio::AudioEngine::NewInstance); 34 | 35 | //NODE_SET_METHOD(target, "createAudioEngine", CreateEngine); 36 | //target->Set( NanNew("createAudioEngine"), CreateEngine); 37 | //target->Set( NanNew("createAudioEngine"), NanNew(CreateEngine)->GetFunction() ); 38 | //target->Set( NanNew("createAudioEngine"), NanNew(Audio::AudioEngine::NewInstance)->GetFunction() ); 39 | 40 | target->Set( context, Nan::New("sampleFormatFloat32").ToLocalChecked(), Nan::New(1)); 41 | target->Set( context, Nan::New("sampleFormatInt32").ToLocalChecked(), Nan::New(2) ); 42 | target->Set( context, Nan::New("sampleFormatInt24").ToLocalChecked(), Nan::New(4) ); 43 | target->Set( context, Nan::New("sampleFormatInt16").ToLocalChecked(), Nan::New(8) ); 44 | target->Set( context, Nan::New("sampleFormatInt8").ToLocalChecked(), Nan::New(10) ); 45 | target->Set( context, Nan::New("sampleFormatUInt8").ToLocalChecked(), Nan::New(20) ); 46 | } 47 | 48 | NODE_MODULE( NodeCoreAudio, InitAll ); 49 | -------------------------------------------------------------------------------- /NodeCoreAudio/NodeCoreAudio.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {4710311E-884B-4997-8430-DC8964BD672E} 15 | Win32Proj 16 | NodeCoreAudio 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | Unicode 23 | v141 24 | 25 | 26 | DynamicLibrary 27 | false 28 | true 29 | Unicode 30 | v141 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | D:\Projects\NodeCode\node;D:\Projects\NodeCode\node\Debug;$(LibraryPath) 45 | D:\Projects\NodeCode\node\deps\uv\include;D:\Projects\NodeCode\node\deps\v8\include;D:\Projects\NodeCode\node\src;../portaudio/include;$(IncludePath) 46 | 47 | 48 | false 49 | D:\Projects\NodeCode\node\deps\uv\include;D:\Projects\NodeCode\node\deps\v8\include;D:\Projects\NodeCode\node\src;../portaudio/include;$(IncludePath) 50 | D:\Projects\NodeCode\node;D:\Projects\NodeCode\node\Debug;$(LibraryPath) 51 | 52 | 53 | 54 | Use 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NODECOREAUDIO_EXPORTS;%(PreprocessorDefinitions) 58 | 4251;%(DisableSpecificWarnings) 59 | 60 | 61 | Windows 62 | true 63 | ../portaudio/build/msvc/Win32/Release/portaudio_x86.lib;%(AdditionalDependencies) 64 | 65 | 66 | 67 | 68 | Level3 69 | Use 70 | MaxSpeed 71 | true 72 | true 73 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NODECOREAUDIO_EXPORTS;%(PreprocessorDefinitions) 74 | 75 | 76 | Windows 77 | true 78 | true 79 | true 80 | ../portaudio/build/msvc/Win32/Release/portaudio_x86.lib;%(AdditionalDependencies) 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | NotUsing 94 | NotUsing 95 | 96 | 97 | false 98 | 99 | 100 | false 101 | NotUsing 102 | 103 | 104 | NotUsing 105 | NotUsing 106 | 107 | 108 | Create 109 | NotUsing 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /NodeCoreAudio/NodeCoreAudio.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 14 | h;hpp;hxx;hm;inl;inc;xsd 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Source Files\Header Files 23 | 24 | 25 | Source Files\Header Files 26 | 27 | 28 | Source Files\Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /NodeCoreAudio/NodeCoreAudio.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | WindowsLocalDebugger 7 | 8 | -------------------------------------------------------------------------------- /NodeCoreAudio/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | // #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /NodeCoreAudio/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // NodeWinNetInfo.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /NodeCoreAudio/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /NodeCoreAudio/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Node Core Audio 2 | ================== 3 | 4 | ![alt tag](https://nodei.co/npm-dl/node-core-audio.png) 5 | 6 | A C++ extension for node.js that gives javascript access to audio buffers and basic audio processing functionality 7 | 8 | Right now, it's basically a node.js binding for PortAudio. 9 | 10 | NOTE: Looking for help maintaining this repository! 11 | 12 | Active contributors: 13 | 14 | - [rmedaer](https://github.com/rmedaer) 15 | 16 | Installation 17 | ===== 18 | 19 | ``` 20 | npm install node-core-audio 21 | ``` 22 | 23 | Basic Usage 24 | ===== 25 | 26 | Below is the most basic use of the audio engine. We create a new instance of 27 | node-core-audio, and then give it our processing function. The audio engine 28 | will call the audio callback whenever it needs an output buffer to send to 29 | the sound card. 30 | 31 | ```javascript 32 | // Create a new instance of node-core-audio 33 | var coreAudio = require("node-core-audio"); 34 | 35 | // Create a new audio engine 36 | var engine = coreAudio.createNewAudioEngine(); 37 | 38 | // Add an audio processing callback 39 | // This function accepts an input buffer coming from the sound card, 40 | // and returns an ourput buffer to be sent to your speakers. 41 | // 42 | // Note: This function must return an output buffer 43 | function processAudio( inputBuffer ) { 44 | console.log( "%d channels", inputBuffer.length ); 45 | console.log( "Channel 0 has %d samples", inputBuffer[0].length ); 46 | 47 | return inputBuffer; 48 | } 49 | 50 | engine.addAudioCallback( processAudio ); 51 | ``` 52 | 53 | // Alternatively, you can read/write samples to the sound card manually 54 | ```javascript 55 | var engine = coreAudio.createNewAudioEngine(); 56 | 57 | // Grab a buffer 58 | var buffer = engine.read(); 59 | 60 | // Silence the 0th channel 61 | for( var iSample=0; iSample 1000) { 59 | lastFPS = frames; 60 | frames = 0; 61 | lastFrameTime = newTime; 62 | } 63 | 64 | frames++; 65 | }); 66 | 67 | window.resize(w, h); 68 | window.show(); 69 | 70 | setInterval(app.processEvents.bind(app), 0); 71 | setInterval(function() { window.update(); }, 0); //Update our display as often as possible -------------------------------------------------------------------------------- /examples/standalone_waveform_visualizer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "standalone_waveform_visualizer", 3 | "version": "0.0.0", 4 | "description": "node-core-audio example project", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "anprogrammer", 10 | "license": "MIT", 11 | "dependencies": { 12 | "node-qt": "0.0.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gyp/lib/libportaudio.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/libportaudio.a -------------------------------------------------------------------------------- /gyp/lib/win32/portaudio_x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win32/portaudio_x86.dll -------------------------------------------------------------------------------- /gyp/lib/win32/portaudio_x86.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win32/portaudio_x86.exp -------------------------------------------------------------------------------- /gyp/lib/win32/portaudio_x86.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win32/portaudio_x86.lib -------------------------------------------------------------------------------- /gyp/lib/win64/portaudio_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win64/portaudio_x64.dll -------------------------------------------------------------------------------- /gyp/lib/win64/portaudio_x64.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win64/portaudio_x64.exp -------------------------------------------------------------------------------- /gyp/lib/win64/portaudio_x64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioNet/node-core-audio/e3c348f1ad16ea9e0694d0443d87bc4f888f8b6e/gyp/lib/win64/portaudio_x64.lib -------------------------------------------------------------------------------- /node-core-audio.js: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // node-core-audio - main module 3 | ////////////////////////////////////////////////////////////////////////// 4 | // 5 | // Main javascript audio API 6 | /* ---------------------------------------------------------------------- 7 | Object Structures 8 | ------------------------------------------------------------------------- 9 | 10 | */ 11 | ////////////////////////////////////////////////////////////////////////// 12 | // Node.js Exports 13 | var globalNamespace = {}; 14 | (function (exports) { 15 | exports.createNewAudioEngine = function( options ) { 16 | newAudioEngine= new AudioEngine( options ); 17 | return newAudioEngine; 18 | }; 19 | }(typeof exports === 'object' && exports || globalNamespace)); 20 | 21 | var FFT = require("fft"); 22 | 23 | 24 | ////////////////////////////////////////////////////////////////////////// 25 | // Namespace (lol) 26 | var SHOW_DEBUG_PRINTS = true; 27 | var MAX_SUPPORTED_CHANNELS = 6; // We need to allocate our process audio for the max channels, 28 | // so we have to set some reasonable limit 29 | var log = function( a ) { if(SHOW_DEBUG_PRINTS) console.log(a); }; // A log function we can turn off 30 | var exists = function(a) { return typeof(a) == "undefined" ? false : true; }; // Check whether a variable exists 31 | 32 | 33 | ////////////////////////////////////////////////////////////////////////// 34 | // Constructor 35 | function AudioEngine( options ) { 36 | var audioEngineImpl = require( __dirname + "/build/Release/NodeCoreAudio" ); 37 | 38 | var defaultOptions = { 39 | inputChannels: 1, 40 | outputChannels: 2, 41 | framesPerBuffer: 1024, 42 | useMicrophone: true 43 | }; 44 | 45 | this.options = options || defaultOptions; 46 | this.audioEngine = audioEngineImpl.createAudioEngine( this.options ); 47 | this.options = this.audioEngine.getOptions(); 48 | 49 | this.audioStreamer; 50 | 51 | this.processingCallbacks = []; 52 | this.uiUpdateCallbacks = []; 53 | 54 | this.outputBuffer = []; 55 | this.tempBuffer = []; 56 | this.processBuffer = []; 57 | 58 | this.fft = new FFT.complex( this.audioEngine.getOptions().framesPerBuffer, false ); 59 | this.fftBuffer = []; 60 | 61 | var _this = this; 62 | 63 | function validateOutputBufferStructure( buffer ) { 64 | if( buffer === undefined ) { 65 | console.log( "Audio processing function didn't return an output buffer" ); 66 | return false; 67 | } 68 | 69 | if( !_this.audioEngine.getOptions().interleaved ) { 70 | 71 | if( buffer.length > _this.options.inputChannels ) { 72 | console.log( "Output buffer has info for too many channels" ); 73 | return false; 74 | } else if( buffer.length < _this.options.inputChannels ) { 75 | console.log( "Output buffer doesn't have data for enough channels" ); 76 | return false; 77 | } 78 | 79 | if( typeof(buffer[0]) != "object" ) { 80 | console.log( "Output buffer not setup correctly, buffer[0] isn't an array" ); 81 | return false; 82 | } 83 | 84 | if( typeof(buffer[0][0]) != "number" ) { 85 | console.log( "Output buffer not setup correctly, buffer[0][0] isn't a number" ); 86 | return false; 87 | } 88 | } else { 89 | if( typeof(buffer[0]) != "number" ) { 90 | console.log( "Output buffer not setup correctly, buffer[0] isn't a number" ); 91 | return false; 92 | } 93 | } 94 | 95 | return true; 96 | } 97 | 98 | // Allocate a processing buffer for each of our channels 99 | for( var iChannel = 0; iChannel= 0.1.0", 13 | "fft": "~0.2.1", 14 | "nan": "^2.14.2", 15 | "node-waveheader": "git://github.com/mrose17/node-waveheader.git", 16 | "portfinder": "0.2.1" 17 | }, 18 | "engines": { 19 | "node": ">=0.12.0" 20 | } 21 | }, 22 | "node_modules/assert-plus": { 23 | "version": "1.0.0", 24 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 25 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 26 | "license": "MIT", 27 | "engines": { 28 | "node": ">=0.8" 29 | } 30 | }, 31 | "node_modules/audio-streamer": { 32 | "version": "0.1.0", 33 | "resolved": "https://registry.npmjs.org/audio-streamer/-/audio-streamer-0.1.0.tgz", 34 | "integrity": "sha1-kd9oKWe5b9j3aTFiQR/2sMdayMU=", 35 | "dependencies": { 36 | "binaryjs": ">= 0.0.1" 37 | }, 38 | "engines": { 39 | "node": ">=0.8.0" 40 | } 41 | }, 42 | "node_modules/binaryjs": { 43 | "version": "0.2.1", 44 | "resolved": "https://registry.npmjs.org/binaryjs/-/binaryjs-0.2.1.tgz", 45 | "integrity": "sha1-KO20CxgwJ49VmOsAw2eSU+jpne4=", 46 | "dependencies": { 47 | "binarypack": ">=0.0.4", 48 | "streamers": ">=0.1.0", 49 | "streamws": ">=0.1.1" 50 | }, 51 | "engines": { 52 | "node": ">=0.6.0" 53 | } 54 | }, 55 | "node_modules/binarypack": { 56 | "version": "0.0.4", 57 | "resolved": "https://registry.npmjs.org/binarypack/-/binarypack-0.0.4.tgz", 58 | "integrity": "sha1-xKtKysfGWeIo7QsLczVibJjWyJA=", 59 | "dependencies": { 60 | "buffercursor": ">=0.0.3" 61 | }, 62 | "engines": { 63 | "node": ">=0.6.0" 64 | } 65 | }, 66 | "node_modules/buffercursor": { 67 | "version": "0.0.12", 68 | "resolved": "https://registry.npmjs.org/buffercursor/-/buffercursor-0.0.12.tgz", 69 | "integrity": "sha1-eKmn9DQ659ggqJmazIDeWR4lp3k=", 70 | "dependencies": { 71 | "verror": "^1.4.0" 72 | }, 73 | "engines": { 74 | "node": ">= 0.5.0" 75 | } 76 | }, 77 | "node_modules/commander": { 78 | "version": "0.6.1", 79 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 80 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 81 | "engines": { 82 | "node": ">= 0.4.x" 83 | } 84 | }, 85 | "node_modules/core-util-is": { 86 | "version": "1.0.2", 87 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 88 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 89 | "license": "MIT" 90 | }, 91 | "node_modules/debug": { 92 | "version": "0.7.4", 93 | "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", 94 | "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", 95 | "engines": { 96 | "node": "*" 97 | } 98 | }, 99 | "node_modules/extsprintf": { 100 | "version": "1.4.0", 101 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", 102 | "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=", 103 | "engines": [ 104 | "node >=0.6.0" 105 | ], 106 | "license": "MIT" 107 | }, 108 | "node_modules/eyes": { 109 | "version": "0.1.8", 110 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 111 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", 112 | "engines": { 113 | "node": "> 0.1.90" 114 | } 115 | }, 116 | "node_modules/fft": { 117 | "version": "0.2.1", 118 | "resolved": "https://registry.npmjs.org/fft/-/fft-0.2.1.tgz", 119 | "integrity": "sha1-EERVT9uhoLlsSEPV3qhSXKs2Iao=", 120 | "engines": { 121 | "node": ">=0.6.0-0" 122 | } 123 | }, 124 | "node_modules/mkdirp": { 125 | "version": "0.0.7", 126 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", 127 | "integrity": "sha1-2JtPDkw+XlylQjWTFnXglP4aUHI=", 128 | "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", 129 | "license": "MIT/X11", 130 | "engines": { 131 | "node": "*" 132 | } 133 | }, 134 | "node_modules/nan": { 135 | "version": "2.14.2", 136 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", 137 | "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", 138 | "license": "MIT" 139 | }, 140 | "node_modules/node-waveheader": { 141 | "name": "waveheader", 142 | "version": "0.0.2", 143 | "resolved": "git+ssh://git@github.com/mrose17/node-waveheader.git#268ea1b55ad7bb818340ae230dfaae4f4c59f564", 144 | "dependencies": { 145 | "debug": "~0.7.2" 146 | } 147 | }, 148 | "node_modules/options": { 149 | "version": "0.0.6", 150 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", 151 | "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", 152 | "engines": { 153 | "node": ">=0.4.0" 154 | } 155 | }, 156 | "node_modules/portfinder": { 157 | "version": "0.2.1", 158 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", 159 | "integrity": "sha1-srmwFk+eF/o6nH2yME0KdRQMca0=", 160 | "dependencies": { 161 | "mkdirp": "0.0.x" 162 | }, 163 | "engines": { 164 | "node": ">= 0.4.0" 165 | } 166 | }, 167 | "node_modules/streamers": { 168 | "version": "0.1.1", 169 | "resolved": "https://registry.npmjs.org/streamers/-/streamers-0.1.1.tgz", 170 | "integrity": "sha1-OHk+rhRHAhaC7TYdHjEGrFlrDFU=", 171 | "dependencies": { 172 | "underscore": "1.2.3", 173 | "vows": "0.6.1" 174 | }, 175 | "engines": { 176 | "node": "*" 177 | } 178 | }, 179 | "node_modules/streamws": { 180 | "version": "0.1.1", 181 | "resolved": "https://registry.npmjs.org/streamws/-/streamws-0.1.1.tgz", 182 | "integrity": "sha1-lcM7XseVtShTYen3OZPgBDjTOxo=", 183 | "hasInstallScript": true, 184 | "dependencies": { 185 | "commander": "~0.6.1", 186 | "options": "latest", 187 | "tinycolor": "0.x" 188 | }, 189 | "engines": { 190 | "node": ">=0.6.0" 191 | } 192 | }, 193 | "node_modules/tinycolor": { 194 | "version": "0.0.1", 195 | "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", 196 | "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=", 197 | "engines": { 198 | "node": ">=0.4.0" 199 | } 200 | }, 201 | "node_modules/underscore": { 202 | "version": "1.2.3", 203 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.2.3.tgz", 204 | "integrity": "sha1-Ebh02nD0aD19SLuitEvh5gDS9s8=", 205 | "engines": { 206 | "node": "*" 207 | } 208 | }, 209 | "node_modules/verror": { 210 | "version": "1.10.0", 211 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 212 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 213 | "engines": [ 214 | "node >=0.6.0" 215 | ], 216 | "license": "MIT", 217 | "dependencies": { 218 | "assert-plus": "^1.0.0", 219 | "core-util-is": "1.0.2", 220 | "extsprintf": "^1.2.0" 221 | } 222 | }, 223 | "node_modules/vows": { 224 | "version": "0.6.1", 225 | "resolved": "https://registry.npmjs.org/vows/-/vows-0.6.1.tgz", 226 | "integrity": "sha1-DTzOx2eUt6yGALXHANaJhkpkCis=", 227 | "dependencies": { 228 | "eyes": ">=0.1.6" 229 | }, 230 | "bin": { 231 | "vows": "bin/vows" 232 | }, 233 | "engines": { 234 | "node": ">=0.2.6" 235 | } 236 | } 237 | }, 238 | "dependencies": { 239 | "assert-plus": { 240 | "version": "1.0.0", 241 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 242 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 243 | }, 244 | "audio-streamer": { 245 | "version": "0.1.0", 246 | "resolved": "https://registry.npmjs.org/audio-streamer/-/audio-streamer-0.1.0.tgz", 247 | "integrity": "sha1-kd9oKWe5b9j3aTFiQR/2sMdayMU=", 248 | "requires": { 249 | "binaryjs": ">= 0.0.1" 250 | } 251 | }, 252 | "binaryjs": { 253 | "version": "0.2.1", 254 | "resolved": "https://registry.npmjs.org/binaryjs/-/binaryjs-0.2.1.tgz", 255 | "integrity": "sha1-KO20CxgwJ49VmOsAw2eSU+jpne4=", 256 | "requires": { 257 | "binarypack": ">=0.0.4", 258 | "streamers": ">=0.1.0", 259 | "streamws": ">=0.1.1" 260 | } 261 | }, 262 | "binarypack": { 263 | "version": "0.0.4", 264 | "resolved": "https://registry.npmjs.org/binarypack/-/binarypack-0.0.4.tgz", 265 | "integrity": "sha1-xKtKysfGWeIo7QsLczVibJjWyJA=", 266 | "requires": { 267 | "buffercursor": ">=0.0.3" 268 | } 269 | }, 270 | "buffercursor": { 271 | "version": "0.0.12", 272 | "resolved": "https://registry.npmjs.org/buffercursor/-/buffercursor-0.0.12.tgz", 273 | "integrity": "sha1-eKmn9DQ659ggqJmazIDeWR4lp3k=", 274 | "requires": { 275 | "verror": "^1.4.0" 276 | } 277 | }, 278 | "commander": { 279 | "version": "0.6.1", 280 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 281 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=" 282 | }, 283 | "core-util-is": { 284 | "version": "1.0.2", 285 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 286 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 287 | }, 288 | "debug": { 289 | "version": "0.7.4", 290 | "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", 291 | "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" 292 | }, 293 | "extsprintf": { 294 | "version": "1.4.0", 295 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", 296 | "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=" 297 | }, 298 | "eyes": { 299 | "version": "0.1.8", 300 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 301 | "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" 302 | }, 303 | "fft": { 304 | "version": "0.2.1", 305 | "resolved": "https://registry.npmjs.org/fft/-/fft-0.2.1.tgz", 306 | "integrity": "sha1-EERVT9uhoLlsSEPV3qhSXKs2Iao=" 307 | }, 308 | "mkdirp": { 309 | "version": "0.0.7", 310 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", 311 | "integrity": "sha1-2JtPDkw+XlylQjWTFnXglP4aUHI=" 312 | }, 313 | "nan": { 314 | "version": "2.14.2", 315 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", 316 | "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" 317 | }, 318 | "node-waveheader": { 319 | "version": "git+ssh://git@github.com/mrose17/node-waveheader.git#268ea1b55ad7bb818340ae230dfaae4f4c59f564", 320 | "from": "node-waveheader@git://github.com/mrose17/node-waveheader.git", 321 | "requires": { 322 | "debug": "~0.7.2" 323 | } 324 | }, 325 | "options": { 326 | "version": "0.0.6", 327 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", 328 | "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" 329 | }, 330 | "portfinder": { 331 | "version": "0.2.1", 332 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", 333 | "integrity": "sha1-srmwFk+eF/o6nH2yME0KdRQMca0=", 334 | "requires": { 335 | "mkdirp": "0.0.x" 336 | } 337 | }, 338 | "streamers": { 339 | "version": "0.1.1", 340 | "resolved": "https://registry.npmjs.org/streamers/-/streamers-0.1.1.tgz", 341 | "integrity": "sha1-OHk+rhRHAhaC7TYdHjEGrFlrDFU=", 342 | "requires": { 343 | "underscore": "1.2.3", 344 | "vows": "0.6.1" 345 | } 346 | }, 347 | "streamws": { 348 | "version": "0.1.1", 349 | "resolved": "https://registry.npmjs.org/streamws/-/streamws-0.1.1.tgz", 350 | "integrity": "sha1-lcM7XseVtShTYen3OZPgBDjTOxo=", 351 | "requires": { 352 | "commander": "~0.6.1", 353 | "options": "latest", 354 | "tinycolor": "0.x" 355 | } 356 | }, 357 | "tinycolor": { 358 | "version": "0.0.1", 359 | "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", 360 | "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=" 361 | }, 362 | "underscore": { 363 | "version": "1.2.3", 364 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.2.3.tgz", 365 | "integrity": "sha1-Ebh02nD0aD19SLuitEvh5gDS9s8=" 366 | }, 367 | "verror": { 368 | "version": "1.10.0", 369 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 370 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 371 | "requires": { 372 | "assert-plus": "^1.0.0", 373 | "core-util-is": "1.0.2", 374 | "extsprintf": "^1.2.0" 375 | } 376 | }, 377 | "vows": { 378 | "version": "0.6.1", 379 | "resolved": "https://registry.npmjs.org/vows/-/vows-0.6.1.tgz", 380 | "integrity": "sha1-DTzOx2eUt6yGALXHANaJhkpkCis=", 381 | "requires": { 382 | "eyes": ">=0.1.6" 383 | } 384 | } 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-core-audio", 3 | "version": "0.5.1", 4 | "author": "Mike Vegeto (http://mikevegeto.com/)", 5 | "contributors": [ 6 | "Marc J. Schmidt (http://marcjschmidt.de/)", 7 | "Jeremiah Senkpiel (http://searchbeam.jit.su/)", 8 | "Daniel Church (https://github.com/anprogrammer/)" 9 | ], 10 | "dependencies": { 11 | "audio-streamer": ">= 0.1.0", 12 | "fft": "~0.2.1", 13 | "nan": "^2.14.2", 14 | "node-waveheader": "git://github.com/mrose17/node-waveheader.git", 15 | "portfinder": "0.2.1" 16 | }, 17 | "description": "Core native node.js audio functionality, including sound card access and audio streaming", 18 | "main": "./node-core-audio", 19 | "scripts": { 20 | "test": "node test/test.js" 21 | }, 22 | "engines": { 23 | "node": ">=0.12.0" 24 | }, 25 | "keywords": [ 26 | "audio", 27 | "dsp", 28 | "processing", 29 | "portaudio", 30 | "sound", 31 | "synth", 32 | "signal", 33 | "streaming", 34 | "buffer" 35 | ], 36 | "license": "MIT", 37 | "repository": { 38 | "type": "git", 39 | "url": "http://github.com/ZECTBynmo/node-core-audio.git" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /portaudio/portaudio.h: -------------------------------------------------------------------------------- 1 | #ifndef PORTAUDIO_H 2 | #define PORTAUDIO_H 3 | /* 4 | * $Id: portaudio.h 1745 2011-08-25 17:44:01Z rossb $ 5 | * PortAudio Portable Real-Time Audio Library 6 | * PortAudio API Header File 7 | * Latest version available at: http://www.portaudio.com/ 8 | * 9 | * Copyright (c) 1999-2002 Ross Bencina and Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup public_header 44 | @brief The portable PortAudio API. 45 | */ 46 | 47 | 48 | #ifdef __cplusplus 49 | extern "C" 50 | { 51 | #endif /* __cplusplus */ 52 | 53 | 54 | /** Retrieve the release number of the currently running PortAudio build, 55 | eg 1900. 56 | */ 57 | int Pa_GetVersion( void ); 58 | 59 | 60 | /** Retrieve a textual description of the current PortAudio build, 61 | eg "PortAudio V19-devel 13 October 2002". 62 | */ 63 | const char* Pa_GetVersionText( void ); 64 | 65 | 66 | /** Error codes returned by PortAudio functions. 67 | Note that with the exception of paNoError, all PaErrorCodes are negative. 68 | */ 69 | 70 | typedef int PaError; 71 | typedef enum PaErrorCode 72 | { 73 | paNoError = 0, 74 | 75 | paNotInitialized = -10000, 76 | paUnanticipatedHostError, 77 | paInvalidChannelCount, 78 | paInvalidSampleRate, 79 | paInvalidDevice, 80 | paInvalidFlag, 81 | paSampleFormatNotSupported, 82 | paBadIODeviceCombination, 83 | paInsufficientMemory, 84 | paBufferTooBig, 85 | paBufferTooSmall, 86 | paNullCallback, 87 | paBadStreamPtr, 88 | paTimedOut, 89 | paInternalError, 90 | paDeviceUnavailable, 91 | paIncompatibleHostApiSpecificStreamInfo, 92 | paStreamIsStopped, 93 | paStreamIsNotStopped, 94 | paInputOverflowed, 95 | paOutputUnderflowed, 96 | paHostApiNotFound, 97 | paInvalidHostApi, 98 | paCanNotReadFromACallbackStream, 99 | paCanNotWriteToACallbackStream, 100 | paCanNotReadFromAnOutputOnlyStream, 101 | paCanNotWriteToAnInputOnlyStream, 102 | paIncompatibleStreamHostApi, 103 | paBadBufferPtr 104 | } PaErrorCode; 105 | 106 | 107 | /** Translate the supplied PortAudio error code into a human readable 108 | message. 109 | */ 110 | const char *Pa_GetErrorText( PaError errorCode ); 111 | 112 | 113 | /** Library initialization function - call this before using PortAudio. 114 | This function initializes internal data structures and prepares underlying 115 | host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), 116 | and Pa_GetErrorText(), this function MUST be called before using any other 117 | PortAudio API functions. 118 | 119 | If Pa_Initialize() is called multiple times, each successful 120 | call must be matched with a corresponding call to Pa_Terminate(). 121 | Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not 122 | required to be fully nested. 123 | 124 | Note that if Pa_Initialize() returns an error code, Pa_Terminate() should 125 | NOT be called. 126 | 127 | @return paNoError if successful, otherwise an error code indicating the cause 128 | of failure. 129 | 130 | @see Pa_Terminate 131 | */ 132 | PaError Pa_Initialize( void ); 133 | 134 | 135 | /** Library termination function - call this when finished using PortAudio. 136 | This function deallocates all resources allocated by PortAudio since it was 137 | initialized by a call to Pa_Initialize(). In cases where Pa_Initialise() has 138 | been called multiple times, each call must be matched with a corresponding call 139 | to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically 140 | close any PortAudio streams that are still open. 141 | 142 | Pa_Terminate() MUST be called before exiting a program which uses PortAudio. 143 | Failure to do so may result in serious resource leaks, such as audio devices 144 | not being available until the next reboot. 145 | 146 | @return paNoError if successful, otherwise an error code indicating the cause 147 | of failure. 148 | 149 | @see Pa_Initialize 150 | */ 151 | PaError Pa_Terminate( void ); 152 | 153 | 154 | 155 | /** The type used to refer to audio devices. Values of this type usually 156 | range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice 157 | and paUseHostApiSpecificDeviceSpecification values. 158 | 159 | @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification 160 | */ 161 | typedef int PaDeviceIndex; 162 | 163 | 164 | /** A special PaDeviceIndex value indicating that no device is available, 165 | or should be used. 166 | 167 | @see PaDeviceIndex 168 | */ 169 | #define paNoDevice ((PaDeviceIndex)-1) 170 | 171 | 172 | /** A special PaDeviceIndex value indicating that the device(s) to be used 173 | are specified in the host api specific stream info structure. 174 | 175 | @see PaDeviceIndex 176 | */ 177 | #define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) 178 | 179 | 180 | /* Host API enumeration mechanism */ 181 | 182 | /** The type used to enumerate to host APIs at runtime. Values of this type 183 | range from 0 to (Pa_GetHostApiCount()-1). 184 | 185 | @see Pa_GetHostApiCount 186 | */ 187 | typedef int PaHostApiIndex; 188 | 189 | 190 | /** Retrieve the number of available host APIs. Even if a host API is 191 | available it may have no devices available. 192 | 193 | @return A non-negative value indicating the number of available host APIs 194 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 195 | or an error is encountered. 196 | 197 | @see PaHostApiIndex 198 | */ 199 | PaHostApiIndex Pa_GetHostApiCount( void ); 200 | 201 | 202 | /** Retrieve the index of the default host API. The default host API will be 203 | the lowest common denominator host API on the current platform and is 204 | unlikely to provide the best performance. 205 | 206 | @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) 207 | indicating the default host API index or, a PaErrorCode (which are always 208 | negative) if PortAudio is not initialized or an error is encountered. 209 | */ 210 | PaHostApiIndex Pa_GetDefaultHostApi( void ); 211 | 212 | 213 | /** Unchanging unique identifiers for each supported host API. This type 214 | is used in the PaHostApiInfo structure. The values are guaranteed to be 215 | unique and to never change, thus allowing code to be written that 216 | conditionally uses host API specific extensions. 217 | 218 | New type ids will be allocated when support for a host API reaches 219 | "public alpha" status, prior to that developers should use the 220 | paInDevelopment type id. 221 | 222 | @see PaHostApiInfo 223 | */ 224 | typedef enum PaHostApiTypeId 225 | { 226 | paInDevelopment=0, /* use while developing support for a new host API */ 227 | paDirectSound=1, 228 | paMME=2, 229 | paASIO=3, 230 | paSoundManager=4, 231 | paCoreAudio=5, 232 | paOSS=7, 233 | paALSA=8, 234 | paAL=9, 235 | paBeOS=10, 236 | paWDMKS=11, 237 | paJACK=12, 238 | paWASAPI=13, 239 | paAudioScienceHPI=14 240 | } PaHostApiTypeId; 241 | 242 | 243 | /** A structure containing information about a particular host API. */ 244 | 245 | typedef struct PaHostApiInfo 246 | { 247 | /** this is struct version 1 */ 248 | int structVersion; 249 | /** The well known unique identifier of this host API @see PaHostApiTypeId */ 250 | PaHostApiTypeId type; 251 | /** A textual description of the host API for display on user interfaces. */ 252 | const char *name; 253 | 254 | /** The number of devices belonging to this host API. This field may be 255 | used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate 256 | all devices for this host API. 257 | @see Pa_HostApiDeviceIndexToDeviceIndex 258 | */ 259 | int deviceCount; 260 | 261 | /** The default input device for this host API. The value will be a 262 | device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice 263 | if no default input device is available. 264 | */ 265 | PaDeviceIndex defaultInputDevice; 266 | 267 | /** The default output device for this host API. The value will be a 268 | device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice 269 | if no default output device is available. 270 | */ 271 | PaDeviceIndex defaultOutputDevice; 272 | 273 | } PaHostApiInfo; 274 | 275 | 276 | /** Retrieve a pointer to a structure containing information about a specific 277 | host Api. 278 | 279 | @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) 280 | 281 | @return A pointer to an immutable PaHostApiInfo structure describing 282 | a specific host API. If the hostApi parameter is out of range or an error 283 | is encountered, the function returns NULL. 284 | 285 | The returned structure is owned by the PortAudio implementation and must not 286 | be manipulated or freed. The pointer is only guaranteed to be valid between 287 | calls to Pa_Initialize() and Pa_Terminate(). 288 | */ 289 | const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); 290 | 291 | 292 | /** Convert a static host API unique identifier, into a runtime 293 | host API index. 294 | 295 | @param type A unique host API identifier belonging to the PaHostApiTypeId 296 | enumeration. 297 | 298 | @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, 299 | a PaErrorCode (which are always negative) if PortAudio is not initialized 300 | or an error is encountered. 301 | 302 | The paHostApiNotFound error code indicates that the host API specified by the 303 | type parameter is not available. 304 | 305 | @see PaHostApiTypeId 306 | */ 307 | PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); 308 | 309 | 310 | /** Convert a host-API-specific device index to standard PortAudio device index. 311 | This function may be used in conjunction with the deviceCount field of 312 | PaHostApiInfo to enumerate all devices for the specified host API. 313 | 314 | @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) 315 | 316 | @param hostApiDeviceIndex A valid per-host device index in the range 317 | 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) 318 | 319 | @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) 320 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 321 | or an error is encountered. 322 | 323 | A paInvalidHostApi error code indicates that the host API index specified by 324 | the hostApi parameter is out of range. 325 | 326 | A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter 327 | is out of range. 328 | 329 | @see PaHostApiInfo 330 | */ 331 | PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, 332 | int hostApiDeviceIndex ); 333 | 334 | 335 | 336 | /** Structure used to return information about a host error condition. 337 | */ 338 | typedef struct PaHostErrorInfo{ 339 | PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ 340 | long errorCode; /**< the error code returned */ 341 | const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ 342 | }PaHostErrorInfo; 343 | 344 | 345 | /** Return information about the last host error encountered. The error 346 | information returned by Pa_GetLastHostErrorInfo() will never be modified 347 | asynchronously by errors occurring in other PortAudio owned threads 348 | (such as the thread that manages the stream callback.) 349 | 350 | This function is provided as a last resort, primarily to enhance debugging 351 | by providing clients with access to all available error information. 352 | 353 | @return A pointer to an immutable structure constraining information about 354 | the host error. The values in this structure will only be valid if a 355 | PortAudio function has previously returned the paUnanticipatedHostError 356 | error code. 357 | */ 358 | const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); 359 | 360 | 361 | 362 | /* Device enumeration and capabilities */ 363 | 364 | /** Retrieve the number of available devices. The number of available devices 365 | may be zero. 366 | 367 | @return A non-negative value indicating the number of available devices or, 368 | a PaErrorCode (which are always negative) if PortAudio is not initialized 369 | or an error is encountered. 370 | */ 371 | PaDeviceIndex Pa_GetDeviceCount( void ); 372 | 373 | 374 | /** Retrieve the index of the default input device. The result can be 375 | used in the inputDevice parameter to Pa_OpenStream(). 376 | 377 | @return The default input device index for the default host API, or paNoDevice 378 | if no default input device is available or an error was encountered. 379 | */ 380 | PaDeviceIndex Pa_GetDefaultInputDevice( void ); 381 | 382 | 383 | /** Retrieve the index of the default output device. The result can be 384 | used in the outputDevice parameter to Pa_OpenStream(). 385 | 386 | @return The default output device index for the default host API, or paNoDevice 387 | if no default output device is available or an error was encountered. 388 | 389 | @note 390 | On the PC, the user can specify a default device by 391 | setting an environment variable. For example, to use device #1. 392 |
 393 |  set PA_RECOMMENDED_OUTPUT_DEVICE=1
 394 | 
395 | The user should first determine the available device ids by using 396 | the supplied application "pa_devs". 397 | */ 398 | PaDeviceIndex Pa_GetDefaultOutputDevice( void ); 399 | 400 | 401 | /** The type used to represent monotonic time in seconds. PaTime is 402 | used for the fields of the PaStreamCallbackTimeInfo argument to the 403 | PaStreamCallback and as the result of Pa_GetStreamTime(). 404 | 405 | PaTime values have unspecified origin. 406 | 407 | @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime 408 | */ 409 | typedef double PaTime; 410 | 411 | 412 | /** A type used to specify one or more sample formats. Each value indicates 413 | a possible format for sound data passed to and from the stream callback, 414 | Pa_ReadStream and Pa_WriteStream. 415 | 416 | The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 417 | and aUInt8 are usually implemented by all implementations. 418 | 419 | The floating point representation (paFloat32) uses +1.0 and -1.0 as the 420 | maximum and minimum respectively. 421 | 422 | paUInt8 is an unsigned 8 bit format where 128 is considered "ground" 423 | 424 | The paNonInterleaved flag indicates that audio data is passed as an array 425 | of pointers to separate buffers, one buffer for each channel. Usually, 426 | when this flag is not used, audio data is passed as a single buffer with 427 | all channels interleaved. 428 | 429 | @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo 430 | @see paFloat32, paInt16, paInt32, paInt24, paInt8 431 | @see paUInt8, paCustomFormat, paNonInterleaved 432 | */ 433 | typedef unsigned long PaSampleFormat; 434 | 435 | 436 | #define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ 437 | #define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ 438 | #define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ 439 | #define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ 440 | #define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ 441 | #define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ 442 | #define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ 443 | 444 | #define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ 445 | 446 | /** A structure providing information and capabilities of PortAudio devices. 447 | Devices may support input, output or both input and output. 448 | */ 449 | typedef struct PaDeviceInfo 450 | { 451 | int structVersion; /* this is struct version 2 */ 452 | const char *name; 453 | PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/ 454 | 455 | int maxInputChannels; 456 | int maxOutputChannels; 457 | 458 | /** Default latency values for interactive performance. */ 459 | PaTime defaultLowInputLatency; 460 | PaTime defaultLowOutputLatency; 461 | /** Default latency values for robust non-interactive applications (eg. playing sound files). */ 462 | PaTime defaultHighInputLatency; 463 | PaTime defaultHighOutputLatency; 464 | 465 | double defaultSampleRate; 466 | } PaDeviceInfo; 467 | 468 | 469 | /** Retrieve a pointer to a PaDeviceInfo structure containing information 470 | about the specified device. 471 | @return A pointer to an immutable PaDeviceInfo structure. If the device 472 | parameter is out of range the function returns NULL. 473 | 474 | @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) 475 | 476 | @note PortAudio manages the memory referenced by the returned pointer, 477 | the client must not manipulate or free the memory. The pointer is only 478 | guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). 479 | 480 | @see PaDeviceInfo, PaDeviceIndex 481 | */ 482 | const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); 483 | 484 | 485 | /** Parameters for one direction (input or output) of a stream. 486 | */ 487 | typedef struct PaStreamParameters 488 | { 489 | /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) 490 | specifying the device to be used or the special constant 491 | paUseHostApiSpecificDeviceSpecification which indicates that the actual 492 | device(s) to use are specified in hostApiSpecificStreamInfo. 493 | This field must not be set to paNoDevice. 494 | */ 495 | PaDeviceIndex device; 496 | 497 | /** The number of channels of sound to be delivered to the 498 | stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). 499 | It can range from 1 to the value of maxInputChannels in the 500 | PaDeviceInfo record for the device specified by the device parameter. 501 | */ 502 | int channelCount; 503 | 504 | /** The sample format of the buffer provided to the stream callback, 505 | a_ReadStream() or Pa_WriteStream(). It may be any of the formats described 506 | by the PaSampleFormat enumeration. 507 | */ 508 | PaSampleFormat sampleFormat; 509 | 510 | /** The desired latency in seconds. Where practical, implementations should 511 | configure their latency based on these parameters, otherwise they may 512 | choose the closest viable latency instead. Unless the suggested latency 513 | is greater than the absolute upper limit for the device implementations 514 | should round the suggestedLatency up to the next practical value - ie to 515 | provide an equal or higher latency than suggestedLatency wherever possible. 516 | Actual latency values for an open stream may be retrieved using the 517 | inputLatency and outputLatency fields of the PaStreamInfo structure 518 | returned by Pa_GetStreamInfo(). 519 | @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo 520 | */ 521 | PaTime suggestedLatency; 522 | 523 | /** An optional pointer to a host api specific data structure 524 | containing additional information for device setup and/or stream processing. 525 | hostApiSpecificStreamInfo is never required for correct operation, 526 | if not used it should be set to NULL. 527 | */ 528 | void *hostApiSpecificStreamInfo; 529 | 530 | } PaStreamParameters; 531 | 532 | 533 | /** Return code for Pa_IsFormatSupported indicating success. */ 534 | #define paFormatIsSupported (0) 535 | 536 | /** Determine whether it would be possible to open a stream with the specified 537 | parameters. 538 | 539 | @param inputParameters A structure that describes the input parameters used to 540 | open a stream. The suggestedLatency field is ignored. See PaStreamParameters 541 | for a description of these parameters. inputParameters must be NULL for 542 | output-only streams. 543 | 544 | @param outputParameters A structure that describes the output parameters used 545 | to open a stream. The suggestedLatency field is ignored. See PaStreamParameters 546 | for a description of these parameters. outputParameters must be NULL for 547 | input-only streams. 548 | 549 | @param sampleRate The required sampleRate. For full-duplex streams it is the 550 | sample rate for both input and output 551 | 552 | @return Returns 0 if the format is supported, and an error code indicating why 553 | the format is not supported otherwise. The constant paFormatIsSupported is 554 | provided to compare with the return value for success. 555 | 556 | @see paFormatIsSupported, PaStreamParameters 557 | */ 558 | PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, 559 | const PaStreamParameters *outputParameters, 560 | double sampleRate ); 561 | 562 | 563 | 564 | /* Streaming types and functions */ 565 | 566 | 567 | /** 568 | A single PaStream can provide multiple channels of real-time 569 | streaming audio input and output to a client application. A stream 570 | provides access to audio hardware represented by one or more 571 | PaDevices. Depending on the underlying Host API, it may be possible 572 | to open multiple streams using the same device, however this behavior 573 | is implementation defined. Portable applications should assume that 574 | a PaDevice may be simultaneously used by at most one PaStream. 575 | 576 | Pointers to PaStream objects are passed between PortAudio functions that 577 | operate on streams. 578 | 579 | @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, 580 | Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, 581 | Pa_GetStreamTime, Pa_GetStreamCpuLoad 582 | 583 | */ 584 | typedef void PaStream; 585 | 586 | 587 | /** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() 588 | or Pa_OpenDefaultStream() to indicate that the stream callback will 589 | accept buffers of any size. 590 | */ 591 | #define paFramesPerBufferUnspecified (0) 592 | 593 | 594 | /** Flags used to control the behavior of a stream. They are passed as 595 | parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be 596 | ORed together. 597 | 598 | @see Pa_OpenStream, Pa_OpenDefaultStream 599 | @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, 600 | paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags 601 | */ 602 | typedef unsigned long PaStreamFlags; 603 | 604 | /** @see PaStreamFlags */ 605 | #define paNoFlag ((PaStreamFlags) 0) 606 | 607 | /** Disable default clipping of out of range samples. 608 | @see PaStreamFlags 609 | */ 610 | #define paClipOff ((PaStreamFlags) 0x00000001) 611 | 612 | /** Disable default dithering. 613 | @see PaStreamFlags 614 | */ 615 | #define paDitherOff ((PaStreamFlags) 0x00000002) 616 | 617 | /** Flag requests that where possible a full duplex stream will not discard 618 | overflowed input samples without calling the stream callback. This flag is 619 | only valid for full duplex callback streams and only when used in combination 620 | with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using 621 | this flag incorrectly results in a paInvalidFlag error being returned from 622 | Pa_OpenStream and Pa_OpenDefaultStream. 623 | 624 | @see PaStreamFlags, paFramesPerBufferUnspecified 625 | */ 626 | #define paNeverDropInput ((PaStreamFlags) 0x00000004) 627 | 628 | /** Call the stream callback to fill initial output buffers, rather than the 629 | default behavior of priming the buffers with zeros (silence). This flag has 630 | no effect for input-only and blocking read/write streams. 631 | 632 | @see PaStreamFlags 633 | */ 634 | #define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) 635 | 636 | /** A mask specifying the platform specific bits. 637 | @see PaStreamFlags 638 | */ 639 | #define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) 640 | 641 | /** 642 | Timing information for the buffers passed to the stream callback. 643 | 644 | Time values are expressed in seconds and are synchronised with the time base used by Pa_GetStreamTime() for the associated stream. 645 | 646 | @see PaStreamCallback, Pa_GetStreamTime 647 | */ 648 | typedef struct PaStreamCallbackTimeInfo{ 649 | PaTime inputBufferAdcTime; /**< The time when the first sample of the input buffer was captured at the ADC input */ 650 | PaTime currentTime; /**< The time when the stream callback was invoked */ 651 | PaTime outputBufferDacTime; /**< The time when the first sample of the output buffer will output the DAC */ 652 | } PaStreamCallbackTimeInfo; 653 | 654 | 655 | /** 656 | Flag bit constants for the statusFlags to PaStreamCallback. 657 | 658 | @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, 659 | paPrimingOutput 660 | */ 661 | typedef unsigned long PaStreamCallbackFlags; 662 | 663 | /** In a stream opened with paFramesPerBufferUnspecified, indicates that 664 | input data is all silence (zeros) because no real data is available. In a 665 | stream opened without paFramesPerBufferUnspecified, it indicates that one or 666 | more zero samples have been inserted into the input buffer to compensate 667 | for an input underflow. 668 | @see PaStreamCallbackFlags 669 | */ 670 | #define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) 671 | 672 | /** In a stream opened with paFramesPerBufferUnspecified, indicates that data 673 | prior to the first sample of the input buffer was discarded due to an 674 | overflow, possibly because the stream callback is using too much CPU time. 675 | Otherwise indicates that data prior to one or more samples in the 676 | input buffer was discarded. 677 | @see PaStreamCallbackFlags 678 | */ 679 | #define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) 680 | 681 | /** Indicates that output data (or a gap) was inserted, possibly because the 682 | stream callback is using too much CPU time. 683 | @see PaStreamCallbackFlags 684 | */ 685 | #define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) 686 | 687 | /** Indicates that output data will be discarded because no room is available. 688 | @see PaStreamCallbackFlags 689 | */ 690 | #define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) 691 | 692 | /** Some of all of the output data will be used to prime the stream, input 693 | data may be zero. 694 | @see PaStreamCallbackFlags 695 | */ 696 | #define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) 697 | 698 | /** 699 | Allowable return values for the PaStreamCallback. 700 | @see PaStreamCallback 701 | */ 702 | typedef enum PaStreamCallbackResult 703 | { 704 | paContinue=0, /**< Signal that the stream should continue invoking the callback and processing audio. */ 705 | paComplete=1, /**< Signal that the stream should stop invoking the callback and finish once all output samples have played. */ 706 | paAbort=2 /**< Signal that the stream should stop invoking the callback and finish as soon as possible. */ 707 | } PaStreamCallbackResult; 708 | 709 | 710 | /** 711 | Functions of type PaStreamCallback are implemented by PortAudio clients. 712 | They consume, process or generate audio in response to requests from an 713 | active PortAudio stream. 714 | 715 | When a stream is running, PortAudio calls the stream callback periodically. 716 | The callback function is responsible for processing buffers of audio samples 717 | passed via the input and output parameters. 718 | 719 | The PortAudio stream callback runs at very high or real-time priority. 720 | It is required to consistently meet its time deadlines. Do not allocate 721 | memory, access the file system, call library functions or call other functions 722 | from the stream callback that may block or take an unpredictable amount of 723 | time to complete. 724 | 725 | In order for a stream to maintain glitch-free operation the callback 726 | must consume and return audio data faster than it is recorded and/or 727 | played. PortAudio anticipates that each callback invocation may execute for 728 | a duration approaching the duration of frameCount audio frames at the stream 729 | sample rate. It is reasonable to expect to be able to utilise 70% or more of 730 | the available CPU time in the PortAudio callback. However, due to buffer size 731 | adaption and other factors, not all host APIs are able to guarantee audio 732 | stability under heavy CPU load with arbitrary fixed callback buffer sizes. 733 | When high callback CPU utilisation is required the most robust behavior 734 | can be achieved by using paFramesPerBufferUnspecified as the 735 | Pa_OpenStream() framesPerBuffer parameter. 736 | 737 | @param input and @param output are either arrays of interleaved samples or; 738 | if non-interleaved samples were requested using the paNonInterleaved sample 739 | format flag, an array of buffer pointers, one non-interleaved buffer for 740 | each channel. 741 | 742 | The format, packing and number of channels used by the buffers are 743 | determined by parameters to Pa_OpenStream(). 744 | 745 | @param frameCount The number of sample frames to be processed by 746 | the stream callback. 747 | 748 | @param timeInfo Timestamps indicating the ADC capture time of the first sample 749 | in the input buffer, the DAC output time of the first sample in the output buffer 750 | and the time the callback was invoked. 751 | See PaStreamCallbackTimeInfo and Pa_GetStreamTime() 752 | 753 | @param statusFlags Flags indicating whether input and/or output buffers 754 | have been inserted or will be dropped to overcome underflow or overflow 755 | conditions. 756 | 757 | @param userData The value of a user supplied pointer passed to 758 | Pa_OpenStream() intended for storing synthesis data etc. 759 | 760 | @return 761 | The stream callback should return one of the values in the 762 | ::PaStreamCallbackResult enumeration. To ensure that the callback continues 763 | to be called, it should return paContinue (0). Either paComplete or paAbort 764 | can be returned to finish stream processing, after either of these values is 765 | returned the callback will not be called again. If paAbort is returned the 766 | stream will finish as soon as possible. If paComplete is returned, the stream 767 | will continue until all buffers generated by the callback have been played. 768 | This may be useful in applications such as soundfile players where a specific 769 | duration of output is required. However, it is not necessary to utilize this 770 | mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also 771 | be used to stop the stream. The callback must always fill the entire output 772 | buffer irrespective of its return value. 773 | 774 | @see Pa_OpenStream, Pa_OpenDefaultStream 775 | 776 | @note With the exception of Pa_GetStreamCpuLoad() it is not permissible to call 777 | PortAudio API functions from within the stream callback. 778 | */ 779 | typedef int PaStreamCallback( 780 | const void *input, void *output, 781 | unsigned long frameCount, 782 | const PaStreamCallbackTimeInfo* timeInfo, 783 | PaStreamCallbackFlags statusFlags, 784 | void *userData ); 785 | 786 | 787 | /** Opens a stream for either input, output or both. 788 | 789 | @param stream The address of a PaStream pointer which will receive 790 | a pointer to the newly opened stream. 791 | 792 | @param inputParameters A structure that describes the input parameters used by 793 | the opened stream. See PaStreamParameters for a description of these parameters. 794 | inputParameters must be NULL for output-only streams. 795 | 796 | @param outputParameters A structure that describes the output parameters used by 797 | the opened stream. See PaStreamParameters for a description of these parameters. 798 | outputParameters must be NULL for input-only streams. 799 | 800 | @param sampleRate The desired sampleRate. For full-duplex streams it is the 801 | sample rate for both input and output 802 | 803 | @param framesPerBuffer The number of frames passed to the stream callback 804 | function, or the preferred block granularity for a blocking read/write stream. 805 | The special value paFramesPerBufferUnspecified (0) may be used to request that 806 | the stream callback will receive an optimal (and possibly varying) number of 807 | frames based on host requirements and the requested latency settings. 808 | Note: With some host APIs, the use of non-zero framesPerBuffer for a callback 809 | stream may introduce an additional layer of buffering which could introduce 810 | additional latency. PortAudio guarantees that the additional latency 811 | will be kept to the theoretical minimum however, it is strongly recommended 812 | that a non-zero framesPerBuffer value only be used when your algorithm 813 | requires a fixed number of frames per stream callback. 814 | 815 | @param streamFlags Flags which modify the behavior of the streaming process. 816 | This parameter may contain a combination of flags ORed together. Some flags may 817 | only be relevant to certain buffer formats. 818 | 819 | @param streamCallback A pointer to a client supplied function that is responsible 820 | for processing and filling input and output buffers. If this parameter is NULL 821 | the stream will be opened in 'blocking read/write' mode. In blocking mode, 822 | the client can receive sample data using Pa_ReadStream and write sample data 823 | using Pa_WriteStream, the number of samples that may be read or written 824 | without blocking is returned by Pa_GetStreamReadAvailable and 825 | Pa_GetStreamWriteAvailable respectively. 826 | 827 | @param userData A client supplied pointer which is passed to the stream callback 828 | function. It could for example, contain a pointer to instance data necessary 829 | for processing the audio buffers. This parameter is ignored if streamCallback 830 | is NULL. 831 | 832 | @return 833 | Upon success Pa_OpenStream() returns paNoError and places a pointer to a 834 | valid PaStream in the stream argument. The stream is inactive (stopped). 835 | If a call to Pa_OpenStream() fails, a non-zero error code is returned (see 836 | PaError for possible error codes) and the value of stream is invalid. 837 | 838 | @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, 839 | Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable 840 | */ 841 | PaError Pa_OpenStream( PaStream** stream, 842 | const PaStreamParameters *inputParameters, 843 | const PaStreamParameters *outputParameters, 844 | double sampleRate, 845 | unsigned long framesPerBuffer, 846 | PaStreamFlags streamFlags, 847 | PaStreamCallback *streamCallback, 848 | void *userData ); 849 | 850 | 851 | /** A simplified version of Pa_OpenStream() that opens the default input 852 | and/or output devices. 853 | 854 | @param stream The address of a PaStream pointer which will receive 855 | a pointer to the newly opened stream. 856 | 857 | @param numInputChannels The number of channels of sound that will be supplied 858 | to the stream callback or returned by Pa_ReadStream. It can range from 1 to 859 | the value of maxInputChannels in the PaDeviceInfo record for the default input 860 | device. If 0 the stream is opened as an output-only stream. 861 | 862 | @param numOutputChannels The number of channels of sound to be delivered to the 863 | stream callback or passed to Pa_WriteStream. It can range from 1 to the value 864 | of maxOutputChannels in the PaDeviceInfo record for the default output device. 865 | If 0 the stream is opened as an output-only stream. 866 | 867 | @param sampleFormat The sample format of both the input and output buffers 868 | provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. 869 | sampleFormat may be any of the formats described by the PaSampleFormat 870 | enumeration. 871 | 872 | @param sampleRate Same as Pa_OpenStream parameter of the same name. 873 | @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. 874 | @param streamCallback Same as Pa_OpenStream parameter of the same name. 875 | @param userData Same as Pa_OpenStream parameter of the same name. 876 | 877 | @return As for Pa_OpenStream 878 | 879 | @see Pa_OpenStream, PaStreamCallback 880 | */ 881 | PaError Pa_OpenDefaultStream( PaStream** stream, 882 | int numInputChannels, 883 | int numOutputChannels, 884 | PaSampleFormat sampleFormat, 885 | double sampleRate, 886 | unsigned long framesPerBuffer, 887 | PaStreamCallback *streamCallback, 888 | void *userData ); 889 | 890 | 891 | /** Closes an audio stream. If the audio stream is active it 892 | discards any pending buffers as if Pa_AbortStream() had been called. 893 | */ 894 | PaError Pa_CloseStream( PaStream *stream ); 895 | 896 | 897 | /** Functions of type PaStreamFinishedCallback are implemented by PortAudio 898 | clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback 899 | function. Once registered they are called when the stream becomes inactive 900 | (ie once a call to Pa_StopStream() will not block). 901 | A stream will become inactive after the stream callback returns non-zero, 902 | or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio 903 | output, if the stream callback returns paComplete, or Pa_StopStream is called, 904 | the stream finished callback will not be called until all generated sample data 905 | has been played. 906 | 907 | @param userData The userData parameter supplied to Pa_OpenStream() 908 | 909 | @see Pa_SetStreamFinishedCallback 910 | */ 911 | typedef void PaStreamFinishedCallback( void *userData ); 912 | 913 | 914 | /** Register a stream finished callback function which will be called when the 915 | stream becomes inactive. See the description of PaStreamFinishedCallback for 916 | further details about when the callback will be called. 917 | 918 | @param stream a pointer to a PaStream that is in the stopped state - if the 919 | stream is not stopped, the stream's finished callback will remain unchanged 920 | and an error code will be returned. 921 | 922 | @param streamFinishedCallback a pointer to a function with the same signature 923 | as PaStreamFinishedCallback, that will be called when the stream becomes 924 | inactive. Passing NULL for this parameter will un-register a previously 925 | registered stream finished callback function. 926 | 927 | @return on success returns paNoError, otherwise an error code indicating the cause 928 | of the error. 929 | 930 | @see PaStreamFinishedCallback 931 | */ 932 | PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); 933 | 934 | 935 | /** Commences audio processing. 936 | */ 937 | PaError Pa_StartStream( PaStream *stream ); 938 | 939 | 940 | /** Terminates audio processing. It waits until all pending 941 | audio buffers have been played before it returns. 942 | */ 943 | PaError Pa_StopStream( PaStream *stream ); 944 | 945 | 946 | /** Terminates audio processing immediately without waiting for pending 947 | buffers to complete. 948 | */ 949 | PaError Pa_AbortStream( PaStream *stream ); 950 | 951 | 952 | /** Determine whether the stream is stopped. 953 | A stream is considered to be stopped prior to a successful call to 954 | Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. 955 | If a stream callback returns a value other than paContinue the stream is NOT 956 | considered to be stopped. 957 | 958 | @return Returns one (1) when the stream is stopped, zero (0) when 959 | the stream is running or, a PaErrorCode (which are always negative) if 960 | PortAudio is not initialized or an error is encountered. 961 | 962 | @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive 963 | */ 964 | PaError Pa_IsStreamStopped( PaStream *stream ); 965 | 966 | 967 | /** Determine whether the stream is active. 968 | A stream is active after a successful call to Pa_StartStream(), until it 969 | becomes inactive either as a result of a call to Pa_StopStream() or 970 | Pa_AbortStream(), or as a result of a return value other than paContinue from 971 | the stream callback. In the latter case, the stream is considered inactive 972 | after the last buffer has finished playing. 973 | 974 | @return Returns one (1) when the stream is active (ie playing or recording 975 | audio), zero (0) when not playing or, a PaErrorCode (which are always negative) 976 | if PortAudio is not initialized or an error is encountered. 977 | 978 | @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped 979 | */ 980 | PaError Pa_IsStreamActive( PaStream *stream ); 981 | 982 | 983 | 984 | /** A structure containing unchanging information about an open stream. 985 | @see Pa_GetStreamInfo 986 | */ 987 | 988 | typedef struct PaStreamInfo 989 | { 990 | /** this is struct version 1 */ 991 | int structVersion; 992 | 993 | /** The input latency of the stream in seconds. This value provides the most 994 | accurate estimate of input latency available to the implementation. It may 995 | differ significantly from the suggestedLatency value passed to Pa_OpenStream(). 996 | The value of this field will be zero (0.) for output-only streams. 997 | @see PaTime 998 | */ 999 | PaTime inputLatency; 1000 | 1001 | /** The output latency of the stream in seconds. This value provides the most 1002 | accurate estimate of output latency available to the implementation. It may 1003 | differ significantly from the suggestedLatency value passed to Pa_OpenStream(). 1004 | The value of this field will be zero (0.) for input-only streams. 1005 | @see PaTime 1006 | */ 1007 | PaTime outputLatency; 1008 | 1009 | /** The sample rate of the stream in Hertz (samples per second). In cases 1010 | where the hardware sample rate is inaccurate and PortAudio is aware of it, 1011 | the value of this field may be different from the sampleRate parameter 1012 | passed to Pa_OpenStream(). If information about the actual hardware sample 1013 | rate is not available, this field will have the same value as the sampleRate 1014 | parameter passed to Pa_OpenStream(). 1015 | */ 1016 | double sampleRate; 1017 | 1018 | } PaStreamInfo; 1019 | 1020 | 1021 | /** Retrieve a pointer to a PaStreamInfo structure containing information 1022 | about the specified stream. 1023 | @return A pointer to an immutable PaStreamInfo structure. If the stream 1024 | parameter invalid, or an error is encountered, the function returns NULL. 1025 | 1026 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1027 | 1028 | @note PortAudio manages the memory referenced by the returned pointer, 1029 | the client must not manipulate or free the memory. The pointer is only 1030 | guaranteed to be valid until the specified stream is closed. 1031 | 1032 | @see PaStreamInfo 1033 | */ 1034 | const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); 1035 | 1036 | 1037 | /** Returns the current time in seconds for a stream according to the same clock used 1038 | to generate callback PaStreamCallbackTimeInfo timestamps. The time values are 1039 | monotonically increasing and have unspecified origin. 1040 | 1041 | Pa_GetStreamTime returns valid time values for the entire life of the stream, 1042 | from when the stream is opened until it is closed. Starting and stopping the stream 1043 | does not affect the passage of time returned by Pa_GetStreamTime. 1044 | 1045 | This time may be used for synchronizing other events to the audio stream, for 1046 | example synchronizing audio to MIDI. 1047 | 1048 | @return The stream's current time in seconds, or 0 if an error occurred. 1049 | 1050 | @see PaTime, PaStreamCallback, PaStreamCallbackTimeInfo 1051 | */ 1052 | PaTime Pa_GetStreamTime( PaStream *stream ); 1053 | 1054 | 1055 | /** Retrieve CPU usage information for the specified stream. 1056 | The "CPU Load" is a fraction of total CPU time consumed by a callback stream's 1057 | audio processing routines including, but not limited to the client supplied 1058 | stream callback. This function does not work with blocking read/write streams. 1059 | 1060 | This function may be called from the stream callback function or the 1061 | application. 1062 | 1063 | @return 1064 | A floating point value, typically between 0.0 and 1.0, where 1.0 indicates 1065 | that the stream callback is consuming the maximum number of CPU cycles possible 1066 | to maintain real-time operation. A value of 0.5 would imply that PortAudio and 1067 | the stream callback was consuming roughly 50% of the available CPU time. The 1068 | return value may exceed 1.0. A value of 0.0 will always be returned for a 1069 | blocking read/write stream, or if an error occurs. 1070 | */ 1071 | double Pa_GetStreamCpuLoad( PaStream* stream ); 1072 | 1073 | 1074 | /** Read samples from an input stream. The function doesn't return until 1075 | the entire buffer has been filled - this may involve waiting for the operating 1076 | system to supply the data. 1077 | 1078 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1079 | 1080 | @param buffer A pointer to a buffer of sample frames. The buffer contains 1081 | samples in the format specified by the inputParameters->sampleFormat field 1082 | used to open the stream, and the number of channels specified by 1083 | inputParameters->numChannels. If non-interleaved samples were requested using 1084 | the paNonInterleaved sample format flag, buffer is a pointer to the first element 1085 | of an array of buffer pointers, one non-interleaved buffer for each channel. 1086 | 1087 | @param frames The number of frames to be read into buffer. This parameter 1088 | is not constrained to a specific range, however high performance applications 1089 | will want to match this parameter to the framesPerBuffer parameter used 1090 | when opening the stream. 1091 | 1092 | @return On success PaNoError will be returned, or PaInputOverflowed if input 1093 | data was discarded by PortAudio after the previous call and before this call. 1094 | */ 1095 | PaError Pa_ReadStream( PaStream* stream, 1096 | void *buffer, 1097 | unsigned long frames ); 1098 | 1099 | 1100 | /** Write samples to an output stream. This function doesn't return until the 1101 | entire buffer has been consumed - this may involve waiting for the operating 1102 | system to consume the data. 1103 | 1104 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1105 | 1106 | @param buffer A pointer to a buffer of sample frames. The buffer contains 1107 | samples in the format specified by the outputParameters->sampleFormat field 1108 | used to open the stream, and the number of channels specified by 1109 | outputParameters->numChannels. If non-interleaved samples were requested using 1110 | the paNonInterleaved sample format flag, buffer is a pointer to the first element 1111 | of an array of buffer pointers, one non-interleaved buffer for each channel. 1112 | 1113 | @param frames The number of frames to be written from buffer. This parameter 1114 | is not constrained to a specific range, however high performance applications 1115 | will want to match this parameter to the framesPerBuffer parameter used 1116 | when opening the stream. 1117 | 1118 | @return On success PaNoError will be returned, or paOutputUnderflowed if 1119 | additional output data was inserted after the previous call and before this 1120 | call. 1121 | */ 1122 | PaError Pa_WriteStream( PaStream* stream, 1123 | const void *buffer, 1124 | unsigned long frames ); 1125 | 1126 | 1127 | /** Retrieve the number of frames that can be read from the stream without 1128 | waiting. 1129 | 1130 | @return Returns a non-negative value representing the maximum number of frames 1131 | that can be read from the stream without blocking or busy waiting or, a 1132 | PaErrorCode (which are always negative) if PortAudio is not initialized or an 1133 | error is encountered. 1134 | */ 1135 | signed long Pa_GetStreamReadAvailable( PaStream* stream ); 1136 | 1137 | 1138 | /** Retrieve the number of frames that can be written to the stream without 1139 | waiting. 1140 | 1141 | @return Returns a non-negative value representing the maximum number of frames 1142 | that can be written to the stream without blocking or busy waiting or, a 1143 | PaErrorCode (which are always negative) if PortAudio is not initialized or an 1144 | error is encountered. 1145 | */ 1146 | signed long Pa_GetStreamWriteAvailable( PaStream* stream ); 1147 | 1148 | 1149 | /* Miscellaneous utilities */ 1150 | 1151 | 1152 | /** Retrieve the size of a given sample format in bytes. 1153 | 1154 | @return The size in bytes of a single sample in the specified format, 1155 | or paSampleFormatNotSupported if the format is not supported. 1156 | */ 1157 | PaError Pa_GetSampleSize( PaSampleFormat format ); 1158 | 1159 | 1160 | /** Put the caller to sleep for at least 'msec' milliseconds. This function is 1161 | provided only as a convenience for authors of portable code (such as the tests 1162 | and examples in the PortAudio distribution.) 1163 | 1164 | The function may sleep longer than requested so don't rely on this for accurate 1165 | musical timing. 1166 | */ 1167 | void Pa_Sleep( long msec ); 1168 | 1169 | 1170 | 1171 | #ifdef __cplusplus 1172 | } 1173 | #endif /* __cplusplus */ 1174 | #endif /* PORTAUDIO_H */ 1175 | --------------------------------------------------------------------------------