Subject: Re: [linux-audio-dev] Sequencer Sync Woes
From: Paul Davis (pbd_AT_Op.Net)
Date: Tue Feb 06 2001 - 06:23:57 EET
> So, maybe I'm ok to use /dev/midi00? Is that what everyone else uses?
>Am I doing something wrong in my loop? Is there a way to yield a
>smaller amount of time maybe so I can poll more often? My pseudocode:
>
> loop {
> nanosleep( 5ms ); // something less than HZ I guess?
> // let the editor get some cpu
>
> diff = gettimeofday - time_last_tick_we_sent_was_due
>
> if diff > time_per_tick:
> - output a sync tick along with the notes for this tick
> - remember the time that tick was supposed to be sent, we use
> that for the difference above
> fi
> }
>
> Should I write a kernel module which I can use to queue writes?
i'd use this (below). the key is to hook into the call to RTC::tick().
the object below starts its own thread which sets up the RTC to
provide a periodic wakeup (freq up to 8kHz). that thread runs the
RTC::do_work() function, which basically just poll(2)'s the RTC fd,
and sends the "tick()" signal every time it wakes up. for the non
libsigc++, think of a signal as a linked list of callbacks that get
executed en-masse.
the design assumes that the thread will run with SCHED_FIFO priority
and has its memory locked down. the responsibility for checking the
*actual* time lies with whatever decides to receive the "tick()"
signal.
this is very similar to the way SoftWerk works too, except that it
uses SIGIO-based notification from the RTC, not poll(2)-based wakeup.
--p
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: rtc.cc,v 1.1 2001/01/16 17:19:47 pbd Exp $
*/
#include <stdio.h>
#include <linux/rtc.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <math.h>
#include <sys/ioctl.h>
#include "ardour.h"
#include "rtc.h"
using namespace ARDOUR;
RealTimeClock::RealTimeClock ()
: QMThread ("realtime clock", start_thread, this, true, 8)
{
if ((rtc_fd = open ("/dev/rtc", O_RDONLY)) < 0) {
error << "RealTimeClock: cannot open /dev/rtc ("
<< strerror (errno)
<< ')'
<< endmsg;
throw failed_constructor();
}
if (fcntl (rtc_fd, F_SETOWN, getpid()) < 0) {
error << "RealTimeClock: cannot set ownership of /dev/rtc ("
<< strerror (errno)
<< ')'
<< endmsg;
throw failed_constructor();
}
rtc_running = false;
current_hz = 0;
}
RealTimeClock::~RealTimeClock ()
{
stop_periodic_interrupts ();
close (rtc_fd);
}
void *
RealTimeClock::start_thread (void *arg)
{
RealTimeClock *rtc = (RealTimeClock *) arg;
return rtc->main ();
}
void *
RealTimeClock::do_work ()
{
unsigned long rtc_data;
start_periodic_interrupts ();
while (!work_no_more()) {
struct pollfd pfd;
pfd.fd = rtc_fd;
pfd.events = POLLIN | POLLERR;
again:
if (poll (&pfd, 1, 100000) < 0) {
if (errno == EINTR) {
// this happens mostly when run
// under gdb, or when exiting due to a signal
goto again;
}
error << "RealTimeClock: poll call failed ("
<< strerror (errno)
<< ')'
<< endmsg;
return (void *) -1;
}
read (rtc_fd, &rtc_data, sizeof (rtc_data));
tick ();
}
return 0;
}
bool
RealTimeClock::set_interval (guint32 usecs)
{
int req_hz = (int) floor ((1000000.0/usecs));
int hz = 2;
bool restart;
hz = 2;
while (hz < req_hz) {
hz *= 2;
}
if (hz == current_hz) {
return true;
}
restart = stop_periodic_interrupts ();
if (ioctl(rtc_fd, RTC_IRQP_SET, hz) < 0) {
error << "RealTimeClock: cannot set periodic interval ("
<< strerror (errno)
<< ')'
<< endmsg;
return -1;
}
current_hz = hz;
if (restart) {
start_periodic_interrupts ();
}
return true;
}
bool
RealTimeClock::start_periodic_interrupts ()
{
if (!rtc_running) {
if (ioctl (rtc_fd, RTC_PIE_ON, 0) < 0) {
error << "RealTimeClock: cannot start periodic interrupts ("
<< strerror (errno)
<< ')'
<< endmsg;
return false;
}
rtc_running = true;
}
return rtc_running;
}
bool
RealTimeClock::stop_periodic_interrupts ()
{
bool was_running = rtc_running;
if (rtc_running) {
if (ioctl (rtc_fd, RTC_PIE_OFF, 0) < 0) {
error << "RealTimeClock: cannot stop periodic interrupts ("
<< strerror (errno)
<< ')'
<< endmsg;
return rtc_running;
}
rtc_running = false;
}
return was_running;
}
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: rtc.h,v 1.1 2001/01/16 17:19:47 pbd Exp $
*/
#ifndef __ardour_rtc_h__
#define __ardour_rtc_h__
#include <pbd/thread.h>
#include <sigc++/signal_system.h>
class RealTimeClock : public QMThread, public SigC::Object
{
public:
RealTimeClock ();
virtual ~RealTimeClock();
bool set_interval (unsigned int usecs);
SigC::Signal0<void> tick;
private:
int rtc_fd;
int current_hz;
bool rtc_running;
bool start_periodic_interrupts ();
bool stop_periodic_interrupts ();
static void *start_thread (void *);
void *do_work ();
};
#endif /* __ardour_rtc_h__ */
This archive was generated by hypermail 2b28 : Tue Feb 06 2001 - 06:44:10 EET