// Data transmission methods.
bool qmidinetJackMidiDevice::sendData (
	unsigned char *data, unsigned short len, int port ) const
{
	if (port < 0 || port >= m_nports)
		return false;

	if (m_pJackBufferOut == NULL)
		return false;

	const unsigned int nlimit
		= jack_ringbuffer_write_space(m_pJackBufferOut);
	if (sizeof(qmidinetJackMidiEvent) + len < nlimit) {
		unsigned char  achBuffer[nlimit];
		unsigned char *pchBuffer = &achBuffer[0];
		qmidinetJackMidiEvent *pJackEventOut
			= (struct qmidinetJackMidiEvent *) pchBuffer;
		pchBuffer += sizeof(qmidinetJackMidiEvent);
		memcpy(pchBuffer, data, len);
		pJackEventOut->event.time = jack_frame_time(m_pJackClient);
		pJackEventOut->event.buffer = (jack_midi_data_t *) pchBuffer;
		pJackEventOut->event.size = len;
		pJackEventOut->port = port;
	#ifdef CONFIG_DEBUG
		// - show (output) event for debug purposes...
		fprintf(stderr, "JACK MIDI Out Port %d:", port);
		for (unsigned int i = 0; i < len; ++i)
			fprintf(stderr, " 0x%02x", (unsigned char) pchBuffer[i]);
		fprintf(stderr, "\n");
	#endif
		jack_ringbuffer_write(m_pJackBufferOut,
			(const char *) achBuffer, sizeof(qmidinetJackMidiEvent) + len);
	}

	return true;
}
Beispiel #2
0
static PaTime GetStreamTime( PaStream *s )
{
    PaJackStream *stream = (PaJackStream*)s;

    /* TODO: what if we're recording-only? */
    return jack_frame_time( stream->jack_client ) - stream->t0;
}
Beispiel #3
0
/*
 * =================== Input/output port handling =========================
 */
