void Core::PlayMathBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format) { //size_t limit = (kLimit/gCronoSettings.Speed); size_t limit = (gCronoSettings.Speed / 60)*(kFileFormat.u.raw_audio.frame_rate *(kFileFormat.u.raw_audio.channel_count+1)); bool stereo = format.channel_count == 2; kTicLen = (gCronoSettings.Speed/60*60)/ 5; limit = limit*10; if (kSize >= limit) { /* timeval start; prev = start; gettimeofday(&start, NULL); printf("took %lu\n", start.tv_usec - prev.tv_usec);*/ kSize -= limit; kSem = 0; } size_t fillSize = size; if (kSize + size > limit) { fillSize = size + kSize - limit; } if (kSem == 1) { memset(buffer, 0, fillSize); kSize += fillSize; /*if (fillSize < kSize) { fillSize = kSize - fillSize; kSem = 0; }*/ } if (kSem == 0) { switch(gCronoSettings.Engine) { case CRONO_SINE_ENGINE: FillSineBuffer((float*)buffer, fillSize, stereo); break; case CRONO_TRIANGLE_ENGINE: FillTriangleBuffer((float*)buffer, fillSize, stereo); break; case CRONO_SAWTOOTH_ENGINE: FillSawtoothBuffer((float*)buffer, fillSize, stereo); break; } kSize += fillSize; if (kSize >= kTicLen) { kSem = 1; } } }
BBuffer* ToneProducer::FillNextBuffer(bigtime_t event_time) { // get a buffer from our buffer group BBuffer* buf = mBufferGroup->RequestBuffer(mOutput.format.u.raw_audio.buffer_size, BufferDuration()); // if we fail to get a buffer (for example, if the request times out), we skip this // buffer and go on to the next, to avoid locking up the control thread if (!buf) { return NULL; } // now fill it with data, continuing where the last buffer left off // 20sep99: multichannel support size_t numFrames = mOutput.format.u.raw_audio.buffer_size / (sizeof(float)*mOutput.format.u.raw_audio.channel_count); bool stereo = (mOutput.format.u.raw_audio.channel_count == 2); if(!stereo) { ASSERT(mOutput.format.u.raw_audio.channel_count == 1); } // PRINT(("buffer: %ld, %ld frames, %s\n", mOutput.format.u.raw_audio.buffer_size, numFrames, stereo ? "stereo" : "mono")); float* data = (float*) buf->Data(); switch (mWaveform) { case SINE_WAVE: FillSineBuffer(data, numFrames, stereo); break; case TRIANGLE_WAVE: FillTriangleBuffer(data, numFrames, stereo); break; case SAWTOOTH_WAVE: FillSawtoothBuffer(data, numFrames, stereo); break; } // fill in the buffer header media_header* hdr = buf->Header(); hdr->type = B_MEDIA_RAW_AUDIO; hdr->size_used = mOutput.format.u.raw_audio.buffer_size; hdr->time_source = TimeSource()->ID(); bigtime_t stamp; if (RunMode() == B_RECORDING) { // In B_RECORDING mode, we stamp with the capture time. We're not // really a hardware capture node, but we simulate it by using the (precalculated) // time at which this buffer "should" have been created. stamp = event_time; } else { // okay, we're in one of the "live" performance run modes. in these modes, we // stamp the buffer with the time at which the buffer should be rendered to the // output, not with the capture time. mStartTime is the cached value of the // first buffer's performance time; we calculate this buffer's performance time as // an offset from that time, based on the amount of media we've created so far. // Recalculating every buffer like this avoids accumulation of error. stamp = mStartTime + bigtime_t(double(mFramesSent) / double(mOutput.format.u.raw_audio.frame_rate) * 1000000.0); } hdr->start_time = stamp; return buf; }
void ToneProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) { FPRINTF(stderr, "ToneProducer::Connect\n"); // If something earlier failed, Connect() might still be called, but with a non-zero // error code. When that happens we simply unreserve the connection and do // nothing else. if (error) { mOutput.destination = media_destination::null; mOutput.format = mPreferredFormat; return; } // old workaround for format bug: Connect() receives the format data from the // input returned from BBufferConsumer::Connected(). // // char formatStr[256]; // string_for_format(format, formatStr, 255); // FPRINTF(stderr, "\trequested format: %s\n", formatStr); // if(format.type != B_MEDIA_RAW_AUDIO) { // // +++++ this is NOT proper behavior // // but it works // FPRINTF(stderr, "\tcorrupted format; falling back to last suggested format\n"); // format = mOutput.format; // } // // Okay, the connection has been confirmed. Record the destination and format // that we agreed on, and report our connection name again. mOutput.destination = destination; mOutput.format = format; strncpy(io_name, mOutput.name, B_MEDIA_NAME_LENGTH); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(mOutput.destination, &mLatency, &id); FPRINTF(stderr, "\tdownstream latency = %" B_PRIdBIGTIME "\n", mLatency); // Use a dry run to see how long it takes me to fill a buffer of data bigtime_t start, produceLatency; size_t samplesPerBuffer = mOutput.format.u.raw_audio.buffer_size / sizeof(float); size_t framesPerBuffer = samplesPerBuffer / mOutput.format.u.raw_audio.channel_count; float* data = new float[samplesPerBuffer]; mTheta = 0; start = ::system_time(); FillSineBuffer(data, framesPerBuffer, mOutput.format.u.raw_audio.channel_count==2); produceLatency = ::system_time(); mInternalLatency = produceLatency - start; // +++++ e.moon [13jun99]: fiddling with latency, ick mInternalLatency += 20000LL; delete [] data; FPRINTF(stderr, "\tbuffer-filling took %" B_PRIdBIGTIME " usec on this machine\n", mInternalLatency); SetEventLatency(mLatency + mInternalLatency); // reset our buffer duration, etc. to avoid later calculations // +++++ e.moon 11jun99: crashes w/ divide-by-zero when connecting to LoggingConsumer ASSERT(mOutput.format.u.raw_audio.frame_rate); bigtime_t duration = bigtime_t(1000000) * samplesPerBuffer / bigtime_t(mOutput.format.u.raw_audio.frame_rate); SetBufferDuration(duration); // Set up the buffer group for our connection, as long as nobody handed us a // buffer group (via SetBufferGroup()) prior to this. That can happen, for example, // if the consumer calls SetOutputBuffersFor() on us from within its Connected() // method. if (!mBufferGroup) AllocateBuffers(); }
void Core::PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format) { size_t limit = (kLimit/gCronoSettings.Speed); bool stereo = format.channel_count == 2; printf("%f\n", limit / kFileFormat.u.raw_audio.frame_rate*2); kTicLen = kFileFormat.u.raw_audio.frame_rate/7; limit = limit*10; if (kSize >= limit) { //timeval start; //prev = start; //gettimeofday(&start, NULL); //printf("took %lu\n", start.tv_usec - prev.tv_usec); kSize -= limit; kSem = 0; } size_t remaining = 0; if (kSize+size > limit) { remaining = kSize+size - limit; size -= remaining; } if (kSem == 1) { memset(buffer, 0, size); kSize += size; //if (fillSize < kSize) { // fillSize = kSize - fillSize; // kSem = 0; //} if (remaining >= 0) { kSem = 0; size = remaining; } } if (kSem == 0) { switch(gCronoSettings.Engine) { case CRONO_SINE_ENGINE: FillSineBuffer((float*)buffer, size, stereo); break; case CRONO_TRIANGLE_ENGINE: FillTriangleBuffer((float*)buffer, size, true); break; case CRONO_SAWTOOTH_ENGINE: FillSawtoothBuffer((float*)buffer, size, stereo); break; } kSize += size; if (remaining > 0) { printf("defect\n"); memset(buffer, size-remaining, remaining); remaining = 0; } if (kSize >= kTicLen) { kSem = 1; } } }