diff --git a/Controllers/CreativeController/CreativeControllerDetect.cpp b/Controllers/CreativeController/CreativeControllerDetect.cpp index 5f508e16..3ba06e9e 100644 --- a/Controllers/CreativeController/CreativeControllerDetect.cpp +++ b/Controllers/CreativeController/CreativeControllerDetect.cpp @@ -8,12 +8,13 @@ \*---------------------------------------------------------*/ #include +#include "LogManager.h" #include "CreativeSoundBlasterXG6Controller.h" #include "RGBController_CreativeSoundBlasterXG6.h" #include "Detector.h" /*-----------------------------------------------------*\ -| Creative vendor ID | +| Creative vendor IDs | \*-----------------------------------------------------*/ #define CREATIVE_VID 0x041E /*-----------------------------------------------------*\ diff --git a/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerBase.h b/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerBase.h new file mode 100644 index 00000000..9d238b6d --- /dev/null +++ b/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerBase.h @@ -0,0 +1,28 @@ +/*---------------------------------------------------------*\ +| CreativeSoundBlasterAE5ControllerBase.h | +| | +| Base interface for Creative SoundBlaster AE-5 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include + +class CreativeSoundBlasterAE5ControllerBase +{ +public: + virtual ~CreativeSoundBlasterAE5ControllerBase() = default; + + virtual bool Initialize() = 0; + virtual std::string GetDeviceLocation() = 0; + virtual std::string GetDeviceName() = 0; + virtual unsigned int GetLEDCount() = 0; + virtual unsigned int GetExternalLEDCount() = 0; + virtual void SetExternalLEDCount(unsigned int count) = 0; + + virtual void SetLEDColors(unsigned char led_count, unsigned char* red_values, + unsigned char* green_values, unsigned char* blue_values) = 0; +}; \ No newline at end of file diff --git a/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerDetect_Windows.cpp b/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerDetect_Windows.cpp new file mode 100644 index 00000000..e6e11ef6 --- /dev/null +++ b/Controllers/CreativeController/CreativeSoundBlasterAE5ControllerDetect_Windows.cpp @@ -0,0 +1,34 @@ +/*---------------------------------------------------------*\ +| CreativeSoundBlasterAE5ControllerDetect_Windows.cpp | +| | +| Detector for Creative SoundBlaster AE-5 (Windows) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "Detector.h" +#include "CreativeSoundBlasterAE5Controller_Windows.h" +#include "RGBController_CreativeSoundBlasterAE5.h" +#include "LogManager.h" + +void DetectCreativeAE5Device() +{ + LOG_INFO("[Creative SoundBlaster AE-5] Windows detection function called"); + + CreativeSoundBlasterAE5Controller_Windows* controller = new CreativeSoundBlasterAE5Controller_Windows(); + + if(controller->Initialize()) + { + LOG_INFO("[Creative SoundBlaster AE-5] Device initialized successfully, registering controller"); + RGBController_CreativeSoundBlasterAE5* rgb_controller = new RGBController_CreativeSoundBlasterAE5(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + else + { + LOG_WARNING("[Creative SoundBlaster AE-5] Device initialization failed"); + delete controller; + } +} + +REGISTER_DETECTOR("Creative SoundBlaster AE-5", DetectCreativeAE5Device); \ No newline at end of file diff --git a/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.cpp b/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.cpp new file mode 100644 index 00000000..cb4f0bc5 --- /dev/null +++ b/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.cpp @@ -0,0 +1,425 @@ +/*---------------------------------------------------------*\ +| CreativeSoundBlasterAE5Controller_Windows.cpp | +| | +| Driver for Creative SoundBlaster AE-5 (Windows) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include +#include "CreativeSoundBlasterAE5Controller_Windows.h" +#include "LogManager.h" +#include + +/*---------------------------------------------------------*\ +| Lifecycle | +\*---------------------------------------------------------*/ + +CreativeSoundBlasterAE5Controller_Windows::CreativeSoundBlasterAE5Controller_Windows() +{ + name = "Creative SoundBlaster AE-5"; + location = ""; + device_found = false; + device_handle = INVALID_HANDLE_VALUE; + device_opened = false; + external_led_count = 0; + led_mutex = CreateMutexA(NULL, FALSE, "OpenRGB_AE5_LED_Mutex"); +} + +CreativeSoundBlasterAE5Controller_Windows::~CreativeSoundBlasterAE5Controller_Windows() +{ + CloseDevice(); + if(led_mutex != NULL) + { + CloseHandle(led_mutex); + led_mutex = NULL; + } +} + +bool CreativeSoundBlasterAE5Controller_Windows::Initialize() +{ + if(!FindDevice()) + { + return false; + } + + hdaudio_device_path = FindHDAudioDevicePath(); + if(hdaudio_device_path.empty()) + { + LOG_WARNING("[%s] Failed to find HDAudio device path", name.c_str()); + return false; + } + + return OpenDevice(); +} + +/*---------------------------------------------------------*\ +| Device Discovery | +\*---------------------------------------------------------*/ + +bool CreativeSoundBlasterAE5Controller_Windows::FindDevice() +{ + LOG_DEBUG("[%s] Looking for vendor 0x%04X, device 0x%04X", name.c_str(), AE5_VENDOR_ID, AE5_DEVICE_ID); + + HDEVINFO device_info_set = SetupDiGetClassDevs( + NULL, // No class GUID + TEXT("PCI"), // Enumerator + NULL, // No parent window + DIGCF_PRESENT | DIGCF_ALLCLASSES // Only present devices + ); + + if(device_info_set == INVALID_HANDLE_VALUE) + { + LOG_ERROR("[%s] SetupDiGetClassDevs failed: %lu", name.c_str(), GetLastError()); + return false; + } + + SP_DEVINFO_DATA device_info_data; + device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); + + for(DWORD device_index = 0; SetupDiEnumDeviceInfo(device_info_set, device_index, &device_info_data); device_index++) + { + TCHAR hardware_id[256]; + if(!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_HARDWAREID, + NULL, (PBYTE)hardware_id, sizeof(hardware_id), NULL)) + { + continue; + } + + std::string hw_id_str(hardware_id); + std::transform(hw_id_str.begin(), hw_id_str.end(), hw_id_str.begin(), ::toupper); + + if(hw_id_str.find("PCI\\VEN_1102&DEV_0012") != std::string::npos) + { + // Check subsystem ID to determine AE-5 variant + // Format is SUBSYS_{DEVICE_ID}{VENDOR_ID} + if(hw_id_str.find("SUBSYS_01911102") != std::string::npos) + { + name = "Creative SoundBlaster AE-5 Plus"; + } + else if(hw_id_str.find("SUBSYS_00511102") != std::string::npos) + { + name = "Creative SoundBlaster AE-5"; + } + else + { + name = "Creative SoundBlaster AE-5"; + LOG_WARNING("[%s] Unknown subsystem variant found in hardware ID: %s", name.c_str(), hardware_id); + LOG_WARNING("[%s] Please report this to @eclipse_sol84 in the OpenRGB Discord!", name.c_str()); + } + + LOG_INFO("[%s] Found matching device: %s", name.c_str(), hardware_id); + + TCHAR location_info[256]; + if(SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_LOCATION_INFORMATION, + NULL, (PBYTE)location_info, sizeof(location_info), NULL)) + { + location = "PCI: " + std::string(location_info); + } + else + { + location = "PCI: " + hw_id_str; + } + + device_found = true; + SetupDiDestroyDeviceInfoList(device_info_set); + + LOG_INFO("[%s] Device successfully detected at %s", name.c_str(), location.c_str()); + return true; + } + } + + SetupDiDestroyDeviceInfoList(device_info_set); + LOG_WARNING("[%s] No matching device found", name.c_str()); + return false; +} + +std::string CreativeSoundBlasterAE5Controller_Windows::FindHDAudioDevicePath() +{ + LOG_INFO("[%s] Searching for HDAudio device path...", name.c_str()); + + HKEY device_classes_key; + LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\DeviceClasses", + 0, KEY_READ, &device_classes_key); + + if(result != ERROR_SUCCESS) + { + LOG_ERROR("[%s] Failed to open DeviceClasses registry key: %lu", name.c_str(), result); + return ""; + } + + DWORD guid_index = 0; + CHAR guid_name[256]; + DWORD guid_name_size; + + // Enumerate all GUID folders in DeviceClasses + while(true) + { + guid_name_size = sizeof(guid_name); + result = RegEnumKeyExA(device_classes_key, guid_index, guid_name, &guid_name_size, + NULL, NULL, NULL, NULL); + + if(result != ERROR_SUCCESS) break; + + HKEY guid_key; + result = RegOpenKeyExA(device_classes_key, guid_name, 0, KEY_READ, &guid_key); + if(result != ERROR_SUCCESS) + { + guid_index++; + continue; + } + + // Enumerate device instances under this GUID + DWORD device_index = 0; + CHAR device_name[512]; + DWORD device_name_size; + + while(true) + { + device_name_size = sizeof(device_name); + result = RegEnumKeyExA(guid_key, device_index, device_name, &device_name_size, + NULL, NULL, NULL, NULL); + + if(result != ERROR_SUCCESS) break; + + std::string device_str(device_name); + std::transform(device_str.begin(), device_str.end(), device_str.begin(), ::toupper); + + if(device_str.find("VEN_1102&DEV_0011") != std::string::npos) + { + + // Check if this device has a #GPDHDA subkey + HKEY device_key; + result = RegOpenKeyExA(guid_key, device_name, 0, KEY_READ, &device_key); + if(result == ERROR_SUCCESS) + { + HKEY gpdhda_key; + result = RegOpenKeyExA(device_key, "#GPDHDA", 0, KEY_READ, &gpdhda_key); + if(result == ERROR_SUCCESS) + { + LOG_INFO("[%s] Found HDAudio device interface", name.c_str()); + RegCloseKey(gpdhda_key); + RegCloseKey(device_key); + + // Convert registry path format to device path format + std::string device_path(device_name); + std::transform(device_path.begin(), device_path.end(), device_path.begin(), ::tolower); + + if(device_path.substr(0, 4) == "##?#") + { + device_path = "\\\\?\\" + device_path.substr(4); + } + + device_path += "\\gpdhda"; + + RegCloseKey(guid_key); + RegCloseKey(device_classes_key); + return device_path; + } + RegCloseKey(device_key); + } + } + + device_index++; + } + + RegCloseKey(guid_key); + guid_index++; + } + + RegCloseKey(device_classes_key); + LOG_WARNING("[%s] No Creative HDAudio device found in registry", name.c_str()); + return ""; +} + +bool CreativeSoundBlasterAE5Controller_Windows::OpenDevice() +{ + if(hdaudio_device_path.empty()) + { + LOG_ERROR("[%s] No HDAudio device path available", name.c_str()); + return false; + } + + LOG_INFO("[%s] Opening device: %s", name.c_str(), hdaudio_device_path.c_str()); + + std::wstring wide_path(hdaudio_device_path.begin(), hdaudio_device_path.end()); + + device_handle = CreateFileW( + wide_path.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if(device_handle == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + LOG_ERROR("[%s] Failed to open device: Error %lu", name.c_str(), error); + + if(error == ERROR_PATH_NOT_FOUND) // Error 3 + { + LOG_ERROR("[%s] This device requires Creative's official drivers to be installed for RGB control", name.c_str()); + LOG_ERROR("[%s] Please install Creative Sound Blaster Command software or drivers from Creative's website", name.c_str()); + } + + return false; + } + + LOG_INFO("[%s] Device opened successfully", name.c_str()); + device_opened = true; + return true; +} + +void CreativeSoundBlasterAE5Controller_Windows::CloseDevice() +{ + if(device_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(device_handle); + device_handle = INVALID_HANDLE_VALUE; + device_opened = false; + LOG_INFO("[%s] Device closed", name.c_str()); + } +} + +/*---------------------------------------------------------*\ +| Getters | +\*---------------------------------------------------------*/ + +std::string CreativeSoundBlasterAE5Controller_Windows::GetDeviceLocation() +{ + return location; +} + +std::string CreativeSoundBlasterAE5Controller_Windows::GetDeviceName() +{ + return name; +} + +unsigned int CreativeSoundBlasterAE5Controller_Windows::GetLEDCount() +{ + return AE5_INTERNAL_LED_COUNT + external_led_count; +} + +unsigned int CreativeSoundBlasterAE5Controller_Windows::GetExternalLEDCount() +{ + return external_led_count; +} + +void CreativeSoundBlasterAE5Controller_Windows::SetExternalLEDCount(unsigned int count) +{ + external_led_count = count; +} + +/*---------------------------------------------------------*\ +| LED Control | +\*---------------------------------------------------------*/ + +void CreativeSoundBlasterAE5Controller_Windows::SetLEDColors(unsigned char led_count, unsigned char* red_values, + unsigned char* green_values, unsigned char* blue_values) +{ + if(!device_opened || device_handle == INVALID_HANDLE_VALUE) + { + LOG_ERROR("[%s] Device not opened, cannot set LED colors", name.c_str()); + return; + } + + if(led_count == 0) + { + return; + } + + // Wait for mutex to prevent conflicts with Creative software + if(led_mutex != NULL) + { + DWORD wait_result = WaitForSingleObject(led_mutex, 5000); // 5 second timeout + if(wait_result != WAIT_OBJECT_0) + { + LOG_WARNING("[%s] Failed to acquire LED mutex, proceeding anyway", name.c_str()); + } + } + + // Internal LEDs (first 5) - bug requires sending command twice? + if(led_count > 0) + { + SendLEDCommand(0x03, AE5_INTERNAL_LED_COUNT, red_values, green_values, blue_values); + SendLEDCommand(0x03, AE5_INTERNAL_LED_COUNT, red_values, green_values, blue_values); + } + + // External LEDs + if(led_count > AE5_INTERNAL_LED_COUNT && external_led_count > 0) + { + SendLEDCommand(0x02, external_led_count, red_values + AE5_INTERNAL_LED_COUNT, green_values + AE5_INTERNAL_LED_COUNT, blue_values + AE5_INTERNAL_LED_COUNT); + } + + // Release mutex + if(led_mutex != NULL) + { + ReleaseMutex(led_mutex); + } +} + +bool CreativeSoundBlasterAE5Controller_Windows::SendLEDCommand(BYTE command_byte, unsigned int led_count_to_set, + unsigned char* red_values, unsigned char* green_values, unsigned char* blue_values) +{ + AE5_LED_Command cmd; + memset(&cmd, 0, sizeof(AE5_LED_Command)); + + cmd.command = command_byte; + cmd.packet_led_count = led_count_to_set; + + // Calculate data length + unsigned int data_length = led_count_to_set * 4; + cmd.data_length_low = data_length & 0xFF; + cmd.data_length_high = (data_length >> 8) & 0xFF; + + // Fill LED data + for(unsigned int i = 0; i < led_count_to_set; i++) + { + unsigned int offset = i * 4; + + if(command_byte == 0x02) // External WS2812B LED Strip + { + cmd.led_data[offset + 0] = blue_values[i]; + cmd.led_data[offset + 1] = red_values[i]; + cmd.led_data[offset + 2] = green_values[i]; + cmd.led_data[offset + 3] = 0x00; + } + else // Internal APA102 LED Strip + { + cmd.led_data[offset + 0] = red_values[i]; + cmd.led_data[offset + 1] = green_values[i]; + cmd.led_data[offset + 2] = blue_values[i]; + cmd.led_data[offset + 3] = 0xFF; + } + } + + AE5_LED_Command output_cmd; + memset(&output_cmd, 0, sizeof(AE5_LED_Command)); + DWORD bytes_returned = 0; + + BOOL result = DeviceIoControl( + device_handle, + 0x77772400, // Custom IOCTL command from Creative Lab's drivers + &cmd, + sizeof(AE5_LED_Command), + &output_cmd, + sizeof(AE5_LED_Command), + &bytes_returned, + NULL + ); + + if(!result) + { + DWORD error = GetLastError(); + LOG_ERROR("[%s] DeviceIoControl failed: Error %lu", name.c_str(), error); + return false; + } + + return true; +} diff --git a/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.h b/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.h new file mode 100644 index 00000000..d903f697 --- /dev/null +++ b/Controllers/CreativeController/CreativeSoundBlasterAE5Controller_Windows.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------*\ +| CreativeSoundBlasterAE5Controller_Windows.h | +| | +| Driver for Creative SoundBlaster AE-5 (Windows) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include "RGBController.h" +#include "CreativeSoundBlasterAE5ControllerBase.h" + +// AE-5 LED command structure +#pragma pack(push, 1) +struct AE5_LED_Command +{ + BYTE command; // 0x03 for internal, 0x02 for external + BYTE padding1[11]; // 11 zero bytes + BYTE packet_led_count; // Number of LEDs in this packet + BYTE padding2[3]; // 3 zero bytes + BYTE data_length_low; // Low byte of data length (LEDs × 4) + BYTE data_length_high; // High byte of data length + BYTE padding3[2]; // 2 zero bytes + BYTE led_data[400]; // LED data (RGBA), max 100 LEDs × 4 bytes + BYTE padding4[624]; // Rest filled with zeros (1044 - 420 bytes used) +}; +#pragma pack(pop) + +class CreativeSoundBlasterAE5Controller_Windows : public CreativeSoundBlasterAE5ControllerBase +{ +public: + CreativeSoundBlasterAE5Controller_Windows(); + ~CreativeSoundBlasterAE5Controller_Windows(); + + bool Initialize(); + std::string GetDeviceLocation(); + std::string GetDeviceName(); + unsigned int GetLEDCount(); + unsigned int GetExternalLEDCount(); + void SetExternalLEDCount(unsigned int count); + + void SetLEDColors(unsigned char led_count, unsigned char* red_values, + unsigned char* green_values, unsigned char* blue_values); + +private: + bool FindDevice(); + std::string FindHDAudioDevicePath(); + bool OpenDevice(); + void CloseDevice(); + bool SendLEDCommand(BYTE command_byte, unsigned int led_count_to_set, + unsigned char* red_values, unsigned char* green_values, unsigned char* blue_values); + + + std::string location; + std::string name; + std::string hdaudio_device_path; + bool device_found; + + // Device handle for HDAudio communication + HANDLE device_handle; + bool device_opened; + + // Synchronization to prevent conflicts with Creative software + HANDLE led_mutex; + + unsigned int external_led_count; + +#define AE5_VENDOR_ID 0x1102 +#define AE5_DEVICE_ID 0x0012 +#define AE5_INTERNAL_LED_COUNT 5 +#define AE5_EXTERNAL_LED_COUNT_MAX 100 +}; diff --git a/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.cpp b/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.cpp new file mode 100644 index 00000000..ab17fc28 --- /dev/null +++ b/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.cpp @@ -0,0 +1,171 @@ +/*---------------------------------------------------------*\ +| RGBController_CreativeSoundBlasterAE5.cpp | +| | +| RGBController for Creative SoundBlaster AE-5 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "RGBController_CreativeSoundBlasterAE5.h" + +/**------------------------------------------------------------------*\ + @name Creative Sound Blaster AE-5 + @category Audio + @type PCI + @save :x: + @direct :white_check_mark: + @effects :x: + @detectors DetectCreativeAE5Device + @comment +\*-------------------------------------------------------------------*/ + +RGBController_CreativeSoundBlasterAE5::RGBController_CreativeSoundBlasterAE5(CreativeSoundBlasterAE5ControllerBase* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = "Creative Labs"; + type = DEVICE_TYPE_SPEAKER; + description = controller->GetDeviceName() + " Device"; + location = controller->GetDeviceLocation(); + serial = ""; + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_CreativeSoundBlasterAE5::~RGBController_CreativeSoundBlasterAE5() +{ + delete controller; +} + +void RGBController_CreativeSoundBlasterAE5::SetupZones() +{ + zone internal_zone; + internal_zone.name = "Internal"; + internal_zone.type = ZONE_TYPE_LINEAR; + internal_zone.leds_min = 5; + internal_zone.leds_max = 5; + internal_zone.leds_count = 5; + internal_zone.matrix_map = NULL; + zones.push_back(internal_zone); + + for(unsigned int led_idx = 0; led_idx < 5; led_idx++) + { + led new_led; + new_led.name = "Internal LED " + std::to_string(led_idx + 1); + leds.push_back(new_led); + } + + zone external_zone; + external_zone.name = "External"; + external_zone.type = ZONE_TYPE_LINEAR; + external_zone.leds_min = 0; + external_zone.leds_max = 100; + external_zone.leds_count = controller->GetExternalLEDCount(); + external_zone.matrix_map = NULL; + zones.push_back(external_zone); + + for(unsigned int led_idx = 0; led_idx < controller->GetExternalLEDCount(); led_idx++) + { + led new_led; + new_led.name = "External LED " + std::to_string(led_idx + 1); + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_CreativeSoundBlasterAE5::ResizeZone(int zone, int new_size) +{ + if(zone == 1) // External zone + { + zones[zone].leds_count = new_size; + + leds.resize(5); + + for(unsigned int led_idx = 0; led_idx < (unsigned int)new_size; led_idx++) + { + led new_led; + new_led.name = "External LED " + std::to_string(led_idx + 1); + leds.push_back(new_led); + } + + controller->SetExternalLEDCount(new_size); + SetupColors(); + } +} + +void RGBController_CreativeSoundBlasterAE5::UpdateLEDRange(unsigned int start_led, unsigned int led_count) +{ + if(led_count == 0) + { + return; + } + + unsigned char* red_values = new unsigned char[led_count]; + unsigned char* green_values = new unsigned char[led_count]; + unsigned char* blue_values = new unsigned char[led_count]; + + for(unsigned int i = 0; i < led_count; i++) + { + unsigned int led_idx = start_led + i; + red_values[i] = RGBGetRValue(colors[led_idx]); + green_values[i] = RGBGetGValue(colors[led_idx]); + blue_values[i] = RGBGetBValue(colors[led_idx]); + } + + controller->SetLEDColors(led_count, red_values, green_values, blue_values); + + delete[] red_values; + delete[] green_values; + delete[] blue_values; +} + +void RGBController_CreativeSoundBlasterAE5::DeviceUpdateLEDs() +{ + UpdateLEDRange(0, controller->GetLEDCount()); +} + +void RGBController_CreativeSoundBlasterAE5::UpdateZoneLEDs(int zone) +{ + if(zone >= 0 && zone < (int)zones.size()) + { + unsigned int start_led = 0; + + // Calculate starting LED index for this zone + for(int i = 0; i < zone; i++) + { + start_led += zones[i].leds_count; + } + + UpdateLEDRange(start_led, zones[zone].leds_count); + } +} + +void RGBController_CreativeSoundBlasterAE5::UpdateSingleLED(int led) +{ + // Find which zone this LED belongs to and update only that zone + unsigned int current_led = 0; + for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + if(led >= (int)current_led && led < (int)(current_led + zones[zone_idx].leds_count)) + { + UpdateLEDRange(current_led, zones[zone_idx].leds_count); + return; + } + current_led += zones[zone_idx].leds_count; + } +} + +void RGBController_CreativeSoundBlasterAE5::DeviceUpdateMode() +{ + DeviceUpdateLEDs(); +} diff --git a/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.h b/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.h new file mode 100644 index 00000000..d6c629c7 --- /dev/null +++ b/Controllers/CreativeController/RGBController_CreativeSoundBlasterAE5.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------*\ +| RGBController_CreativeSoundBlasterAE5.h | +| | +| RGBController for Creative SoundBlaster AE-5 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "CreativeSoundBlasterAE5ControllerBase.h" + +class RGBController_CreativeSoundBlasterAE5: public RGBController +{ +public: + RGBController_CreativeSoundBlasterAE5(CreativeSoundBlasterAE5ControllerBase* controller_ptr); + ~RGBController_CreativeSoundBlasterAE5(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + CreativeSoundBlasterAE5ControllerBase* controller; + void UpdateLEDRange(unsigned int start_led, unsigned int led_count); +}; \ No newline at end of file