static
void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, jack_nframes_t nframes)
{
	const snd_seq_real_time_t* alsa_time;
	snd_seq_queue_status_t *status;

	snd_seq_queue_status_alloca(&status);

	info->dir = dir;

	info->period_start = jack_last_frame_time(self->jack);
	info->nframes = nframes;
	info->sample_rate = jack_get_sample_rate(self->jack);

	info->cur_frames = jack_frame_time(self->jack);

	// immediately get alsa'a real time (uhh, why everybody has their own 'real' time)
	snd_seq_get_queue_status(self->seq, self->queue, status);
	alsa_time = snd_seq_queue_status_get_real_time(status);
	info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;

	if (info->period_start + info->nframes < info->cur_frames) {
		int periods_lost = (info->cur_frames - info->period_start) / info->nframes;
		info->period_start += periods_lost * info->nframes;
		debug_log("xrun detected: %d periods lost\n", periods_lost);
	}
}
Beispiel #4
0
static PaTime GetStreamTime( PaStream *s )
{
    PaJackStream *stream = (PaJackStream*)s;

    /* TODO: what if we're recording-only? */
    int delta_t = jack_frame_time( stream->jack_client ) - stream->t0;
    return delta_t / (PaTime)jack_get_sample_rate( stream->jack_client );
}
Beispiel #5
0
static PyObject* get_frame_time(PyObject* self, PyObject* args)
{
    pyjack_client_t * client = self_or_global_client(self);
    if(client->pjc == NULL) {
        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
        return NULL;
    }

    int frt = jack_frame_time(client->pjc);
    return Py_BuildValue("i", frt);
}
Beispiel #6
0
static int _get(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj* const *objv) {
  if (argc != 2)
    return fw_error_obj(interp, Tcl_ObjPrintf("usage: %s get", Tcl_GetString(objv[0])));
  _t *data = (_t *)clientData;
  Tcl_Obj *result[] = {
    Tcl_NewIntObj(jack_frame_time(data->fw.client)),
    Tcl_NewDoubleObj(data->sam.pll.freq.f),
    NULL
  };
  Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
  return TCL_OK;
}
Beispiel #7
0
static
void jack_process(midi_stream_t *str, jack_nframes_t nframes)
{
    int r, w;
    process_jack_t proc;
    jack_nframes_t cur_frames;

    if (!str->owner->keep_walking)
        return;

    proc.midi = str->owner;
    proc.nframes = nframes;
    proc.frame_time = jack_last_frame_time(proc.midi->client);
    cur_frames = jack_frame_time(proc.midi->client);
    int periods_diff = cur_frames - proc.frame_time;
    if (periods_diff < proc.nframes) {
        int periods_lost = periods_diff / proc.nframes;
        proc.frame_time += periods_lost * proc.nframes;
        debug_log("xrun detected: %d periods lost", periods_lost);
    }

    // process existing ports
    for (r=0, w=0; r<str->jack.nports; ++r) {
        midi_port_t *port = str->jack.ports[r];
        proc.port = port;

        assert (port->state > PORT_ADDED_TO_JACK && port->state < PORT_REMOVED_FROM_JACK);

        proc.buffer = jack_port_get_buffer(port->jack, nframes);
        if (str->mode == POLLIN)
            jack_midi_clear_buffer(proc.buffer);

        if (port->state == PORT_REMOVED_FROM_MIDI) {
            port->state = PORT_REMOVED_FROM_JACK; // this signals to scan thread
            continue; // this effectively removes port from the midi->in.jack.ports[]
        }

        (str->process_jack)(&proc);

        if (r != w)
            str->jack.ports[w] = port;
        ++w;
    }
    if (str->jack.nports != w)
        debug_log("jack_%s: nports %d -> %d", str->name, str->jack.nports, w);
    str->jack.nports = w;

    jack_add_ports(str); // it makes no sense to add them earlier since they have no data yet

    // wake midi thread
    write(str->wake_pipe[1], &r, 1);
}
// MIDI events capture method.
void qmidinetJackMidiDevice::capture (void)
{
	if (m_pJackBufferIn == NULL)
		return;

	char *pchBuffer;
	qmidinetJackMidiEvent ev;

	while (jack_ringbuffer_peek(m_pJackBufferIn,
			(char *) &ev, sizeof(ev)) == sizeof(ev)) {
		jack_ringbuffer_read_advance(m_pJackBufferIn, sizeof(ev));
		pchBuffer = m_pQueueIn->push(ev.port, ev.event.time, ev.event.size);
		if (pchBuffer)
			jack_ringbuffer_read(m_pJackBufferIn, pchBuffer, ev.event.size);
		else
			jack_ringbuffer_read_advance(m_pJackBufferIn, ev.event.size);
	}

	float sample_rate = jack_get_sample_rate(m_pJackClient);
	jack_nframes_t frame_time = jack_frame_time(m_pJackClient);

	while ((pchBuffer = m_pQueueIn->pop(
			&ev.port, &ev.event.time, &ev.event.size)) != NULL) {	
		ev.event.time += m_last_frame_time;
		if (ev.event.time > frame_time) {
			unsigned long sleep_time = ev.event.time - frame_time;
			float secs = float(sleep_time) / sample_rate;
			if (secs > 0.0001f) {
			#if 0 // defined(__GNUC__) && defined(Q_OS_LINUX)
				struct timespec ts;
				ts.tv_sec  = time_t(secs);
				ts.tv_nsec = long(1E+9f * (secs - ts.tv_sec));
				::nanosleep(&ts, NULL);
			#else
				m_pRecvThread->usleep(long(1E+6f * secs));
			#endif
			}
			frame_time = ev.event.time;
		}	
	#ifdef CONFIG_DEBUG
		// - show (input) event for debug purposes...
		fprintf(stderr, "JACK MIDI In Port %d: (%d)", ev.port, int(ev.event.size));
		for (unsigned int i = 0; i < ev.event.size; ++i)
			fprintf(stderr, " 0x%02x", (unsigned char) pchBuffer[i]);
		fprintf(stderr, "\n");
	#endif
		recvData((unsigned char *) pchBuffer, ev.event.size, ev.port);
	}
}
static int jack_process(jack_nframes_t nframes, void *arg) {
    struct userdata *u = arg;
    unsigned c;
    jack_nframes_t frame_time;
    pa_assert(u);

    /* We just forward the request to our other RT thread */

    for (c = 0; c < u->channels; c++)
        pa_assert_se(u->buffer[c] = jack_port_get_buffer(u->port[c], nframes));

    frame_time = jack_frame_time(u->client);

    pa_assert_se(pa_asyncmsgq_send(u->jack_msgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_RENDER, &frame_time, nframes, NULL) == 0);
    return 0;
}
static void showtime() {
	jack_position_t current;
	jack_transport_state_t transport_state;
	jack_nframes_t frame_time;

	transport_state = jack_transport_query(client, &current);
	frame_time = jack_frame_time(client);

	float time = (float) current.frame / (float) current.frame_rate;
	char current_time[256];
	snprintf(current_time, sizeof(current_time), "%f", time);
	send_udp(udp_ip, udp_port, current_time);
	if (lastframe != current.frame) {
		printf(
				"\x1b[Aframe= %u  frame_time= %u usecs= %lld fr_in:%i fr_out:%i time: %f\t ",
				current.frame, frame_time, current.usecs, current.frame_rate, framerate_out , time);
		lastframe = current.frame;

		switch (transport_state) {
		case JackTransportStopped:
			printf("state: Stopped");
			break;
		case JackTransportRolling:
			printf("state: Rolling");
			break;
		case JackTransportStarting:
			printf("state: Starting");
			break;
		default:
			printf("state: [unknown]");
			break;
		}

		if (current.valid & JackPositionBBT)
			printf("\tBBT: %3" PRIi32 "|%" PRIi32 "|%04"
			PRIi32, current.bar, current.beat, current.tick);

		if (current.valid & JackPositionTimecode)
			printf("\tTC: (%.6f, %.6f)", current.frame_time, current.next_time);
		printf("  \n");
	}
}
Beispiel #11
0
void SC_JackDriver::Run()
{
	jack_client_t* client = mClient;
	World* world = mWorld;

#ifdef SC_JACK_USE_DLL
	mDLL.Update(secondsSinceEpoch(getTime()));
#if SC_JACK_DEBUG_DLL
	static int tick = 0;
	if (++tick >= 10) {
		tick = 0;
		scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n",
				 mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(),
				 mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs);
	}
