Added midi.c for SMF decoding.
[cantaveria.git] / seq.c
blob8658c53c5e2debd1aa7803669d1464fa4a6c282c
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 <seq.h>
28 #include <org.h>
29 #include <list.h>
30 #include <audio.h>
31 #include <util.h>
33 int tick;
34 int terr;
35 int loop_start;
36 int looping;
38 //event lists
39 list* sequence;
40 list* blank_events;
41 list* immediate_events;
43 list* next_event;
44 list* event_after_loop;
48 void advance_event(event* now){
49 if(now->type == 0x100 && looping){
50 next_event = event_after_loop;
51 tick = loop_start;
53 else{
54 next_event = next_event->next;
58 event* dequeue_event(){
59 if(next_event == NULL) return NULL;
61 event* e = next_event->item;
62 if(e->tick <= tick){
63 advance_event(e);
64 return e;
66 else{
67 return NULL;
71 int samples_until_next(int max){
72 int N = 2646000;
73 int D = 46080;
75 if(next_event == NULL) return max;
77 event* e = next_event->item;
78 if(e->tick - tick > max * D / N) return max;
80 int d = (e->tick-tick)*N/D;
81 return d < max ? d : max;
84 event* seq_advance(int max, int* used){
85 int N = 46080; // bpm * tpb
86 int D = 2646000; // srate * 60
88 int u = samples_until_next(max);
90 terr += N * u;
91 tick += terr/D;
92 terr %= D;
94 *used = u;
95 return dequeue_event();
101 /* *** */
102 static event* make_event(int type, int chan, int val1, int val2){
103 event* e;
104 if(blank_events->next){
105 e = pop(blank_events);
107 else{
108 e = xmalloc(sizeof(event));
111 e->type = type;
112 e->chan = chan;
113 e->val1= val1;
114 e->val2= val2;
115 e->tick = 0;
116 return e;
119 void recycle_event(event* e){
120 push(blank_events, e);
124 void seq_instant(int type, int chan, int val1, int val2){
125 event* e = make_event(type, chan, val1, val2);
126 audio_lock();
127 append(immediate_events, e);
128 audio_unlock();
132 void seq_play_sound(int id){
133 seq_instant(0x90, 15, id, 0);
138 event* seq_get_immediate(){
139 event* e = pop(immediate_events);
140 if(e != NULL){
141 recycle_event(e);
142 return e;
144 else{
145 return NULL;
151 void seq_enqueue(int when, int type, int chan, int val1, int val2){
152 event* e = make_event(type, chan, val1, val2);
153 e->tick = when;
154 seq_append(e);
157 void seq_clear(){
158 list* ptr = sequence->next;
159 while(ptr){
160 free(ptr->item);
161 ptr = ptr->next;
163 recycle(sequence);
164 sequence = empty();
168 void seq_append(event* e){
169 append(sequence, e);
172 void seq_init(){
173 printf(" sequencer: ... ");
175 blank_events = empty();
176 immediate_events = empty();
177 sequence = empty();
181 seq_enqueue(0, 0x90, 1, 0, 0);
182 seq_enqueue(384, 0x80, 1, 0, 0);
183 seq_enqueue(384, 0x90, 1, 2, 0);
184 seq_enqueue(384*2, 0x80, 1, 2, 0);
185 seq_enqueue(384*2, 0x90, 1, 4, 0);
186 seq_enqueue(384*3, 0x80, 1, 4, 0);
187 seq_enqueue(384*3, 0x90, 1, 0, 0);
188 seq_enqueue(384*4, 0x80, 1, 0, 0);
189 seq_enqueue(384*4, 0x90, 1, 0, 0);
190 seq_enqueue(384*5, 0x80, 1, 0, 0);
191 seq_enqueue(384*5, 0x90, 1, 2, 0);
192 seq_enqueue(384*6, 0x80, 1, 2, 0);
193 seq_enqueue(384*6, 0x90, 1, 4, 0);
194 seq_enqueue(384*7, 0x80, 1, 4, 0);
195 seq_enqueue(384*7, 0x90, 1, 0, 0);
196 seq_enqueue(384*8, 0x80, 1, 0, 0);
197 seq_enqueue(384*8, 0x100, 0, 0, 0);
199 looping = 1;
200 loop_start = 0;
201 event_after_loop = sequence->next;
203 next_event = sequence->next;
204 printf("OK\n");