Rewrite of the stage module.
[cantaveria.git] / seq.c
blob65ac307ba906f9cb764e1f98c521ba509c86c796
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
22 evanrinehart@gmail.com
24 #include <stdio.h>
25 #include <stdlib.h>
27 #include <list.h>
28 #include <util.h>
29 #include <audio.h>
30 #include <midi.h>
31 #include <seq.h>
33 int tick;
34 int terr;
35 int loop_start;
36 int enable = 0;
38 int bpm = 120;
39 int tpb = 384;
41 //event lists
42 list* sequence;
43 list* blank_events;
44 list* immediate_events;
46 list* next_event;
47 list* event_after_loop;
51 void advance_event(event* now){
52 if(now->type == EVX_LOOPEND){
53 next_event = event_after_loop;
54 tick = loop_start;
56 else{
57 next_event = next_event->next;
61 event* dequeue_event(){
62 if(next_event == NULL) return NULL;
64 event* e = next_event->item;
65 if(e->tick <= tick){
66 advance_event(e);
68 if(e->type == EVX_TEMPOCHANGE){
69 bpm = e->val1;
72 if(e->type == EVX_TICKSPERBEAT){
73 tpb = e->val1;
76 if(e->type == EVX_LOOPSTART){
77 loop_start = e->tick;
78 event_after_loop = next_event;
81 return e;
83 else{
84 return NULL;
88 int samples_until_next(int max){
89 int N = 2646000;
90 int D = bpm*tpb;
92 if(next_event == NULL) return max;
94 event* e = next_event->item;
95 if(e->tick - tick > max * D / N) return max;
97 int d = (e->tick-tick)*N/D;
98 return d < max ? d : max;
101 event* seq_advance(int max, int* used){
102 int N = bpm*tpb; // bpm * tpb
103 int D = 2646000; // srate * 60
104 event* e;
106 int u = samples_until_next(max);
108 if(!enable){
109 *used = max;
110 return NULL;
113 *used = u;
114 e = dequeue_event();
116 terr += N * u;
117 tick += terr/D;
118 terr %= D;
120 return e;
126 /* *** */
127 static event* make_event(int type, int chan, int val1, int val2){
128 event* e;
129 if(blank_events->next){
130 e = pop(blank_events);
132 else{
133 e = xmalloc(sizeof(event));
136 e->type = type;
137 e->chan = chan;
138 e->val1= val1;
139 e->val2= val2;
140 e->tick = 0;
141 return e;
144 void recycle_event(event* e){
145 push(blank_events, e);
149 void seq_instant(int type, int chan, int val1, int val2){
150 event* e = make_event(type, chan, val1, val2);
151 audio_lock();
152 append(immediate_events, e);
153 audio_unlock();
157 void seq_play_sound(int id){
158 seq_instant(0x90, 15, id, 0);
163 event* seq_get_immediate(){
164 event* e = pop(immediate_events);
165 if(e != NULL){
166 recycle_event(e);
167 return e;
169 else{
170 return NULL;
176 void seq_enqueue(int when, int type, int chan, int val1, int val2){
177 event* e = make_event(type, chan, val1, val2);
178 e->tick = when;
179 seq_append(e);
182 void seq_clear(){
183 list* ptr = sequence->next;
184 while(ptr){
185 free(ptr->item);
186 ptr = ptr->next;
188 recycle(sequence);
189 sequence = empty();
193 void seq_append(event* e){
194 append(sequence, e);
197 void seq_init(){
198 blank_events = empty();
199 immediate_events = empty();
200 sequence = empty();
202 loop_start = 0;
204 next_event = sequence->next;
207 void seq_load(list* events){
208 audio_lock();
209 tick = 0;
210 terr = 0;
211 sequence = events;
212 next_event = sequence->next;
213 event_after_loop = next_event;
214 loop_start = 0;
215 audio_unlock();
218 void seq_seek(list* target){
219 event* e = target->item;
220 audio_lock();
221 next_event = target;
222 tick = e->tick;
223 audio_unlock();
226 list* seq_tell(){
227 return next_event;
230 void seq_enable(){
231 enable = 1;
234 void seq_disable(){
235 seq_instant(EVX_MUSICCUT, 0, 0, 0);
236 enable = 0;