Testing of song playback.
[cantaveria.git] / seq.c
blob83ac8f6230813e7ab73d08c00aa6c2ebfa94bd1c
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 <seq.h>
29 #include <org.h>
30 #include <audio.h>
31 #include <util.h>
33 int tick;
34 int terr;
35 int loop_start;
36 int looping;
37 int enable = 0;
39 int bpm = 120;
40 int tpb = 384;
42 //event lists
43 list* sequence;
44 list* blank_events;
45 list* immediate_events;
47 list* next_event;
48 list* event_after_loop;
52 void advance_event(event* now){
53 if(now->type == 0x100 && looping){
54 next_event = event_after_loop;
55 tick = loop_start;
57 else{
58 next_event = next_event->next;
62 event* dequeue_event(){
63 if(next_event == NULL) return NULL;
65 event* e = next_event->item;
66 if(e->tick <= tick){
67 advance_event(e);
69 if(e->type == EVX_TEMPOCHANGE){
70 //printf("tempo change to %d bpm\n", e->val1);
71 bpm = e->val1;
74 if(e->type == EVX_TICKSPERBEAT){
75 //printf("setting tpb to %d\n", e->val1);
76 tpb = e->val1;
78 //printf("event (%d, %03x, %d, %d, %d)\n", e->tick, e->type, e->chan, e->val1, e->val2);
80 return e;
82 else{
83 return NULL;
87 int samples_until_next(int max){
88 int N = 2646000;
89 int D = bpm*tpb;
91 if(next_event == NULL) return max;
93 event* e = next_event->item;
94 if(e->tick - tick > max * D / N) return max;
96 int d = (e->tick-tick)*N/D;
97 return d < max ? d : max;
100 event* seq_advance(int max, int* used){
101 int N = bpm*tpb; // bpm * tpb
102 int D = 2646000; // srate * 60
104 int u = samples_until_next(max);
106 if(!enable){
107 *used = max;
108 return NULL;
111 terr += N * u;
112 tick += terr/D;
113 terr %= D;
115 *used = u;
116 return dequeue_event();
122 /* *** */
123 static event* make_event(int type, int chan, int val1, int val2){
124 event* e;
125 if(blank_events->next){
126 e = pop(blank_events);
128 else{
129 e = xmalloc(sizeof(event));
132 e->type = type;
133 e->chan = chan;
134 e->val1= val1;
135 e->val2= val2;
136 e->tick = 0;
137 return e;
140 void recycle_event(event* e){
141 push(blank_events, e);
145 void seq_instant(int type, int chan, int val1, int val2){
146 event* e = make_event(type, chan, val1, val2);
147 audio_lock();
148 append(immediate_events, e);
149 audio_unlock();
153 void seq_play_sound(int id){
154 seq_instant(0x90, 15, id, 0);
159 event* seq_get_immediate(){
160 event* e = pop(immediate_events);
161 if(e != NULL){
162 recycle_event(e);
163 return e;
165 else{
166 return NULL;
172 void seq_enqueue(int when, int type, int chan, int val1, int val2){
173 event* e = make_event(type, chan, val1, val2);
174 e->tick = when;
175 seq_append(e);
178 void seq_clear(){
179 list* ptr = sequence->next;
180 while(ptr){
181 free(ptr->item);
182 ptr = ptr->next;
184 recycle(sequence);
185 sequence = empty();
189 void seq_append(event* e){
190 append(sequence, e);
193 void seq_init(){
194 printf(" sequencer: ... ");
196 blank_events = empty();
197 immediate_events = empty();
198 sequence = empty();
201 looping = 0;
202 loop_start = 0;
204 next_event = sequence->next;
205 printf("OK\n");
208 void seq_load(list* events){
209 audio_lock();
210 tick = 0;
211 terr = 0;
212 sequence = events;
213 next_event = sequence->next;
214 event_after_loop = next_event;
215 looping = 0; /* fixme */
216 loop_start = 0;
217 audio_unlock();
220 void seq_seek(list* target){
221 event* e = target->item;
222 audio_lock();
223 next_event = target;
224 tick = e->tick;
225 audio_unlock();
228 list* seq_tell(){
229 return next_event;
232 void seq_enable(){
233 enable = 1;
236 void seq_disable(){
237 /* needs to enqueue an 'all off' instant event */
238 enable = 0;