int kqt_Handle_set_position(kqt_Handle handle, int track, long long nanoseconds) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (track < -1 || track >= KQT_TRACKS_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Invalid track number: %d", track); return 0; } if (nanoseconds < 0) { Handle_set_error(h, ERROR_ARGUMENT, "nanoseconds must be non-negative"); return 0; } int64_t skip_frames = (int64_t)(((double)nanoseconds / 1000000000L) * Player_get_audio_rate(h->player)); Device_states_reset(Player_get_device_states(h->player)); Player_reset(h->player, track); Player_skip(h->player, skip_frames); return 1; }
int kqt_Handle_set_audio_rate(kqt_Handle handle, long rate) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (rate <= 0) { Handle_set_error(h, ERROR_ARGUMENT, "Audio rate must be positive"); return 0; } #if LONG_MAX > INT32_MAX else if ((int64_t)rate > INT32_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Audio rate must be <= %" PRId32, INT32_MAX); return 0; } #endif if (!Player_set_audio_rate(h->player, (int32_t)rate)) { Handle_set_error( h, ERROR_MEMORY, "Couldn't allocate memory after change of audio rate."); return 0; } return 1; }
int kqt_Handle_set_thread_count(kqt_Handle handle, int count) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (count < 1) { Handle_set_error(h, ERROR_ARGUMENT, "Thread count must be positive"); return 0; } if (count > KQT_THREADS_MAX) { Handle_set_error( h, ERROR_ARGUMENT, "Thread count must not exceed %d", KQT_THREADS_MAX); return 0; } Error* error = ERROR_AUTO; if (!Player_set_thread_count(h->player, count, error)) { Handle_set_error_from_Error(h, error); return 0; } return 1; }
int kqt_Handle_set_audio_buffer_size(kqt_Handle handle, long size) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (size <= 0) { Handle_set_error(h, ERROR_ARGUMENT, "Buffer size must be positive"); return 0; } if (size > KQT_AUDIO_BUFFER_SIZE_MAX) { Handle_set_error( h, ERROR_ARGUMENT, "Buffer size must not be greater than %ld frames", KQT_AUDIO_BUFFER_SIZE_MAX); return 0; } if (!Player_set_audio_buffer_size(h->player, (int32_t)size)) { Handle_set_error(h, ERROR_MEMORY, "Couldn't allocate memory for new buffers"); return 0; } return 1; }
kqt_Handle kqt_new_Handle(void) { Handle* handle = memory_alloc_item(Handle); if (handle == NULL) { Handle_set_error(0, ERROR_MEMORY, "Couldn't allocate memory"); return 0; } if (!Handle_init(handle)) { memory_free(handle); return 0; } kqt_Handle id = add_handle(handle); if (id == 0) { Handle_deinit(handle); memory_free(handle); return 0; } return id; }
bool Handle_init(Handle* handle) { assert(handle != NULL); handle->data_is_valid = true; handle->data_is_validated = true; handle->module = NULL; handle->error = *ERROR_AUTO; handle->validation_error = *ERROR_AUTO; memset(handle->position, '\0', POSITION_LENGTH); handle->player = NULL; handle->length_counter = NULL; // int buffer_count = SONG_DEFAULT_BUF_COUNT; // int voice_count = 256; handle->module = new_Module(); if (handle->module == NULL) { Handle_set_error(NULL, ERROR_MEMORY, "Couldn't allocate memory"); Handle_deinit(handle); return false; } // Create players handle->player = new_Player( handle->module, DEFAULT_AUDIO_RATE, 2048, 16384, 256); handle->length_counter = new_Player(handle->module, 1000000000L, 0, 0, 0); if (handle->player == NULL || handle->length_counter == NULL) { Handle_set_error(NULL, ERROR_MEMORY, "Couldn't allocate memory"); Handle_deinit(handle); return false; } Handle_stop(handle); //kqt_Handle_set_position(handle, 0, 0); return true; }
int kqt_Handle_set_data( kqt_Handle handle, const char* key, const void* data, long length) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_key(h, key, 0); // Short-circuit if we have already got invalid data // TODO: Remove this if we decide to collect more error info if (Error_is_set(&h->validation_error)) return 1; if (length < 0) { Handle_set_error( h, ERROR_ARGUMENT, "Data length must be non-negative"); return 0; } if (data == NULL && length > 0) { Handle_set_error( h, ERROR_ARGUMENT, "Data must not be null if given length (%ld) is positive", length); return 0; } if (!parse_data(h, key, data, length)) return 0; h->data_is_validated = false; return 1; }
int kqt_Handle_fire_event(kqt_Handle handle, int channel, const char* event) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (channel < 0 || channel >= KQT_COLUMNS_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Invalid channel number: %d", channel); return 0; } if (event == NULL) { Handle_set_error(h, ERROR_ARGUMENT, "No event description given"); return 0; } const size_t length = strlen(event); if (length > 4096) { Handle_set_error(h, ERROR_ARGUMENT, "Event description is too long"); return 0; } Streader* sr = Streader_init(STREADER_AUTO, event, (int64_t)length); if (!Player_fire(h->player, channel, sr)) { rassert(Streader_is_error_set(sr)); Handle_set_error( h, ERROR_ARGUMENT, "Invalid event description `%s`: %s", event, Streader_get_error_desc(sr)); return 0; } return 1; }
static kqt_Handle add_handle(Handle* handle) { rassert(handle != NULL); #ifndef NDEBUG for (int i = 0; i < KQT_HANDLES_MAX; ++i) rassert(handles[i] != handle); #endif static int next_try = 0; for (int i = 0; i < KQT_HANDLES_MAX; ++i) { const int try = (i + next_try) % KQT_HANDLES_MAX; if (handles[try] == NULL) { handles[try] = handle; next_try = try + 1; return try + 1; // shift kqt_Handle range to [1, KQT_HANDLES_MAX] } } Handle_set_error(NULL, ERROR_MEMORY, "Maximum number of Kunquat Handles reached"); return 0; } Handle* get_handle(kqt_Handle id) { rassert(kqt_Handle_is_valid(id)); Handle* handle = handles[id - 1]; rassert(handle != NULL); return handle; } static bool remove_handle(kqt_Handle id) { rassert(kqt_Handle_is_valid(id)); const bool was_null = (handles[id - 1] == NULL); handles[id - 1] = NULL; return !was_null; }
const float* kqt_Handle_get_audio(kqt_Handle handle, int index) { check_handle(handle, NULL); Handle* h = get_handle(handle); check_data_is_valid(h, NULL); check_data_is_validated(h, NULL); if (index < 0 || index >= KQT_BUFFERS_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Buffer #%d does not exist", index); return NULL; } return Player_get_audio(h->player, index); }
void kqt_del_Handle(kqt_Handle handle) { check_handle_void(handle); Handle* h = get_handle(handle); if (!remove_handle(handle)) { Handle_set_error(NULL, ERROR_ARGUMENT, "Invalid Kunquat Handle: %d", handle); return; } Handle_deinit(h); memory_free(h); return; }
int kqt_Handle_play(kqt_Handle handle, long nframes) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (nframes <= 0) { Handle_set_error(h, ERROR_ARGUMENT, "Number of frames must be positive."); return 0; } Player_play(h->player, (int32_t)min(nframes, KQT_AUDIO_BUFFER_SIZE_MAX)); return 1; }
long long kqt_Handle_get_duration(kqt_Handle handle, int track) { check_handle(handle, -1); Handle* h = get_handle(handle); check_data_is_valid(h, -1); check_data_is_validated(h, -1); if (track < -1 || track >= KQT_TRACKS_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Invalid track number: %d", track); return -1; } Player_reset(h->length_counter, track); Player_skip(h->length_counter, KQT_CALC_DURATION_MAX); return Player_get_nanoseconds(h->length_counter); }
static bool Handle_update_connections(Handle* handle) { rassert(handle != NULL); Module* module = Handle_get_module(handle); const Connections* conns = Module_get_connections(module); if (conns == NULL) return true; Device_states* dstates = Player_get_device_states(handle->player); if (!Device_states_prepare(dstates, conns)) { Handle_set_error(handle, ERROR_MEMORY, "Couldn't allocate memory for connections"); return false; } return true; }
bool key_is_valid(Handle* handle, const char* key) { rassert(handle != NULL); if (key == NULL) { Handle_set_error(handle, ERROR_ARGUMENT, "No key given"); return false; } if (strlen(key) > KQT_KEY_LENGTH_MAX) { char key_repr[KQT_KEY_LENGTH_MAX + 3] = { '\0' }; strncpy(key_repr, key, KQT_KEY_LENGTH_MAX - 1); strcat(key_repr, "..."); Handle_set_error(handle, ERROR_ARGUMENT, "Key %s is too long" " (over %d characters)", key_repr, KQT_KEY_LENGTH_MAX); return false; } bool valid_element = false; bool element_has_period = false; const char* key_iter = key; while (*key_iter != '\0') { if (!(*key_iter >= '0' && *key_iter <= '9') && strchr("abcdefghijklmnopqrstuvwxyz_./X", *key_iter) == NULL) { Handle_set_error(handle, ERROR_ARGUMENT, "Key %s contains an" " illegal character \'%c\'", key, *key_iter); return false; } if (*key_iter != '.' && *key_iter != '/') { valid_element = true; } else if (*key_iter == '.') { element_has_period = true; } else if (*key_iter == '/') { if (!valid_element) { Handle_set_error(handle, ERROR_ARGUMENT, "Key %s contains" " an invalid component", key); return false; } else if (element_has_period) { Handle_set_error(handle, ERROR_ARGUMENT, "Key %s contains" " an intermediate component with a period", key); return false; } valid_element = false; element_has_period = false; } ++key_iter; } if (!element_has_period) { Handle_set_error(handle, ERROR_ARGUMENT, "The final element of" " key %s does not have a period", key); return false; } return true; }