summaryrefslogtreecommitdiff
path: root/sid/sidplay-libs-2.1.0/libsidplay/include/sidplay/event.h
blob: b89af24eacadee7ad26a6495eccda849ce88f4c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/***************************************************************************
                          event.h  -  Event scheduler (based on alarm
                                      from Vice)
                             -------------------
    begin                : Wed May 9 2001
    copyright            : (C) 2001 by Simon White
    email                : s_a_white@email.com
 ***************************************************************************/

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

#ifndef _event_h_
#define _event_h_

#include <stdio.h>
#include "sidtypes.h"

typedef uint_fast32_t event_clock_t;
#define EVENT_CONTEXT_MAX_PENDING_EVENTS 0x100

class SID_EXTERN Event
{
private:
    friend  class EventScheduler;
    const   char * const m_name;
    event_clock_t m_clk;

    /* This variable is set by the event context
       when it is scheduled */
    bool m_pending;

    /* Link to the next and previous events in the
       list.  */
    Event *m_next, *m_prev;

public:
    Event(const char * const name)
        : m_name(name),
          m_pending(false) {}

    virtual void event (void) = 0;
};

// Public Event Context
class EventContext
{
public:
    virtual void cancel   (Event *event) = 0;
    virtual void schedule (Event *event, event_clock_t cycles) = 0;
    virtual event_clock_t getTime (void) const = 0;
    virtual event_clock_t getTime (event_clock_t clock) const = 0;
};

// Private Event Context Object (The scheduler)
class EventScheduler: public EventContext
{
private:
    const char * const m_name;
    event_clock_t  m_eventClk, m_schedClk;
    uint  m_pendingEventClk;
    uint  m_pendingEventCount;

    class SID_EXTERN EventDummy: public Event
    {
    private:
        void event (void) {;}
    public:
        EventDummy () : Event("Bad Event: Dummy") {;}
    } m_pendingEvents;

    class SID_EXTERN EventTimeWarp: public Event
    {
    private:
        EventScheduler &m_scheduler;

        void event (void)
        {
            m_scheduler.timeWarp ();
        }

    public:
        EventTimeWarp (EventScheduler *context)
        :Event("Time Warp"),
         m_scheduler(*context)
        {;}
    } m_timeWarp;
    friend class EventTimeWarp;

private:
    void timeWarp (void);
    void dispatch (void)
    {
        Event &e = *m_pendingEvents.m_next;
        cancelPending (e);
        //printf ("Event \"%s\"\n", e.m_name);
        e.event ();
    }

    void cancelPending (Event &event)
    {
        event.m_pending      = false;
        event.m_prev->m_next = event.m_next;
        event.m_next->m_prev = event.m_prev;
        m_pendingEventClk    = m_pendingEvents.m_next->m_clk;
        m_pendingEventCount--;
    }

public:
    EventScheduler (const char * const name);
    void cancel    (Event *event);
    void reset     (void);
    void schedule  (Event *event, event_clock_t cycles);

    void clock (void)
    {
        if (m_pendingEventCount)
        {
            event_clock_t delta = m_pendingEventClk - m_eventClk;
            m_schedClk  += delta;
            m_eventClk  += delta;
            dispatch ();
        }
    }

    event_clock_t getTime (void) const
    {   return m_schedClk; }
    event_clock_t getTime (event_clock_t clock) const
    {   return m_schedClk - clock; }
};

#endif // _event_h_