Changed printf to error_msg.
[cantaveria.git] / seq.c
blob31a7362272b614422a1d5d4861e269e431be94f1
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 //printf("tempo change to %d bpm\n", e->val1);
70 bpm = e->val1;
73 if(e->type == EVX_TICKSPERBEAT){
74 //printf("setting tpb to %d\n", e->val1);
75 tpb = e->val1;
78 if(e->type == EVX_LOOPSTART){
79 loop_start = e->tick;
80 event_after_loop = next_event;
84 //printf("event (%d, %03x, %d, %d, %d)\n", e->tick, e->type, e->chan, e->val1, e->val2);
86 return e;
88 else{
89 return NULL;
93 int samples_until_next(int max){
94 int N = 2646000;
95 int D = bpm*tpb;
97 if(next_event == NULL) return max;
99 event* e = next_event->item;
100 if(e->tick - tick > max * D / N) return max;
102 int d = (e->tick-tick)*N/D;
103 return d < max ? d : max;
106 event* seq_advance(int max, int* used){
107 int N = bpm*tpb; // bpm * tpb
108 int D = 2646000; // srate * 60
109 event* e;
111 int u = samples_until_next(max);
113 if(!enable){
114 *used = max;
115 return NULL;
118 *used = u;
119 e = dequeue_event();
121 terr += N * u;
122 tick += terr/D;
123 terr %= D;
125 return e;
131 /* *** */
132 static event* make_event(int type, int chan, int val1, int val2){
133 event* e;
134 if(blank_events->next){
135 e = pop(blank_events);
137 else{
138 e = xmalloc(sizeof(event));
141 e->type = type;
142 e->chan = chan;
143 e->val1= val1;
144 e->val2= val2;
145 e->tick = 0;
146 return e;
149 void recycle_event(event* e){
150 push(blank_events, e);
154 void seq_instant(int type, int chan, int val1, int val2){
155 event* e = make_event(type, chan, val1, val2);
156 audio_lock();
157 append(immediate_events, e);
158 audio_unlock();
162 void seq_play_sound(int id){
163 seq_instant(0x90, 15, id, 0);
168 event* seq_get_immediate(){
169 event* e = pop(immediate_events);
170 if(e != NULL){
171 recycle_event(e);
172 return e;
174 else{
175 return NULL;
181 void seq_enqueue(int when, int type, int chan, int val1, int val2){
182 event* e = make_event(type, chan, val1, val2);
183 e->tick = when;
184 seq_append(e);
187 void seq_clear(){
188 list* ptr = sequence->next;
189 while(ptr){
190 free(ptr->item);
191 ptr = ptr->next;
193 recycle(sequence);
194 sequence = empty();
198 void seq_append(event* e){
199 append(sequence, e);
202 void seq_init(){
203 blank_events = empty();
204 immediate_events = empty();
205 sequence = empty();
207 loop_start = 0;
209 next_event = sequence->next;
212 void seq_load(list* events){
213 audio_lock();
214 tick = 0;
215 terr = 0;
216 sequence = events;
217 next_event = sequence->next;
218 event_after_loop = next_event;
219 loop_start = 0;
220 audio_unlock();
223 void seq_seek(list* target){
224 event* e = target->item;
225 audio_lock();
226 next_event = target;
227 tick = e->tick;
228 audio_unlock();
231 list* seq_tell(){
232 return next_event;
235 void seq_enable(){
236 enable = 1;
239 void seq_disable(){
240 seq_instant(EVX_MUSICCUT, 0, 0, 0);
241 enable = 0;