コード例 #1
0
ファイル: CHAIN.cpp プロジェクト: eriser/RTcmix-1
int CHAIN::configure()
{
	int status = -1;
	Instrument *previous = NULL;
	for (std::vector<Instrument *>::iterator it = mInstVector.begin(); it != mInstVector.end(); ++it) {
		Instrument *inst = *it;
		status = inst->configure(RTBUFSAMPS);
		if (status != 0)
			return status;
		if (previous != NULL) {
			status = inst->setChainedInputBuffer(previous->outbuf, previous->outputChannels());
			if (status != 0)
				return status;
		}
		previous = inst;
	}
	// For CHAIN itself, we override our (what should be zero) input channel count here.  This allows setChainedInputBuffer() to succeed
	// even though the counts don't seem to match.
	_input.inputchans = previous->outputChannels();
	status = setChainedInputBuffer(previous->outbuf, previous->outputChannels());
	return status;
}
コード例 #2
0
ファイル: intraverse.cpp プロジェクト: eriser/RTcmix-1
// This is now the audio play callback
bool RTcmix::inTraverse(AudioDevice *device, void *arg)
{
//	RTcmix *RTCore = (RTcmix *) arg;
	Bool panic = NO;
	short bus = -1, bus_count = 0, busq = 0;
	int i;
	short bus_q_offset = 0;

#ifdef WBUG
	RTPrintf("ENTERING inTraverse()\n");
#endif
#ifdef DBUG	  
	RTPrintf("\nEntering big loop ...........  bufStartSamp = %llu\n", (unsigned long long)bufStartSamp);
#endif

#ifdef EMBEDDED
	// BGG mm -- I need to find a better place to put this...
   bufEndSamp = bufStartSamp + RTBUFSAMPS;
#endif

	// send a buffer of zeros to audio output device.  NOTE:  This used to be
	// in the inTraverse init code.
	
	if (startupBufCount-- > 0) {
		return (rtsendzeros(device, false) == 0) ? true : false;
	}

	if (rtInteractive && run_status == RT_PANIC)
		panic = YES;
#ifdef EMBEDDED
	else if (rtInteractive && run_status == RT_FLUSH) {
		resetHeapAndQueue();
		rtsendzeros(device, false);
		run_status = RT_GOOD;
		return true;
	}
#endif

	// Pop elements off rtHeap and insert into rtQueue +++++++++++++++++++++

	// deleteMin() returns top instrument if inst's start time is < bufEndSamp,
	// else NULL.  heapChunkStart is set in all cases
	
	FRAMETYPE heapChunkStart = 0;
	Instrument *Iptr;
    const BusSlot *iBus;

	while ((Iptr = rtHeap->deleteMin(bufEndSamp, &heapChunkStart)) != NULL) {
#ifdef DBUG
		RTPrintf("Iptr %p pulled from rtHeap\n", Iptr);
		RTPrintf("heapChunkStart = %lld\n", (long long)heapChunkStart);
#endif
		if (panic) {
#ifdef DBUG
			RTPrintf("Panic: Iptr %p unref'd\n", Iptr);
#endif
			Iptr->unref();
			continue;
		}

		// Because we know this instrument will be run during this slot,
		// perform final configuration on it if we are not interactive.
		// (If interactive, this is handled at init() time).

		if (!rtInteractive) {
#ifdef ALLBUG
			RTPrintf("Calling configure()\n");
#endif
			if (Iptr->configure(RTBUFSAMPS) != 0) {
#ifdef DBUG
				rtcmix_warn(NULL, "Inst configure error: Iptr %p unref'd", Iptr);
#endif
				Iptr->unref();
				continue;
			}
		}

        iBus = Iptr->getBusSlot();

		// DJT Now we push things onto different queues
		::pthread_mutex_lock(&bus_slot_lock);
		IBusClass bus_class = iBus->Class();
		switch (bus_class) {
		case TO_AUX:
			bus_count = iBus->auxout_count;
			bus_q_offset = 0;
			for(i=0;i<bus_count;i++) {
				bus = iBus->auxout[i];
				busq = bus+bus_q_offset;
#ifdef ALLBUG
				RTPrintf("Pushing on TO_AUX[%d] rtQueue\n", busq);
#endif
				rtQueue[busq].push(Iptr,heapChunkStart);
			}
			break;
		case AUX_TO_AUX:
			bus_count = iBus->auxout_count;
			bus_q_offset = busCount;
			for(i=0;i<bus_count;i++) {
				bus = iBus->auxout[i];
				busq = bus+bus_q_offset;
#ifdef ALLBUG
				RTPrintf("Pushing on AUX_TO_AUX[%d] rtQueue\n", busq);
#endif
				rtQueue[busq].push(Iptr,heapChunkStart);
			}
			break;
		case TO_OUT:
			bus_count = iBus->out_count;
			bus_q_offset = busCount*2;
			for(i=0;i<bus_count;i++) {
				bus = iBus->out[i];
				busq = bus+bus_q_offset;
#ifdef ALLBUG
				RTPrintf("Pushing on TO_OUT[%d] rtQueue\n", busq);
#endif
				rtQueue[busq].push(Iptr,heapChunkStart);
			}
			break;
		case TO_AUX_AND_OUT:
			bus_count = iBus->out_count;
			bus_q_offset = busCount;
			for(i=0;i<bus_count;i++) {
				bus = iBus->out[i];
				busq = bus+bus_q_offset;
#ifdef ALLBUG
				RTPrintf("Pushing on TO_OUT2[%d] rtQueue\n", busq);
#endif
				rtQueue[busq].push(Iptr,heapChunkStart);
			}
			bus_count = iBus->auxout_count;
			bus_q_offset = 2*busCount;
			for(i=0;i<bus_count;i++) {
				bus = iBus->auxout[i];
				busq = bus+bus_q_offset;
#ifdef ALLBUG
				RTPrintf("Pushing on TO_AUX2[%d] rtQueue\n", busq);
#endif
				rtQueue[busq].push(Iptr,heapChunkStart);
			}
			break;
		default:
			rterror("intraverse", "unknown bus_class");
			break;
		}
		::pthread_mutex_unlock(&bus_slot_lock);
	}
	// End rtHeap popping and rtQueue insertion ----------------------------

	BusType bus_type = BUS_OUT; // Default when none is set
	IBusClass qStatus = TO_AUX;
	short play_bus = 0;
	Bool aux_pb_done = NO;
	int rtQSize = 0, allQSize = 0;
    FRAMETYPE rtQchunkStart = 0;
#ifdef MULTI_THREAD
	vector<Instrument *>instruments;
	instruments.reserve(busCount);
#endif
	// rtQueue[] playback shuffling ++++++++++++++++++++++++++++++++++++++++
	while (!aux_pb_done) {
		switch (qStatus) {
		case TO_AUX:
			bus_q_offset = 0;
			bus_type = BUS_AUX_OUT;
			::pthread_mutex_lock(&to_aux_lock);
			bus = ToAuxPlayList[play_bus++];
			::pthread_mutex_unlock(&to_aux_lock);
			break;
		case AUX_TO_AUX:
			bus_q_offset = busCount;
			::pthread_mutex_lock(&aux_to_aux_lock);
			bus = AuxToAuxPlayList[play_bus++];
			::pthread_mutex_unlock(&aux_to_aux_lock);
			bus_type = BUS_AUX_OUT;
			break;
		case TO_OUT:
			bus_q_offset = busCount*2;
			::pthread_mutex_lock(&to_out_lock);
			bus = ToOutPlayList[play_bus++];
			::pthread_mutex_unlock(&to_out_lock);
			bus_type = BUS_OUT;
			break;
		default:
			rterror("intraverse", "unknown bus_class");
			break;
		}

		if (bus != -1) {
			busq = bus+bus_q_offset;
			rtQSize = rtQueue[busq].getSize();
			if (rtQSize > 0) {
				rtQueue[busq].sort();
				rtQchunkStart = rtQueue[busq].nextChunk();
				// DS ADDED
				assert(rtQchunkStart > 0 || bufStartSamp == 0);
			}
		}
		else {
			switch (qStatus) {
			case TO_AUX:
				qStatus = AUX_TO_AUX;
				play_bus = 0;
				break;
			case AUX_TO_AUX:
				qStatus = TO_OUT;
				play_bus = 0;
				break;
			case TO_OUT:
#ifdef ALLBUG
				printf("aux_pb_done\n");
#endif
				aux_pb_done = YES;
				break;
			default:
				rterror("intraverse", "unknown bus_class");
				break;
			}
		}
#ifdef ALLBUG
		printf("bus: %d  busq: %d\n", bus, busq);
#endif
        
#ifdef MULTI_THREAD
		if (bus != -1) {
#if defined(IBUG)
			printf("\nAdding instruments for current slice [end = %.3f ms] and bus [%d]\n",
				   1000 * bufEndSamp/SR, busq);
#endif
		}
		else {
#if defined(IBUG) || defined(DEBUG)
			printf("\nDone with bus type %d -- continuing\n", bus_type);
#endif
			continue;
		}
		// Play elements on queue (insert back in if needed) ++++++++++++++++++
		while (rtQSize > 0 && rtQchunkStart < bufEndSamp) {
			int chunksamps = 0;
			            
			Iptr = rtQueue[busq].pop(&rtQchunkStart);  // get next instrument off queue
#ifdef DBUG
			cout << "Iptr " << (void *) Iptr << " popped from rtQueue " << busq << " at rtQchunkStart " << rtQchunkStart << endl;
#endif			
			Iptr->set_ichunkstart(rtQchunkStart);

			FRAMETYPE endsamp = Iptr->getendsamp();

			// difference in sample start (countdown)
			int offset = int(rtQchunkStart - bufStartSamp);

			// DJT:  may have to expand here.  IE., conditional above
			// (rtQchunkStart >= bufStartSamp)
			// unlcear what that will do just now
			if (offset < 0) { // BGG: added this trap for robustness
#ifndef EMBEDDED
				cout << "WARNING: the scheduler is behind the queue!" << endl;
				cout << "bufStartSamp:  " << bufStartSamp << endl;
				cout << "endsamp:  " << endsamp << endl;
#endif
				endsamp += offset;  // DJT:  added this (with hope)
				offset = 0;
			}

			Iptr->set_output_offset(offset);

			if (endsamp < bufEndSamp) {  // compute # of samples to write
				chunksamps = int(endsamp-rtQchunkStart);
			}
			else {
				chunksamps = int(bufEndSamp-rtQchunkStart);
			}
			if (chunksamps > RTBUFSAMPS) {
#ifndef EMBEDDED
				cout << "ERROR: chunksamps: " << chunksamps << " limiting to " << RTBUFSAMPS << endl;
#endif
				chunksamps = RTBUFSAMPS;
			}
#ifdef DBUG
			cout << "Begin playback iteration==========\n";
			cout << "bufEndSamp:  " << bufEndSamp << endl;
			cout << "RTBUFSAMPS:  " << RTBUFSAMPS << endl;
			cout << "endsamp:  " << endsamp << endl;
			cout << "offset:  " << offset << endl;
			cout << "chunksamps:  " << chunksamps << endl;
#endif      
			Iptr->setchunk(chunksamps);  // set "chunksamps"		 
						
			// DT_PANIC_MOD
			if (!panic) {
#ifdef IBUG
				cout << "putting inst " << (void *) Iptr << " into taskmgr (bustype " << bus_type << ") [" << Iptr->name() << "]\n";
#endif
				instruments.push_back(Iptr);
				taskManager->addTask<Instrument, int, BusType, int, &Instrument::exec>(Iptr, bus_type, bus);
			}
			else // DT_PANIC_MOD ... just keep on incrementing endsamp
				endsamp += chunksamps;
			rtQSize = rtQueue[busq].getSize();
		}	// while (rtQSize > 0 && rtQchunkStart < bufEndSamp)

		if (!instruments.empty()) {
#if defined(DBUG) || defined(IBUG)
			cout << "Done adding instruments for current slice\n";
			cout << "waiting for " << instruments.size() << " instrument tasks..." << endl;
#endif
			taskManager->waitForTasks(instruments);
        	RTcmix::mixToBus();
#if defined(DBUG) || defined(IBUG)
			cout << "done waiting" << endl;
#endif
#if defined(IBUG)
			cout << "Re-queuing instruments\n";
#endif
		}
		for (vector<Instrument *>::iterator it = instruments.begin(); it != instruments.end(); ++it) {
			Iptr = *it;
			int chunksamps = Iptr->framesToRun();
			FRAMETYPE endsamp = Iptr->getendsamp();
			int inst_chunk_finished = Iptr->needsToRun();

			rtQchunkStart = Iptr->get_ichunkstart();    // We stored this value before placing into the vector
            
			// ReQueue or unref ++++++++++++++++++++++++++++++++++++++++++++++
			if (endsamp > bufEndSamp && !panic) {
#ifdef DBUG
				cout << "re queueing inst " << (void *) Iptr << " on rtQueue " << busq << endl;
#endif
				rtQueue[busq].push(Iptr,rtQchunkStart+chunksamps);   // put back onto queue
			}
			else {
				iBus = Iptr->getBusSlot();
				// unref only after all buses have played -- i.e., if inst_chunk_finished.
				// if not unref'd here, it means the inst still needs to run on another bus.
				if (qStatus == iBus->Class() && inst_chunk_finished) {
#ifdef DBUG
					cout << "unref'ing inst " << (void *) Iptr << endl;
#endif
					Iptr->unref();
				}
			}  // end rtQueue or unref ----------------------------------------
			
			rtQSize = rtQueue[busq].getSize();
			if (rtQSize) {
				allQSize += rtQSize;
			}
#ifdef DBUG
			cout << "rtQSize: " << rtQSize << endl;
			cout << "rtQchunkStart:  " << rtQchunkStart << endl;
			cout << "chunksamps:  " << chunksamps << endl;
			cout << "Iteration done==========\n";
#endif
		} // end while() [Play elements on queue (insert back in if needed)] -----------
		instruments.clear();
	}  // end while (!aux_pb_done) --------------------------------------------------

#else   // MULTI_THREAD
    
    // Play elements on queue (insert back in if needed) ++++++++++++++++++
    while (rtQSize > 0 && rtQchunkStart < bufEndSamp && bus != -1) {
        int chunksamps = 0;
                
        Iptr = rtQueue[busq].pop(&rtQchunkStart);  // get next instrument off queue
#ifdef DBUG
		cout << "Iptr " << (void *) Iptr << " popped from rtQueue " << busq << " at rtQchunkStart " << rtQchunkStart << endl;
#endif
        Iptr->set_ichunkstart(rtQchunkStart);
                
        FRAMETYPE endsamp = Iptr->getendsamp();
        
        // difference in sample start (countdown)
        int offset = int(rtQchunkStart - bufStartSamp);
        
        // DJT:  may have to expand here.  IE., conditional above
        // (rtQchunkStart >= bufStartSamp)
        // unlcear what that will do just now
        if (offset < 0) { // BGG: added this trap for robustness
#ifndef EMBEDDED
            cout << "WARNING: the scheduler is behind the queue!" << endl;
            cout << "bufStartSamp:  " << bufStartSamp << endl;
            cout << "endsamp:  " << endsamp << endl;
#endif
            endsamp += offset;  // DJT:  added this (with hope)
            offset = 0;
        }
        
        Iptr->set_output_offset(offset);
        
        if (endsamp < bufEndSamp) {  // compute # of samples to write
            chunksamps = int(endsamp-rtQchunkStart);
        }
        else {
            chunksamps = int(bufEndSamp-rtQchunkStart);
        }
        if (chunksamps > RTBUFSAMPS) {
#ifndef EMBEDDED
            cout << "ERROR: chunksamps: " << chunksamps << " limiting to " << RTBUFSAMPS << endl;
#endif
            chunksamps = RTBUFSAMPS;
        }
#ifdef DBUG
        cout << "Begin playback iteration==========\n";
        cout << "bufEndSamp:  " << bufEndSamp << endl;
        cout << "RTBUFSAMPS:  " << RTBUFSAMPS << endl;
        cout << "endsamp:  " << endsamp << endl;
        cout << "offset:  " << offset << endl;
        cout << "chunksamps:  " << chunksamps << endl;
#endif      
        Iptr->setchunk(chunksamps);  // set "chunksamps"		 
        
        int inst_chunk_finished = 0;
        
        // DT_PANIC_MOD
        if (!panic) {
#ifdef TBUG
            cout << "Iptr->exec(" << bus_type << "," << bus << ") [" << Iptr->name() << "]\n";
#endif
            inst_chunk_finished = Iptr->exec(bus_type, bus);    // write the samples * * * * * * * * * 
            endsamp = Iptr->getendsamp();
        }
        else // DT_PANIC_MOD ... just keep on incrementing endsamp
            endsamp += chunksamps;
        
        // ReQueue or unref ++++++++++++++++++++++++++++++++++++++++++++++
        if (endsamp > bufEndSamp && !panic) {
#ifdef DBUG
            cout << "re queueing inst " << (void *) Iptr << " on rtQueue " << busq << endl;
#endif
            rtQueue[busq].push(Iptr,rtQchunkStart+chunksamps);   // put back onto queue
        }
        else {
            iBus = Iptr->getBusSlot();
            // unref only after all buses have played -- i.e., if inst_chunk_finished.
            // if not unref'd here, it means the inst still needs to run on another bus.

            if (qStatus == iBus->Class() && inst_chunk_finished) {
#ifdef DBUG
                cout << "unref'ing inst " << (void *) Iptr << endl;
#endif
                Iptr->unref();
            }
        }  // end rtQueue or unref ----------------------------------------
        
        // DJT:  not sure this check before new rtQchunkStart is necessary
        rtQSize = rtQueue[busq].getSize();
        if (rtQSize) {
            rtQueue[busq].sort();
            rtQchunkStart = rtQueue[busq].nextChunk(); /* FIXME:  crapping out */
            allQSize += rtQSize;                /* in RT situation sometimes */
        }
#ifdef DBUG
        cout << "rtQSize: " << rtQSize << endl;
        cout << "rtQchunkStart:  " << rtQchunkStart << endl;
        cout << "chunksamps:  " << chunksamps << endl;
        cout << "Iteration done==========\n";
#endif
    } // end while() [Play elements on queue (insert back in if needed)] -----------
}  // end while (!aux_pb_done) --------------------------------------------------