Re: [linux-audio-dev] Sequencer Sync Woes

New Message Reply About this list Date view Thread view Subject view Author view Other groups

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__ */


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Tue Feb 06 2001 - 06:44:10 EET