#endif
#else
	HostTime hostTime = getTime();

	double hostSecs = secondsSinceEpoch(hostTime);
	double sampleTime = (double)(jack_frame_time(client) + jack_frames_since_cycle_start(client));

	if (mStartHostSecs == 0) {
		mStartHostSecs = hostSecs;
		mStartSampleTime = sampleTime;
	} else {
		double instSampleRate = (sampleTime - mPrevSampleTime) / (hostSecs - mPrevHostSecs);
		double smoothSampleRate = mSmoothSampleRate;
		smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
		if (fabs(smoothSampleRate - mSampleRate) > 10.) {
			smoothSampleRate = mSampleRate;
		}
		mOSCincrement = (int64)(mOSCincrementNumerator / smoothSampleRate);
		mSmoothSampleRate = smoothSampleRate;
#if 0
		double avgSampleRate = (sampleTime - mStartSampleTime)/(hostSecs - mStartHostSecs);
		double jitter = (smoothSampleRate * (hostSecs - mPrevHostSecs)) - (sampleTime - mPrevSampleTime);
		double drift = (smoothSampleRate - mSampleRate) * (hostSecs - mStartHostSecs);
#endif
	}

	mPrevHostSecs = hostSecs;
	mPrevSampleTime = sampleTime;
#endif

	try {
		mFromEngine.Free();
		mToEngine.Perform();
		mOscPacketsToEngine.Perform();

		int numInputs = mInputList->mSize;
		int numOutputs = mOutputList->mSize;
		jack_port_t **inPorts = mInputList->mPorts;
		jack_port_t **outPorts = mOutputList->mPorts;
		sc_jack_sample_t **inBuffers = mInputList->mBuffers;
		sc_jack_sample_t **outBuffers = mOutputList->mBuffers;

		int numSamples = NumSamplesPerCallback();
		int bufFrames = mWorld->mBufLength;
		int numBufs = numSamples / bufFrames;

		float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
		float *outBuses = mWorld->mAudioBus;
		int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
		int32 *outTouched = mWorld->mAudioBusTouched;

		int minInputs = sc_min(numInputs, (int)mWorld->mNumInputs);
		int minOutputs = sc_min(numOutputs, (int)mWorld->mNumOutputs);

		int bufFramePos = 0;

		// cache I/O buffers
		for (int i = 0; i < minInputs; ++i) {
			inBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(inPorts[i], numSamples);
		}

		for (int i = 0; i < minOutputs; ++i) {
			outBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(outPorts[i], numSamples);
		}

		// main loop
#ifdef SC_JACK_USE_DLL
		int64 oscTime = mOSCbuftime = (int64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5);
// 		int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate());
		int64 oscInc = mOSCincrement = (int64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5);
		mSmoothSampleRate = mDLL.SampleRate();
		double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */;
#else
		int64 oscTime = mOSCbuftime = OSCTime(hostTime) - (int64)(mMaxOutputLatency * kSecondsToOSCunits + .5);
		int64 oscInc = mOSCincrement;
		double oscToSamples = mOSCtoSamples;
#endif

		for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) {
			int32 bufCounter = mWorld->mBufCounter;
			int32 *tch;

			// copy+touch inputs
			tch = inTouched;
			for (int k = 0; k < minInputs; ++k) {
				sc_jack_sample_t *src = inBuffers[k] + bufFramePos;
				float *dst = inBuses + k * bufFrames;
				for (int n = 0; n < bufFrames; ++n) {
					*dst++ = *src++;
				}
				*tch++ = bufCounter;
			}

			// run engine
			int64 schedTime;
			int64 nextTime = oscTime + oscInc;

			while ((schedTime = mScheduler.NextTime()) <= nextTime) {
				float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
				float diffTimeFloor = floor(diffTime);
				world->mSampleOffset = (int)diffTimeFloor;
				world->mSubsampleOffset = diffTime - diffTimeFloor;

				if (world->mSampleOffset < 0) world->mSampleOffset = 0;
				else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;

				SC_ScheduledEvent event = mScheduler.Remove();
				event.Perform();
			}

			world->mSampleOffset = 0;
			world->mSubsampleOffset = 0.f;
			World_Run(world);

			// copy touched outputs
			tch = outTouched;
			for (int k = 0; k < minOutputs; ++k) {
				sc_jack_sample_t *dst = outBuffers[k] + bufFramePos;
				if (*tch++ == bufCounter) {
					float *src = outBuses + k * bufFrames;
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = *src++;
					}
				} else {
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = 0.0f;
					}
				}
			}

			// advance OSC time
			mOSCbuftime = oscTime = nextTime;
		}
	} catch (std::exception& exc) {
		scprintf("%s: exception in real time: %s\n", kJackDriverIdent, exc.what());
	} catch (...) {
		scprintf("%s: unknown exception in real time\n", kJackDriverIdent);
	}

	double cpuUsage = (double)jack_cpu_load(mClient);
	mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
	if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) {
		mPeakCPU = cpuUsage;
		mPeakCounter = mMaxPeakCounter;
	}

	mAudioSync.Signal();
}
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *memchunk) {
    struct userdata *u = PA_SINK(o)->userdata;

    switch (code) {

        case SINK_MESSAGE_RENDER:

            /* Handle the request from the JACK thread */

            if (u->sink->thread_info.state == PA_SINK_RUNNING) {
                pa_memchunk chunk;
                size_t nbytes;
                void *p;

                pa_assert(offset > 0);
                nbytes = (size_t) offset * pa_frame_size(&u->sink->sample_spec);

                pa_sink_render_full(u->sink, nbytes, &chunk);

                p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index;
                pa_deinterleave(p, u->buffer, u->channels, sizeof(float), (unsigned) offset);
                pa_memblock_release(chunk.memblock);

                pa_memblock_unref(chunk.memblock);
            } else {
                unsigned c;
                pa_sample_spec ss;

                /* Humm, we're not RUNNING, hence let's write some silence */

                ss = u->sink->sample_spec;
                ss.channels = 1;

                for (c = 0; c < u->channels; c++)
                    pa_silence_memory(u->buffer[c], (size_t) offset * pa_sample_size(&ss), &ss);
            }

            u->frames_in_buffer = (jack_nframes_t) offset;
            u->saved_frame_time = * (jack_nframes_t*) data;
            u->saved_frame_time_valid = TRUE;

            return 0;

        case SINK_MESSAGE_BUFFER_SIZE:
            pa_sink_set_max_request_within_thread(u->sink, (size_t) offset * pa_frame_size(&u->sink->sample_spec));
            return 0;

        case SINK_MESSAGE_ON_SHUTDOWN:
            pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
            return 0;

        case PA_SINK_MESSAGE_GET_LATENCY: {
            jack_nframes_t l, ft, d;
            size_t n;

            /* This is the "worst-case" latency */
            l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer;

            if (u->saved_frame_time_valid) {
                /* Adjust the worst case latency by the time that
                 * passed since we last handed data to JACK */

                ft = jack_frame_time(u->client);
                d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0;
                l = l > d ? l - d : 0;
            }

            /* Convert it to usec */
            n = l * pa_frame_size(&u->sink->sample_spec);
            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);

            return 0;
        }

    }

    return pa_sink_process_msg(o, code, data, offset, memchunk);
}
Beispiel #13
0
int 
main(int argc, char *argv[])
{
	int		ch;
	char		*file_name, *autoconnect_port_name = NULL;


#ifdef WITH_LASH
	lash_args_t *lash_args;
#endif

	g_thread_init(NULL);

#ifdef WITH_LASH
	lash_args = lash_extract_args(&argc, &argv);
#endif

	g_log_set_default_handler(log_handler, NULL);

	while ((ch = getopt(argc, argv, "a:dnqr:stVx")) != -1) {
		switch (ch) {
			case 'a':
				autoconnect_port_name = strdup(optarg);
				break;

			case 'd':
				debug = 1;
				break;

			case 'n':
				start_stopped = 1;
				break;

			case 'q':
				be_quiet = 1;
				break;

			case 'r':
				rate_limit = strtod(optarg, NULL);
				if (rate_limit <= 0.0) {
					g_critical("Invalid rate limit specified.\n");

					exit(EX_USAGE);
				}

				break;

			case 's':
				just_one_output = 1;
				break;

			case 't':
				use_transport = 0;
				break;

            case 'x':
                    remote_control = 1;
                    break;

			case 'V':
				show_version();
				break;

			case '?':
			default:
				usage();
				break;
		}
	}

	argc -= optind;
	argv += optind;

	if (argv[0] == NULL) {
		g_critical("No file name given.");
		usage();
	}

	file_name = argv[0];

	if (!remote_control) {
	smf_vol = smf = smf_load(file_name);

	if (smf == NULL) {
		g_critical("Loading SMF file failed.");

		exit(-1);
	}

	if (!be_quiet)
		g_message("%s.", smf_decode(smf));

	if (smf->number_of_tracks > MAX_NUMBER_OF_TRACKS) {
		g_warning("Number of tracks (%d) exceeds maximum for per-track output; implying '-s' option.", smf->number_of_tracks);
		just_one_output = 1;
	}
	}

#ifdef WITH_LASH
	init_lash(lash_args);
#endif

	g_timeout_add(1000, emergency_exit_timeout, (gpointer)0);
	signal(SIGINT, ctrl_c_handler);

	init_jack();

	if (autoconnect_port_name) {
		if (connect_to_input_port(autoconnect_port_name)) {
			g_critical("Couldn't connect to '%s', exiting.", autoconnect_port_name);
			exit(EX_UNAVAILABLE);
		}
	}

	if (use_transport && !start_stopped) {
		jack_transport_locate(jack_client, 0);
		jack_transport_start(jack_client);
	}

	if (!use_transport)
		playback_started = jack_frame_time(jack_client);

	if (remote_control)
		remote_control_start(argv[0]);

	g_main_loop_run(g_main_loop_new(NULL, TRUE));

	/* Not reached. */

	return 0;
}
Beispiel #14
0
static int JackCallback( jack_nframes_t frames, void *userData )
{
    PaJackStream *stream = (PaJackStream*)userData;
    PaStreamCallbackTimeInfo timeInfo;
    int callbackResult;
    int chn;
    int framesProcessed;

    /* TODO: make this a lot more accurate */
    PaTime now = GetStreamTime(stream);
    timeInfo.currentTime = now;
    timeInfo.outputBufferDacTime = now;
    timeInfo.inputBufferAdcTime = now;

    if( stream->t0 == -1 )
    {
        if( stream->num_outgoing_connections == 0 )
        {
            /* TODO: how to handle stream time for capture-only operation? */
        }
        else
        {
            /* the beginning time needs to be initialized */
            stream->t0 = jack_frame_time( stream->jack_client ) -
                         jack_frames_since_cycle_start( stream->jack_client) +
                         jack_port_get_total_latency( stream->jack_client,
                                                      stream->local_output_ports[0] );
        }
    }

    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
            0 /* @todo pass underflow/overflow flags when necessary */ );

    for( chn = 0; chn < stream->num_incoming_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_input_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
                                              chn,
                                              channel_buf );
    }

    for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_output_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
                                               chn,
                                               channel_buf );
    }

    if( stream->num_incoming_connections > 0 )
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );

    if( stream->num_outgoing_connections > 0 )
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );

    callbackResult = paContinue;
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
                                                  &callbackResult );

    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
    stream->total_frames_sent += frames;


    if( callbackResult == paContinue )
    {
        /* nothing special */
    }
    else if( callbackResult == paAbort )
    {
        /* finish playback immediately  */

        /* TODO: memset 0 the outgoing samples to "cancel" them */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    else
    {
        /* User callback has asked us to stop with paComplete or other non-zero value. */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    return 0;
}
Beispiel #15
0
static
void *midi_thread(void *arg)
{
    midi_stream_t *str = arg;
    alsa_rawmidi_t *midi = str->owner;
    struct pollfd pfds[MAX_PFDS];
    int npfds;
    jack_time_t wait_nsec = 1000*1000*1000; // 1 sec
    process_midi_t proc;

    proc.midi = midi;
    proc.mode = str->mode;

    pfds[0].fd = str->wake_pipe[0];
    pfds[0].events = POLLIN|POLLERR|POLLNVAL;
    npfds = 1;

    if (jack_is_realtime(midi->client))
        set_threaded_log_function();

    //debug_log("midi_thread(%s): enter", str->name);

    while (midi->keep_walking) {
        int poll_timeout;
        int wait_nanosleep;
        int r=1, w=1; // read,write pos in pfds
        int rp=0, wp=0; // read, write pos in ports

        // sleep
        //if (wait_nsec != 1000*1000*1000) {
        //	debug_log("midi_thread(%s): ", str->name);
        //	assert (wait_nsec == 1000*1000*1000);
        //}
        poll_timeout = wait_nsec / (1000*1000);
        wait_nanosleep = wait_nsec % (1000*1000);
        if (wait_nanosleep > NANOSLEEP_RESOLUTION) {
            struct timespec ts;
            ts.tv_sec = 0;
            ts.tv_nsec = wait_nanosleep;
            clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
        }
        int res = poll((struct pollfd*)&pfds, npfds, poll_timeout);
        //debug_log("midi_thread(%s): poll exit: %d", str->name, res);
        if (!midi->keep_walking)
            break;
        if (res < 0) {
            if (errno == EINTR)
                continue;
            error_log("midi_thread(%s) poll failed: %s", str->name, strerror(errno));
            break;
        }

        // check wakeup pipe
        if (pfds[0].revents & ~POLLIN)
            break;
        if (pfds[0].revents & POLLIN) {
            char c;
            read(pfds[0].fd, &c, 1);
        }

        // add new ports
        while (jack_ringbuffer_read_space(str->midi.new_ports) >= sizeof(midi_port_t*) && str->midi.nports < MAX_PORTS) {
            midi_port_t *port;
            jack_ringbuffer_read(str->midi.new_ports, (char*)&port, sizeof(port));
            str->midi.ports[str->midi.nports++] = port;
            debug_log("midi_thread(%s): added port %s", str->name, port->name);
        }

//		if (res == 0)
//			continue;

        // process ports
        proc.cur_time = 0; //jack_frame_time(midi->client);
        proc.next_time = NFRAMES_INF;

        for (rp = 0; rp < str->midi.nports; ++rp) {
            midi_port_t *port = str->midi.ports[rp];
            proc.cur_time = jack_frame_time(midi->client);
            proc.port = port;
            proc.rpfds = &pfds[r];
            proc.wpfds = &pfds[w];
            proc.max_pfds = MAX_PFDS - w;
            r += port->npfds;
            if (!(str->process_midi)(&proc)) {
                port->state = PORT_REMOVED_FROM_MIDI; // this signals to jack thread
                continue; // this effectively removes port from array
            }
            w += port->npfds;
            if (rp != wp)
                str->midi.ports[wp] = port;
            ++wp;
        }
        if (str->midi.nports != wp)
            debug_log("midi_%s: nports %d -> %d", str->name, str->midi.nports, wp);
        str->midi.nports = wp;
        if (npfds != w)
            debug_log("midi_%s: npfds %d -> %d", str->name, npfds, w);
        npfds = w;

        /*
         * Input : ports do not set proc.next_time.
         * Output: port sets proc.next_time ONLY if it does not have queued data.
         * So, zero timeout will not cause busy-looping.
         */
        if (proc.next_time < proc.cur_time) {
            debug_log("%s: late: next_time = %d, cur_time = %d", str->name, (int)proc.next_time, (int)proc.cur_time);
            wait_nsec = 0; // we are late
        } else if (proc.next_time != NFRAMES_INF) {
            jack_time_t wait_frames = proc.next_time - proc.cur_time;
            jack_nframes_t rate = jack_get_sample_rate(midi->client);
            wait_nsec = (wait_frames * (1000*1000*1000)) / rate;
            debug_log("midi_%s: timeout = %d", str->name, (int)wait_frames);
        } else
            wait_nsec = 1000*1000*1000;
        //debug_log("midi_thread(%s): wait_nsec = %lld", str->name, wait_nsec);
    }
    return NULL;
}
Beispiel #16
0
void *
midi_thread_function(void *arg)
{
    int rc;
    struct sched_param rtparam;
    snd_seq_event_t *ev = 0;

    /* try to get low-priority real-time scheduling */
    memset (&rtparam, 0, sizeof (rtparam));
    rtparam.sched_priority = 1; /* just above SCHED_OTHER */
    if ((rc = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
        if (rc == EPERM) {
            ghss_debug_rt(GDB_MIDI, " midi thread: no permission for SCHED_FIFO, continuing...");
        } else {
            ghss_debug_rt(GDB_MIDI, " midi thread: error getting SCHED_FIFO, continuing...");
        }
    }

    midi_thread_running = 1;

    do { /* while(!host_exiting) */

        rc = poll(alsaClient_pfd, alsaClient_npfd, 500);
        if (rc <= 0) {
            if (rc < 0 && rc != EINTR) {
                ghss_debug_rt(GDB_MIDI, " midi thread: poll error: %s", strerror(errno));
                usleep(500);
            }
            continue;
        }

        pthread_mutex_lock(&midiEventBufferMutex);

        do {
        
            if (snd_seq_event_input(alsaClient, &ev) > 0) {

                if (midiEventReadIndex == midiEventWriteIndex + 1) {
                    ghss_debug_rt(GDB_MIDI, " midi thread: MIDI event buffer overflow!");
                    continue;
                }

                midiEventBuffer[midiEventWriteIndex] = *ev;

                ev = &midiEventBuffer[midiEventWriteIndex];

                /* We don't need to handle EVENT_NOTE here, because ALSA
                   won't ever deliver them on the sequencer queue -- it
                   unbundles them into NOTE_ON and NOTE_OFF when they're
                   dispatched.  We would only need worry about them when
                   retrieving MIDI events from some other source. */

                if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) {
                    ev->type =  SND_SEQ_EVENT_NOTEOFF;
                }

                /* fprintf(stderr, "midi: flags %02x, tick %u, sec %u nsec %u\n",
                 *         ev->flags, ev->time.tick, ev->time.time.tv_sec, ev->time.time.tv_nsec);
                 * fflush(stderr); */

                /* -FIX- Ideally, we would use ev->time to figure out how long ago
                 * this event was generated, and adjust accordingly. Instead, we
                 * take the easy-and-fast route of just restamping the event with
                 * the JACK rolling frame time at its arrival, which seems to work
                 * pretty well.... */
                /* -FIX- Rosegarden has example of setting up input queue, see
                 * /t/src/example/rosegarden-CVS-20050109/sound/AlsaDriver.cpp */
                /* -FIX- snd_seq_ioctl_get_queue_status, aka snd_seq_MUMBLE_get_queue_status()
                 * should return current queue time, subtract event time from that to get offset
                 * into past that event arrived? */
                ev->time.tick = jack_frame_time(jackClient);

                /* fprintf(stderr, "midi: %u\n", ev->time.tick); fflush(stderr); */

                ev->dest.client = 0;  /* flag as from MIDI thread */

                midiEventWriteIndex = (midiEventWriteIndex + 1) % EVENT_BUFFER_SIZE;
            }
        
        } while (snd_seq_event_input_pending(alsaClient, 0) > 0);

        pthread_mutex_unlock(&midiEventBufferMutex);

    } while(!host_exiting);

    midi_thread_running = 0;

    return NULL;
}
    uint32_t JackAudioSystem::time_stamp()
    {
	if( !_client ) return 0;
	return jack_frame_time(_client);
    }
Beispiel #18
0
static void
a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event)
{
	jack_midi_data_t data[MAX_EVENT_SIZE];
	struct a2j_stream *str = &self->stream;
	long size;
	struct a2j_port *port;
	jack_nframes_t now;

	now = jack_frame_time (self->jack_client);
  
	if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) {
		return;
	}

	/*
	 * RPNs, NRPNs, Bank Change, etc. need special handling
	 * but seems, ALSA does it for us already.
	 */
	snd_midi_event_reset_decode(str->codec);
	if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) {
		return;
	}

	// fixup NoteOn with vel 0
	if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
		data[0] = 0x80 + (data[0] & 0x0F);
		data[2] = 0x40;
	}

	a2j_debug("input: %d bytes at event_frame=%u", (int)size, now);

	if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) {
		struct a2j_alsa_midi_event ev;
		char *ev_charp = (char*) &ev;
		size_t limit;
		size_t to_write = sizeof(ev);

		jack_ringbuffer_data_t vec[2];
		jack_ringbuffer_get_write_vector( port->inbound_events, vec );
		ev.time = now;
		ev.size = size;

    
		limit = (to_write > vec[0].len ? vec[0].len : to_write);
		if( limit ) {
			memcpy( vec[0].buf, ev_charp, limit );
			to_write -= limit;
			ev_charp += limit;
			vec[0].buf += limit;
			vec[0].len -= limit;
		}
		if( to_write ) {
			memcpy( vec[1].buf, ev_charp, to_write );
			vec[1].buf += to_write;
			vec[1].len -= to_write;
		}

		to_write = size;
		ev_charp = (char *)data;
		limit = (to_write > vec[0].len ? vec[0].len : to_write);
		if( limit )
			memcpy( vec[0].buf, ev_charp, limit );
		to_write -= limit;
		ev_charp += limit;
		if( to_write )
			memcpy( vec[1].buf, ev_charp, to_write );

		jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size );
	} else {
		a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size);
	}

}
Beispiel #19
0
static int
a2j_process (jack_nframes_t nframes, void * arg)
{
	struct a2j* self = (struct a2j *) arg;
	struct a2j_stream * stream_ptr;
	int i;
	struct a2j_port ** port_ptr;
	struct a2j_port * port;

	if (g_freewheeling) {
		return 0;
	}

	self->cycle_start = jack_last_frame_time (self->jack_client);
	
	stream_ptr = &self->stream;
	a2j_add_ports (stream_ptr);
	
	// process ports
	
	for (i = 0 ; i < PORT_HASH_SIZE ; i++) {

		port_ptr = &stream_ptr->port_hash[i];

		while (*port_ptr != NULL) {

			struct a2j_alsa_midi_event ev;
			jack_nframes_t now;
			jack_nframes_t one_period;
			char *ev_buf;
				
			port = *port_ptr;
			
			if (port->is_dead) {
				if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) {
				
					a2j_debug("jack: removed port %s", port->name);
					*port_ptr = port->next;
					jack_ringbuffer_write (self->port_del, (char*)&port, sizeof(port));
				} else {
					a2j_error ("port deletion lost - no space in event buffer!");
				}

				port_ptr = &port->next;
				continue;
			}

			port->jack_buf = jack_port_get_buffer(port->jack_port, nframes);
				
			/* grab data queued by the ALSA input thread and write it into the JACK
			   port buffer. it will delivered during the JACK period that this
			   function is called from.
			*/
				
			/* first clear the JACK port buffer in preparation for new data 
			 */
				
			// a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
				
			jack_midi_clear_buffer (port->jack_buf);
				
			now = jack_frame_time (self->jack_client);
			one_period = jack_get_buffer_size (self->jack_client);
				
			while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
					
				jack_midi_data_t* buf;
				jack_nframes_t offset;
					
				if (ev.time >= self->cycle_start) {
					break;
				}
					
				//jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
				ev_buf = (char *) alloca( sizeof(ev) + ev.size );
					
				if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size)
					break;
					
				offset = self->cycle_start - ev.time;
				if (offset > one_period) {
					/* from a previous cycle, somehow. cram it in at the front */
					offset = 0;
				} else {
					/* offset from start of the current cycle */
					offset = one_period - offset;
				}
					
				a2j_debug ("event at %d offset %d", ev.time, offset);
					
				/* make sure there is space for it */
					
				buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
					
				if (buf) {
					/* grab the event */
					memcpy( buf, ev_buf + sizeof(ev), ev.size );
				} else {
					/* throw it away (no space) */
					a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
				}
				jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
					
				a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
			}
			
			port_ptr = &port->next;
		}
	}

	return 0;
}
Beispiel #20
0
static int _frame_time(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj* const *objv) {
  _t *dp = (_t *)clientData;
  if (argc != 2) return fw_error_str(interp, "jack-client frame-time");
  Tcl_SetObjResult(interp, Tcl_NewIntObj(jack_frame_time(dp->fw.client)));
  return TCL_OK;
}
Beispiel #21
0
int process(jack_nframes_t nframes, void *arg) {
    struct guitarseq *guitarseq = arg;
    if(!guitarseq) {
        fprintf(stderr, "No guitarseq instance!\n");
        return 1;
    }

    void* port_buf;
    jack_nframes_t now = jack_frame_time (guitarseq->jack_client);

    //Output
    port_buf = jack_port_get_buffer(guitarseq->out_port, nframes);
    jack_midi_clear_buffer(port_buf);
    while (1) {
        jack_nframes_t time;
        //TODO: Do a safer read, in case only part of the message is here
        if (!jack_ringbuffer_read (guitarseq->out_buffer, (char *)&time, sizeof(time))) {
            break;
        }

        // from the future?
        if (time >= now) {
            break;
        }

        // time it right
        jack_nframes_t offset = time - now + nframes - 1;

        // get the size of the event
        size_t size;
        jack_ringbuffer_read(guitarseq->out_buffer, (char *)&size, sizeof(size));

        INFO("out event at %u%+d size %zu\n", now, offset, size);

        if (offset > nframes)
            // from the past, somehow. cram it in at the front
            offset = 0;

        // proceed to giving it to jack
        jack_midi_data_t *buffer = jack_midi_event_reserve (port_buf, offset, size);
        if(buffer) {
            jack_ringbuffer_read(guitarseq->out_buffer, (char *)buffer, size);
        } else {
            // throw it away :( TODO: find more
            jack_ringbuffer_read_advance (guitarseq->out_buffer, size);
            ERROR("threw away MIDI event - no space reserved at time %u offset %d\n",time,offset);
        }
    }

    // 	Input
    port_buf = jack_port_get_buffer(guitarseq->in_port, nframes);
    jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
    for(jack_nframes_t i=0; i<event_count; i++) {
        jack_midi_event_t in_event;
        jack_midi_event_get(&in_event, port_buf, i);

        //adds a note to the ringbuffer
        if (jack_ringbuffer_write_space(guitarseq->in_buffer) >= sizeof(in_event.time)+sizeof(in_event.size)+in_event.size) {
            jack_ringbuffer_write(guitarseq->in_buffer, (char *)&in_event.time, sizeof(in_event.time));
            jack_ringbuffer_write(guitarseq->in_buffer, (char *)&in_event.size, sizeof(in_event.size));
            jack_ringbuffer_write(guitarseq->in_buffer, (char *)in_event.buffer, in_event.size);
        } else {
            ERROR("Couldn't write to ringbuffer at %u, %zu midi data bytes lost\n", in_event.time, in_event.size);
        }
    }

    return 0;
}
Beispiel #22
0
jack_nframes_t luajack_frame_time(luajack_t *client) 
	{
	cud_t *cud = get_cud(client);	
	if(!cud) return 0;
	return jack_frame_time(cud->client);
	}