2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (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, see <http://www.gnu.org/licenses/>.
25 static gboolean
master_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
27 struct cbox_master
*m
= ct
->user_data
;
28 if (!strcmp(cmd
->command
, "/status") && !*cmd
->arg_types
)
30 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
32 if (!cbox_execute_on(fb
, NULL
, "/sample_rate", "i", error
, m
->srate
))
36 return cbox_execute_on(fb
, NULL
, "/tempo", "f", error
, m
->tempo
) &&
37 cbox_execute_on(fb
, NULL
, "/timesig", "ii", error
, m
->timesig_nom
, m
->timesig_denom
) &&
38 cbox_execute_on(fb
, NULL
, "/playing", "i", error
, (int)m
->state
) &&
39 cbox_execute_on(fb
, NULL
, "/pos", "i", error
, m
->spb
->song_pos_samples
) &&
40 cbox_execute_on(fb
, NULL
, "/pos_ppqn", "i", error
, m
->spb
->song_pos_ppqn
);
43 if (!strcmp(cmd
->command
, "/tell") && !*cmd
->arg_types
)
45 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
49 return cbox_execute_on(fb
, NULL
, "/playing", "i", error
, (int)m
->state
) &&
50 cbox_execute_on(fb
, NULL
, "/pos", "i", error
, m
->spb
->song_pos_samples
) &&
51 cbox_execute_on(fb
, NULL
, "/pos_ppqn", "i", error
, m
->spb
->song_pos_ppqn
);
54 if (!strcmp(cmd
->command
, "/set_tempo") && !strcmp(cmd
->arg_types
, "f"))
56 cbox_master_set_tempo(m
, CBOX_ARG_F(cmd
, 0));
60 if (!strcmp(cmd
->command
, "/set_timesig") && !strcmp(cmd
->arg_types
, "ii"))
62 cbox_master_set_timesig(m
, CBOX_ARG_I(cmd
, 0), CBOX_ARG_I(cmd
, 1));
66 if (!strcmp(cmd
->command
, "/play") && !strcmp(cmd
->arg_types
, ""))
72 if (!strcmp(cmd
->command
, "/stop") && !strcmp(cmd
->arg_types
, ""))
78 if (!strcmp(cmd
->command
, "/seek_samples") && !strcmp(cmd
->arg_types
, "i"))
81 cbox_song_playback_seek_samples(m
->spb
, CBOX_ARG_I(cmd
, 0));
85 if (!strcmp(cmd
->command
, "/seek_ppqn") && !strcmp(cmd
->arg_types
, "i"))
88 cbox_song_playback_seek_ppqn(m
->spb
, CBOX_ARG_I(cmd
, 0), FALSE
);
93 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Unknown combination of target path and argument: '%s', '%s'", cmd
->command
, cmd
->arg_types
);
98 static void cbox_master_init(struct cbox_master
*master
, struct cbox_rt
*rt
)
101 master
->tempo
= 120.0;
102 master
->new_tempo
= 120.0;
103 master
->timesig_nom
= 4;
104 master
->timesig_denom
= 4;
105 master
->state
= CMTS_STOP
;
109 cbox_command_target_init(&master
->cmd_target
, master_process_cmd
, master
);
112 struct cbox_master
*cbox_master_new(struct cbox_rt
*rt
)
114 struct cbox_master
*master
= malloc(sizeof(struct cbox_master
));
115 cbox_master_init(master
, rt
);
120 void cbox_master_set_sample_rate(struct cbox_master
*master
, int srate
)
122 master
->srate
= srate
;
125 void cbox_master_set_tempo(struct cbox_master
*master
, float tempo
)
127 // XXXKF not realtime-safe; won't crash, but may lose tempo
128 // changes when used multiple times in rapid succession
129 master
->new_tempo
= tempo
;
132 void cbox_master_set_timesig(struct cbox_master
*master
, int beats
, int unit
)
134 master
->timesig_nom
= beats
;
135 master
->timesig_denom
= unit
;
139 void cbox_master_to_bbt(const struct cbox_master *master, struct cbox_bbt *bbt, int time_samples)
141 double second = ((double)time_samples) / master->srate;
142 double beat = master->tempo * second / 60;
143 int beat_int = (int)beat;
144 bbt->bar = beat_int / master->timesig_nom;
145 bbt->beat = beat_int % master->timesig_nom;
146 bbt->tick = (beat - beat_int) * PPQN; // XXXKF what if timesig_denom is not 4?
150 uint32_t cbox_master_song_pos_from_bbt(struct cbox_master *master, const struct cbox_bbt *bbt)
152 double beat = bbt->bar * master->timesig_nom + bbt->beat + bbt->tick * 1.0 / PPQN;
153 return (uint32_t)(master->srate * 60 / master->tempo);
157 void cbox_master_play(struct cbox_master
*master
)
159 master
->state
= CMTS_ROLLING
;
162 void cbox_master_stop(struct cbox_master
*master
)
164 master
->state
= CMTS_STOP
;
167 int cbox_master_ppqn_to_samples(struct cbox_master
*master
, int time_ppqn
)
169 double tempo
= master
->tempo
;
173 int idx
= cbox_song_playback_tmi_from_ppqn(master
->spb
, time_ppqn
);
176 const struct cbox_tempo_map_item
*tmi
= &master
->spb
->tempo_map_items
[idx
];
178 time_ppqn
-= tmi
->time_ppqn
;
179 offset
= tmi
->time_samples
;
182 return offset
+ (int)(master
->srate
* 60.0 * time_ppqn
/ (tempo
* PPQN
));
185 int cbox_master_samples_to_ppqn(struct cbox_master
*master
, int time_samples
)
187 double tempo
= master
->tempo
;
191 int idx
= cbox_song_playback_tmi_from_samples(master
->spb
, time_samples
);
194 const struct cbox_tempo_map_item
*tmi
= &master
->spb
->tempo_map_items
[idx
];
196 time_samples
-= tmi
->time_samples
;
197 offset
= tmi
->time_ppqn
;
200 return offset
+ (int)(tempo
* PPQN
* time_samples
/ (master
->srate
* 60.0));
203 void cbox_master_destroy(struct cbox_master
*master
)
207 cbox_song_playback_destroy(master
->spb
);