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/>.
29 CBOX_CLASS_DEFINITION_ROOT(cbox_track
)
30 CBOX_CLASS_DEFINITION_ROOT(cbox_track_item
)
32 static gboolean
cbox_track_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
);
33 static gboolean
cbox_track_item_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
);
35 void cbox_track_item_destroyfunc(struct cbox_objhdr
*hdr
)
37 struct cbox_track_item
*item
= CBOX_H2O(hdr
);
38 item
->owner
->items
= g_list_remove(item
->owner
->items
, item
);
42 struct cbox_track
*cbox_track_new(struct cbox_document
*document
)
44 struct cbox_track
*p
= malloc(sizeof(struct cbox_track
));
45 CBOX_OBJECT_HEADER_INIT(p
, cbox_track
, document
);
47 p
->name
= g_strdup("Unnamed");
52 cbox_command_target_init(&p
->cmd_target
, cbox_track_process_cmd
, p
);
53 CBOX_OBJECT_REGISTER(p
);
57 #define CBTI(it) ((struct cbox_track_item *)(it)->data)
59 struct cbox_track_item
*cbox_track_add_item(struct cbox_track
*track
, uint32_t time
, struct cbox_midi_pattern
*pattern
, uint32_t offset
, uint32_t length
)
61 struct cbox_track_item
*item
= malloc(sizeof(struct cbox_track_item
));
62 CBOX_OBJECT_HEADER_INIT(item
, cbox_track_item
, CBOX_GET_DOCUMENT(track
));
65 item
->pattern
= pattern
;
66 item
->offset
= offset
;
67 item
->length
= length
;
68 cbox_command_target_init(&item
->cmd_target
, cbox_track_item_process_cmd
, item
);
70 GList
*it
= track
->items
;
71 while(it
!= NULL
&& CBTI(it
)->time
< item
->time
)
73 // all items earlier than the new one -> append
76 track
->items
= g_list_append(track
->items
, item
);
77 CBOX_OBJECT_REGISTER(item
);
80 // Here, I don't really care about overlaps - it's more important to preserve
81 // all clips as sent by the caller.
82 track
->items
= g_list_insert_before(track
->items
, it
, item
);
83 CBOX_OBJECT_REGISTER(item
);
87 void cbox_track_destroyfunc(struct cbox_objhdr
*objhdr
)
89 struct cbox_track
*track
= CBOX_H2O(objhdr
);
91 cbox_song_remove_track(track
->owner
, track
);
92 // XXXKF I'm not sure if I want the lifecycle of track playback objects to be managed by the track itself
94 cbox_track_playback_destroy(track
->pb
);
95 // The items will unlink themselves from the list in destructor
97 cbox_object_destroy(track
->items
->data
);
98 g_free((gchar
*)track
->name
);
102 gboolean
cbox_track_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
104 struct cbox_track
*track
= ct
->user_data
;
105 if (!strcmp(cmd
->command
, "/status") && !strcmp(cmd
->arg_types
, ""))
107 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
110 GList
*it
= track
->items
;
113 struct cbox_track_item
*trki
= it
->data
;
114 if (!cbox_execute_on(fb
, NULL
, "/clip", "iiioo", error
, trki
->time
, trki
->offset
, trki
->length
, trki
->pattern
, trki
))
116 it
= g_list_next(it
);
119 return cbox_execute_on(fb
, NULL
, "/name", "s", error
, track
->name
) &&
120 CBOX_OBJECT_DEFAULT_STATUS(track
, fb
, error
);
122 else if (!strcmp(cmd
->command
, "/add_clip") && !strcmp(cmd
->arg_types
, "iiis"))
124 int pos
= CBOX_ARG_I(cmd
, 0);
125 int offset
= CBOX_ARG_I(cmd
, 1);
126 int length
= CBOX_ARG_I(cmd
, 2);
129 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Invalid pattern position %d (cannot be negative)", pos
);
134 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Invalid pattern offset %d (cannot be negative)", offset
);
139 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Invalid pattern length %d (must be positive)", length
);
142 struct cbox_objhdr
*pattern
= CBOX_ARG_O(cmd
, 3, track
, cbox_midi_pattern
, error
);
145 struct cbox_midi_pattern
*mp
= CBOX_H2O(pattern
);
146 struct cbox_track_item
*trki
= cbox_track_add_item(track
, pos
, mp
, offset
, length
);
148 return cbox_execute_on(fb
, NULL
, "/uuid", "o", error
, trki
);
151 else if (!strcmp(cmd
->command
, "/name") && !strcmp(cmd
->arg_types
, "s"))
153 char *old_name
= track
->name
;
154 track
->name
= g_strdup(CBOX_ARG_S(cmd
, 0));
159 return cbox_object_default_process_cmd(ct
, fb
, cmd
, error
);
162 gboolean
cbox_track_item_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
164 struct cbox_track_item
*trki
= ct
->user_data
;
165 if (!strcmp(cmd
->command
, "/status") && !strcmp(cmd
->arg_types
, ""))
167 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
170 return cbox_execute_on(fb
, NULL
, "/pos", "i", error
, trki
->time
) &&
171 cbox_execute_on(fb
, NULL
, "/offset", "i", error
, trki
->offset
) &&
172 cbox_execute_on(fb
, NULL
, "/length", "i", error
, trki
->length
) &&
173 cbox_execute_on(fb
, NULL
, "/pattern", "o", error
, trki
->pattern
) &&
174 CBOX_OBJECT_DEFAULT_STATUS(trki
, fb
, error
);
176 if (!strcmp(cmd
->command
, "/delete") && !strcmp(cmd
->arg_types
, ""))
178 cbox_object_destroy(CBOX_O2H(trki
));
181 return cbox_object_default_process_cmd(ct
, fb
, cmd
, error
);