diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 9183bf1..a857694 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -87,8 +87,8 @@ struct PACKED USBNew3DSOptimizeHeaderSoundData { uint16_t magic; uint16_t unk_fixed_1 : 1; uint16_t buffer_num : 1; - uint16_t unk : 5; - uint16_t column_index : 9; + uint16_t unk : 4; + uint16_t column_index : 10; USBNew3DSOptimizeSingleSoundData samples[2]; }; diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp index 2a5eb89..d143cb4 100644 --- a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp @@ -575,6 +575,7 @@ void cyni_device_acquisition_main_loop(CaptureData* capture_data) { cypress_device_capture_recv_data[i].status = &status; cypress_device_capture_recv_data[i].cb_data.actual_user_data = &cypress_device_capture_recv_data[i]; cypress_device_capture_recv_data[i].cb_data.transfer_data = NULL; + cypress_device_capture_recv_data[i].cb_data.is_data_ready = false; cypress_device_capture_recv_data[i].cb_data.is_transfer_done_mutex = &is_transfer_done_shared_mutex; cypress_device_capture_recv_data[i].cb_data.internal_index = i; cypress_device_capture_recv_data[i].cb_data.is_transfer_data_ready_mutex = &is_transfer_data_ready_shared_mutex; diff --git a/source/CaptureDeviceSpecific/Optimize_New_3DS/cypress_optimize_new_3ds_acquisition.cpp b/source/CaptureDeviceSpecific/Optimize_New_3DS/cypress_optimize_new_3ds_acquisition.cpp index 99929ab..ab372f3 100644 --- a/source/CaptureDeviceSpecific/Optimize_New_3DS/cypress_optimize_new_3ds_acquisition.cpp +++ b/source/CaptureDeviceSpecific/Optimize_New_3DS/cypress_optimize_new_3ds_acquisition.cpp @@ -18,27 +18,35 @@ // Such an action is allowed under EU law. // No reverse engineering of the original software was done to create this. -#define SINGLE_RING_BUFFER_SLICE_SIZE 0x10000 -#define NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS 64 +#define SYNCH_VALUE_OPTIMIZE 0xCC33 -#define NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS 4 +#define SINGLE_RING_BUFFER_SLICE_SIZE 0x10000 +#define NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS 16 + +#define NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS (3 * NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS) #define MAX_TIME_WAIT 1.0 #define OPTIMIZE_NEW_3DS_CYPRESS_USB_WINDOWS_DRIVER CYPRESS_WINDOWS_OPTIMIZE_NEW_USB_DRIVER struct CypressOptimizeNew3DSDeviceCaptureReceivedData { + CypressOptimizeNew3DSDeviceCaptureReceivedData* array_ptr; volatile bool in_use; + volatile bool to_process; uint32_t index; SharedConsumerMutex* is_buffer_free_shared_mutex; int* status; uint32_t* last_index; - uint8_t* buffer_slice; - int buffer_slice_index; - int* last_used_buffer_slice_index; - size_t* last_used_buffer_slice_pos; - bool* is_buffer_slice_in_use; - bool* is_buffer_slice_ready; + uint8_t *ring_slice_buffer_arr; + bool* is_ring_buffer_slice_data_in_use_arr; + bool* is_ring_buffer_slice_data_ready_arr; + int ring_buffer_slice_index; + int* last_ring_buffer_slice_allocated; + int* last_used_ring_buffer_slice_index; + size_t* last_used_ring_buffer_slice_pos; + int* buffer_ring_slice_to_array_ptr; + InputVideoDataType* stored_video_data_type; + bool* stored_is_3d; CaptureData* capture_data; std::chrono::time_point* clock_start; cy_async_callback_data cb_data; @@ -98,7 +106,7 @@ std::string cypress_optimize_new_3ds_get_serial(const void* usb_device_desc, std } static CaptureDevice _cypress_optimize_new_3ds_create_device(const cyopn_device_usb_device* usb_device_desc, std::string serial, std::string path) { - return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_CYPRESS_NEW_OPTIMIZE, (void*)usb_device_desc, true, true, true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, HEIGHT_3DS, (TOP_WIDTH_3DS * 2) + BOT_WIDTH_3DS, OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE, 90, BOT_WIDTH_3DS, 0, BOT_WIDTH_3DS + TOP_WIDTH_3DS, 0, 0, 0, false, VIDEO_DATA_RGB16, 0x200, path); + return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_CYPRESS_NEW_OPTIMIZE, (void*)usb_device_desc, true, true, true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, HEIGHT_3DS, (TOP_WIDTH_3DS * 2) + BOT_WIDTH_3DS, OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE * 8, 90, BOT_WIDTH_3DS, 0, BOT_WIDTH_3DS + TOP_WIDTH_3DS, 0, 0, 0, false, VIDEO_DATA_RGB16, 0x200, path); } CaptureDevice cypress_optimize_new_3ds_create_device(const void* usb_device_desc, std::string serial, std::string path) { @@ -206,38 +214,164 @@ uint64_t cyopn_device_get_video_in_size(CaptureData* capture_data, bool is_3d, I static int cypress_device_read_frame_request(CaptureData* capture_data, CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, uint32_t index, bool is_3d, InputVideoDataType video_data_type) { if(cypress_device_capture_recv_data == NULL) return LIBUSB_SUCCESS; - if((*cypress_device_capture_recv_data->status) < 0) { - cypress_device_capture_recv_data->in_use = false; + if((*cypress_device_capture_recv_data->status) < 0) return LIBUSB_SUCCESS; - } const cyopn_device_usb_device* usb_device_info = (const cyopn_device_usb_device*)capture_data->status.device.descriptor; cypress_device_capture_recv_data->index = index; cypress_device_capture_recv_data->cb_data.function = cypress_device_read_frame_cb; - size_t read_size = cyopn_device_get_video_in_size(is_3d, video_data_type); - CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(cypress_device_capture_recv_data->cb_data.internal_index); - uint8_t* buffer = (uint8_t*)&data_buf->capture_buf; + //size_t read_size = cyopn_device_get_video_in_size(is_3d, video_data_type); + size_t read_size = SINGLE_RING_BUFFER_SLICE_SIZE; + int new_buffer_slice_index = ((*cypress_device_capture_recv_data->last_ring_buffer_slice_allocated) + 1) % NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; + uint8_t* buffer = &cypress_device_capture_recv_data->ring_slice_buffer_arr[new_buffer_slice_index * SINGLE_RING_BUFFER_SLICE_SIZE]; + cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[new_buffer_slice_index] = false; + cypress_device_capture_recv_data->is_ring_buffer_slice_data_in_use_arr[new_buffer_slice_index] = true; + cypress_device_capture_recv_data->buffer_ring_slice_to_array_ptr[new_buffer_slice_index] = cypress_device_capture_recv_data->cb_data.internal_index; + cypress_device_capture_recv_data->ring_buffer_slice_index = new_buffer_slice_index; + *cypress_device_capture_recv_data->last_ring_buffer_slice_allocated = new_buffer_slice_index; + cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_try_lock(cypress_device_capture_recv_data->cb_data.internal_index); + cypress_device_capture_recv_data->in_use = true; + cypress_device_capture_recv_data->to_process = true; return ReadFrameAsync((cy_device_device_handlers*)capture_data->handle, buffer, read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data); } -static void end_cypress_device_read_frame_cb(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool early_release) { - if(early_release) - cypress_device_capture_recv_data->capture_data->data_buffers.ReleaseWriterBuffer(cypress_device_capture_recv_data->cb_data.internal_index, false); - cypress_device_capture_recv_data->in_use = false; - cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data->cb_data.internal_index); +static void unlock_buffer_directly(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data_real) { + int slice_index = cypress_device_capture_recv_data_real->ring_buffer_slice_index; + cypress_device_capture_recv_data_real->is_ring_buffer_slice_data_ready_arr[slice_index] = false; + cypress_device_capture_recv_data_real->is_ring_buffer_slice_data_in_use_arr[slice_index] = false; + cypress_device_capture_recv_data_real->buffer_ring_slice_to_array_ptr[slice_index] = -1; + cypress_device_capture_recv_data_real->in_use = false; + cypress_device_capture_recv_data_real->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data_real->cb_data.internal_index); +} + +static void unlock_buffer_slice_index(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int slice_index) { + int index = cypress_device_capture_recv_data->buffer_ring_slice_to_array_ptr[slice_index]; + if(index == -1) + return; + unlock_buffer_directly(&cypress_device_capture_recv_data->array_ptr[index]); +} + +static void end_cypress_device_read_frame_cb(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool to_unlock) { + cypress_device_capture_recv_data->to_process = false; + if(to_unlock) + unlock_buffer_directly(cypress_device_capture_recv_data); +} + +static size_t get_pos_first_synch_in_buffer(uint8_t* buffer) { + for(int i = 0; i < (SINGLE_RING_BUFFER_SLICE_SIZE / 2); i++) { + if(read_le16(buffer, i) == SYNCH_VALUE_OPTIMIZE) { + if((read_le16(buffer, i + 1) & 0x3FF) == 0) + return i * 2; + } + } + return SINGLE_RING_BUFFER_SLICE_SIZE + 1; +} + +static int get_num_consecutive_ready_ring_buffer_slices(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int start_index) { + for(int i = 0; i < NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; i++) { + int index_check = (start_index + i) % NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; + if(!cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[index_check]) + return i; + } + // Should never happen + return NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; +} + +static void cypress_output_to_thread(CaptureData* capture_data, uint8_t *buffer_arr, size_t start_slice_index, size_t start_slice_pos, int internal_index, std::chrono::time_point* clock_start, size_t read_size) { + // Output to the other threads... + CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(internal_index); + size_t start_byte = (start_slice_index * SINGLE_RING_BUFFER_SLICE_SIZE) + start_slice_pos; + if((start_byte + read_size) <= (NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE)) + memcpy(&data_buf->capture_buf, buffer_arr + start_byte, read_size); + else { + size_t upper_read_size = (NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE) - start_byte; + size_t start_read_size = read_size - upper_read_size; + memcpy(&data_buf->capture_buf, buffer_arr + start_byte, upper_read_size); + memcpy(((uint8_t*)&data_buf->capture_buf) + upper_read_size, buffer_arr, start_read_size); + } + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - (*clock_start); + *clock_start = curr_time; + capture_data->data_buffers.WriteToBuffer(NULL, read_size, diff.count(), &capture_data->status.device, internal_index); + if (capture_data->status.cooldown_curr_in) + capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1; + capture_data->status.video_wait.unlock(); + capture_data->status.audio_wait.unlock(); } static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) { CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data = (CypressOptimizeNew3DSDeviceCaptureReceivedData*)user_data; if((*cypress_device_capture_recv_data->status) < 0) return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true); - if(transfer_status != LIBUSB_TRANSFER_COMPLETED) { + if((transfer_status != LIBUSB_TRANSFER_COMPLETED) || (transfer_length < SINGLE_RING_BUFFER_SLICE_SIZE)) { int error = LIBUSB_ERROR_OTHER; if(transfer_status == LIBUSB_TRANSFER_TIMED_OUT) error = LIBUSB_ERROR_TIMEOUT; *cypress_device_capture_recv_data->status = error; return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true); } - return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true); + cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[cypress_device_capture_recv_data->ring_buffer_slice_index] = true; + // First case + bool to_free = false; + volatile int read_slice_index = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index; + if(read_slice_index == -1) { + size_t first_to_check = 0; + for(int i = 0; i < NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; i++) { + if(!cypress_device_capture_recv_data->is_ring_buffer_slice_data_in_use_arr[i]) + first_to_check++; + else + break; + } + if(first_to_check > NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS) { + int error = LIBUSB_ERROR_OTHER; + *cypress_device_capture_recv_data->status = error; + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, true); + } + for(int i = 0; i < NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; i++) { + size_t check_index = (first_to_check + i) % NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; + if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[check_index]) { + size_t result = get_pos_first_synch_in_buffer(&cypress_device_capture_recv_data->ring_slice_buffer_arr[check_index * SINGLE_RING_BUFFER_SLICE_SIZE]); + if(result >= SINGLE_RING_BUFFER_SLICE_SIZE) { + unlock_buffer_slice_index(cypress_device_capture_recv_data, check_index); + } + else { + *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index = check_index; + *cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = result; + break; + } + } + else + break; + } + } + // Generic case + read_slice_index = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index; + volatile size_t read_slice_pos = *cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos; + if(read_slice_index != -1) { + int num_consecutive_ready_buffers = get_num_consecutive_ready_ring_buffer_slices(cypress_device_capture_recv_data, read_slice_index); + size_t video_in_size = cyopn_device_get_video_in_size(*cypress_device_capture_recv_data->stored_is_3d, *cypress_device_capture_recv_data->stored_video_data_type); + size_t raw_new_pos = read_slice_pos + video_in_size; + int num_needed_buffers = (raw_new_pos + SINGLE_RING_BUFFER_SLICE_SIZE - 1) / SINGLE_RING_BUFFER_SLICE_SIZE; + if(num_consecutive_ready_buffers >= num_needed_buffers) { + // Enough data. Time to do output... + cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, cypress_device_capture_recv_data->ring_slice_buffer_arr, read_slice_index, read_slice_pos, 0, cypress_device_capture_recv_data->clock_start, video_in_size); + // Keep the ring buffer going. + int new_slice_index = read_slice_index + num_needed_buffers - 1; + size_t new_slice_pos = raw_new_pos % SINGLE_RING_BUFFER_SLICE_SIZE; + if(new_slice_pos == 0) + new_slice_index += 1; + new_slice_index %= NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; + // Unlock the buffers already processed + int pos_to_unlock = read_slice_index; + while(pos_to_unlock != new_slice_index) { + unlock_buffer_slice_index(cypress_device_capture_recv_data, pos_to_unlock); + pos_to_unlock = (pos_to_unlock + 1) % NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; + } + // Update the position of the data + *cypress_device_capture_recv_data->last_used_ring_buffer_slice_index = new_slice_index; + *cypress_device_capture_recv_data->last_used_ring_buffer_slice_pos = new_slice_pos; + } + } + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data, to_free); } static int cypress_device_get_num_free_buffers(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) { @@ -277,6 +411,13 @@ static void error_too_much_time_passed(CaptureData* capture_data, CypressOptimiz } } +static void check_unlock_waiting_with_error(CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) { + if(cypress_device_capture_recv_data->is_ring_buffer_slice_data_ready_arr[cypress_device_capture_recv_data->ring_buffer_slice_index]) + unlock_buffer_directly(cypress_device_capture_recv_data); + } +} + static void wait_all_cypress_device_buffers_free(CaptureData* capture_data, CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) { if(cypress_device_capture_recv_data == NULL) return; @@ -287,6 +428,7 @@ static void wait_all_cypress_device_buffers_free(CaptureData* capture_data, Cypr for(int i = 0; i < NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) while(cypress_device_capture_recv_data[i].in_use) { error_too_much_time_passed(capture_data, cypress_device_capture_recv_data, async_read_closed, start_time); + check_unlock_waiting_with_error(&cypress_device_capture_recv_data[i]); cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i); } } @@ -339,8 +481,6 @@ static CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_get_free_b return NULL; for(int i = 0; i < NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) if(!cypress_device_capture_recv_data[i].in_use) { - cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i); - cypress_device_capture_recv_data[i].in_use = true; return &cypress_device_capture_recv_data[i]; } return NULL; @@ -365,11 +505,9 @@ static void reset_cypress_device_status(CypressOptimizeNew3DSDeviceCaptureReceiv error_cypress_device_status(cypress_device_capture_recv_data, 0); } -static bool cyopn_device_acquisition_loop(CaptureData* capture_data, CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data) { +static bool cyopn_device_acquisition_loop(CaptureData* capture_data, CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, InputVideoDataType &stored_video_data_type, bool &stored_is_3d) { cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle; const cyopn_device_usb_device* usb_device_desc = (const cyopn_device_usb_device*)capture_data->status.device.descriptor; - InputVideoDataType stored_video_data_type = capture_data->status.device.video_data_type; - bool stored_is_3d = false; uint32_t index = 0; int ret = capture_start(handlers, usb_device_desc, true, stored_video_data_type == VIDEO_DATA_RGB); if (ret < 0) { @@ -383,6 +521,7 @@ static bool cyopn_device_acquisition_loop(CaptureData* capture_data, CypressOpti ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++, stored_is_3d, stored_video_data_type); if(ret < 0) { chosen_buffer->in_use = false; + cypress_device_capture_recv_data->to_process = false; error_cypress_device_status(cypress_device_capture_recv_data, ret); capture_error_print(true, capture_data, "Initial Reads: Failed"); return false; @@ -403,6 +542,7 @@ static bool cyopn_device_acquisition_loop(CaptureData* capture_data, CypressOpti ret = cypress_device_read_frame_request(capture_data, chosen_buffer, index++, stored_is_3d, stored_video_data_type); if(ret < 0) { chosen_buffer->in_use = false; + cypress_device_capture_recv_data->to_process = false; error_cypress_device_status(cypress_device_capture_recv_data, ret); capture_error_print(true, capture_data, "Setup Read: Failed"); return false; @@ -421,6 +561,22 @@ void cyopn_device_acquisition_main_loop(CaptureData* capture_data) { uint32_t last_index = -1; int status = 0; + InputVideoDataType stored_video_data_type = capture_data->status.device.video_data_type; + bool stored_is_3d = false; + + uint8_t *ring_slice_buffer = new uint8_t[NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS * SINGLE_RING_BUFFER_SLICE_SIZE]; + bool *is_ring_buffer_slice_data_ready = new bool[NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS]; + bool *is_ring_buffer_slice_data_in_use = new bool[NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS]; + int *buffer_ring_slice_to_array = new int[NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS]; + for(int i = 0; i < NUM_TOTAL_OPTIMIZE_NEW_3DS_CYPRESS_BUFFERS; i++) { + is_ring_buffer_slice_data_ready[i] = false; + is_ring_buffer_slice_data_in_use[i] = false; + buffer_ring_slice_to_array[i] = -1; + } + int last_used_ring_buffer_slice_index = -1; + size_t last_used_ring_buffer_slice_pos = 0; + int last_ring_buffer_slice_allocated = -1; + std::vector cb_queue; SharedConsumerMutex is_buffer_free_shared_mutex(NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS); SharedConsumerMutex is_transfer_done_shared_mutex(NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS); @@ -428,8 +584,19 @@ void cyopn_device_acquisition_main_loop(CaptureData* capture_data) { std::chrono::time_point clock_start = std::chrono::high_resolution_clock::now(); CypressOptimizeNew3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data = new CypressOptimizeNew3DSDeviceCaptureReceivedData[NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS]; for(int i = 0; i < NUM_OPTIMIZE_NEW_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; i++) { + cypress_device_capture_recv_data[i].array_ptr = cypress_device_capture_recv_data; cypress_device_capture_recv_data[i].in_use = false; + cypress_device_capture_recv_data[i].to_process = false; cypress_device_capture_recv_data[i].index = i; + cypress_device_capture_recv_data[i].stored_video_data_type = &stored_video_data_type; + cypress_device_capture_recv_data[i].stored_is_3d = &stored_is_3d; + cypress_device_capture_recv_data[i].ring_slice_buffer_arr = ring_slice_buffer; + cypress_device_capture_recv_data[i].is_ring_buffer_slice_data_in_use_arr = is_ring_buffer_slice_data_in_use; + cypress_device_capture_recv_data[i].is_ring_buffer_slice_data_ready_arr = is_ring_buffer_slice_data_ready; + cypress_device_capture_recv_data[i].last_ring_buffer_slice_allocated = &last_ring_buffer_slice_allocated; + cypress_device_capture_recv_data[i].last_used_ring_buffer_slice_index = &last_used_ring_buffer_slice_index; + cypress_device_capture_recv_data[i].last_used_ring_buffer_slice_pos = &last_used_ring_buffer_slice_pos; + cypress_device_capture_recv_data[i].buffer_ring_slice_to_array_ptr = buffer_ring_slice_to_array; cypress_device_capture_recv_data[i].capture_data = capture_data; cypress_device_capture_recv_data[i].last_index = &last_index; cypress_device_capture_recv_data[i].clock_start = &clock_start; @@ -439,16 +606,21 @@ void cyopn_device_acquisition_main_loop(CaptureData* capture_data) { cypress_device_capture_recv_data[i].cb_data.transfer_data = NULL; cypress_device_capture_recv_data[i].cb_data.is_transfer_done_mutex = &is_transfer_done_shared_mutex; cypress_device_capture_recv_data[i].cb_data.internal_index = i; + cypress_device_capture_recv_data[i].cb_data.is_data_ready = false; cypress_device_capture_recv_data[i].cb_data.is_transfer_data_ready_mutex = &is_transfer_data_ready_shared_mutex; - cypress_device_capture_recv_data[i].cb_data.in_use_ptr = &cypress_device_capture_recv_data[i].in_use; + cypress_device_capture_recv_data[i].cb_data.in_use_ptr = &cypress_device_capture_recv_data[i].to_process; cypress_device_capture_recv_data[i].cb_data.error_function = exported_error_cypress_device_status; cb_queue.push_back(&cypress_device_capture_recv_data[i].cb_data); } CypressSetupCypressDeviceAsyncThread(handlers, cb_queue, &async_processing_thread, &is_done_thread); - bool proper_return = cyopn_device_acquisition_loop(capture_data, cypress_device_capture_recv_data); + bool proper_return = cyopn_device_acquisition_loop(capture_data, cypress_device_capture_recv_data, stored_video_data_type, stored_is_3d); wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); CypressEndCypressDeviceAsyncThread(handlers, cb_queue, &async_processing_thread, &is_done_thread); delete []cypress_device_capture_recv_data; + delete []ring_slice_buffer; + delete []is_ring_buffer_slice_data_ready; + delete []is_ring_buffer_slice_data_in_use; + delete []buffer_ring_slice_to_array; if(proper_return) capture_end(handlers, usb_device_desc); diff --git a/source/conversions.cpp b/source/conversions.cpp index 9e403ab..aff23ad 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -868,58 +868,50 @@ static inline uint16_t read_sample_indexBE(USBNew3DSOptimizeSingleSoundData* sam return _reverse_endianness(sample->sample_index) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE; } -static inline void copyAudioFromSoundDataNewOptimize3DSLE(std::int16_t *p_out, uint16_t start, USBNew3DSOptimizeSingleSoundData* sample) { - int32_t position = (read_sample_indexLE(sample) + OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE - start) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE; - p_out[position * 2] = sample->sample_l; - p_out[(position * 2) + 1] = sample->sample_r; +static inline void copyAudioFromSoundDataNewOptimize3DSLE(std::int16_t *p_out, USBNew3DSOptimizeSingleSoundData* sample, uint64_t& num_inserted, int& last_inserted_index) { + uint16_t read_index = read_sample_indexLE(sample) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE; + if(read_index == last_inserted_index) + return; + p_out[num_inserted * 2] = sample->sample_l; + p_out[(num_inserted * 2) + 1] = sample->sample_r; + num_inserted += 1; + last_inserted_index = read_index; } -static inline void copyAudioFromSoundDataNewOptimize3DSBE(std::int16_t *p_out, uint16_t start, USBNew3DSOptimizeSingleSoundData* sample) { - int32_t position = (read_sample_indexBE(sample) + OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE - start) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE; - p_out[position * 2] = _reverse_endianness(sample->sample_l); - p_out[(position * 2) + 1] = _reverse_endianness(sample->sample_r); +static inline void copyAudioFromSoundDataNewOptimize3DSBE(std::int16_t *p_out, USBNew3DSOptimizeSingleSoundData* sample, uint64_t& num_inserted, int& last_inserted_index) { + uint16_t read_index = read_sample_indexBE(sample) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE; + if(read_index == last_inserted_index) + return; + p_out[num_inserted * 2] = _reverse_endianness(sample->sample_l); + p_out[(num_inserted * 2) + 1] = _reverse_endianness(sample->sample_r); + num_inserted += 1; + last_inserted_index = read_index; } static void copyAudioNewOptimize3DSLE(std::int16_t *p_out, uint64_t &n_samples, uint16_t &last_buffer_index, CaptureReceived* buffer, bool is_rgb888, bool is_data_3d) { USBNew3DSOptimizeHeaderSoundData* first_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, 0); - uint16_t start = read_sample_indexLE(&first_column_data->samples[0]); - if(start == last_buffer_index) { - start = read_sample_indexLE(&first_column_data->samples[1]); - copyAudioFromSoundDataNewOptimize3DSLE(p_out, start, &first_column_data->samples[1]); - } - else { - copyAudioFromSoundDataNewOptimize3DSLE(p_out, start, &first_column_data->samples[0]); - copyAudioFromSoundDataNewOptimize3DSLE(p_out, start, &first_column_data->samples[1]); - } - for(int i = 1; i < TOP_WIDTH_3DS; i++) { + uint64_t num_inserted = 0; + int last_inserted_index = last_buffer_index; + for(int i = 0; i < TOP_WIDTH_3DS; i++) { USBNew3DSOptimizeHeaderSoundData* curr_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, i); - copyAudioFromSoundDataNewOptimize3DSLE(p_out, start, &curr_column_data->samples[0]); - copyAudioFromSoundDataNewOptimize3DSLE(p_out, start, &curr_column_data->samples[1]); + copyAudioFromSoundDataNewOptimize3DSLE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index); + copyAudioFromSoundDataNewOptimize3DSLE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index); } - USBNew3DSOptimizeHeaderSoundData* last_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, TOP_WIDTH_3DS - 1); - last_buffer_index = read_sample_indexLE(&last_column_data->samples[1]); - n_samples = ((last_buffer_index + 1 + OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE - start) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE) * 2; + last_buffer_index = last_inserted_index; + n_samples = num_inserted * 2; } static void copyAudioNewOptimize3DSBE(std::int16_t *p_out, uint64_t &n_samples, uint16_t &last_buffer_index, CaptureReceived* buffer, bool is_rgb888, bool is_data_3d) { USBNew3DSOptimizeHeaderSoundData* first_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, 0); - uint16_t start = read_sample_indexBE(&first_column_data->samples[0]); - if(start == last_buffer_index) { - start = read_sample_indexBE(&first_column_data->samples[1]); - copyAudioFromSoundDataNewOptimize3DSBE(p_out, start, &first_column_data->samples[1]); - } - else { - copyAudioFromSoundDataNewOptimize3DSBE(p_out, start, &first_column_data->samples[0]); - copyAudioFromSoundDataNewOptimize3DSBE(p_out, start, &first_column_data->samples[1]); - } - for(int i = 1; i < TOP_WIDTH_3DS; i++) { + uint64_t num_inserted = 0; + int last_inserted_index = last_buffer_index; + for(int i = 0; i < TOP_WIDTH_3DS; i++) { USBNew3DSOptimizeHeaderSoundData* curr_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, i); - copyAudioFromSoundDataNewOptimize3DSBE(p_out, start, &curr_column_data->samples[0]); - copyAudioFromSoundDataNewOptimize3DSBE(p_out, start, &curr_column_data->samples[1]); + copyAudioFromSoundDataNewOptimize3DSBE(p_out, &curr_column_data->samples[0], num_inserted, last_inserted_index); + copyAudioFromSoundDataNewOptimize3DSBE(p_out, &curr_column_data->samples[1], num_inserted, last_inserted_index); } - USBNew3DSOptimizeHeaderSoundData* last_column_data = getAudioHeaderPtrNewOptimize3DS(buffer, is_rgb888, is_data_3d, TOP_WIDTH_3DS - 1); - last_buffer_index = read_sample_indexBE(&last_column_data->samples[1]); - n_samples = ((last_buffer_index + 1 + OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE - start) % OPTIMIZE_NEW_3DS_AUDIO_BUFFER_MAX_SIZE) * 2; + last_buffer_index = last_inserted_index; + n_samples = num_inserted * 2; } bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, uint16_t &last_buffer_index, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) {