Но это когда мы точно знали что номер битмапа 4976. А как узнать этот номер? Наиболее быстрый способ это подсмотреть в отладчике в таком коде (перебирает все элементы)
Не-не, дело не в том, что бы достать ресурс из длл, а в том, как получить моментальную картинку гауги. Например снять копию текущего состояние какого-нибудь MFD.
Krit
29.11.2011 в 16:08
Не-не, дело не в том, что бы достать ресурс из длл, а в том, как получить моментальную картинку гауги. Например снять копию текущего состояние какого-нибудь MFD.
Именно так!
Спасибо за подсказку про IMAGE_CREATE_DIBSECTION! Получил «pelement->hdc;» и прочие указатели, щас пытаюсь вытащить оттуда картинку.
serg_p
11.01.2012 в 01:52
Не знаю, может быть кому пригодиться.
Проблема: Если прописать прибор и в ВК и в 2D кабине, то после того, как побывали хоть раз в ВК и хоть раз открыли 2D окно, в котором он прописан в 2D кабине — CallBack прибора с service_id == PANEL_SERVICE_PRE_UPDATE будет вызываться дважды. Это очень плохо. Собственно то, что некоторые программисты могут не учитывать этот факт, приводит к тому, что прибор нельзя прописать и в 2D кабине и в ВК, когда в PRE_UPDATE, например, что-нибудь инкрементируется (т.е. когда в вычислениях есть рекурсия по данным). Понятно, что в таком случае, инкрементироваться все будет дважды.
Если я ничего не упустил, то выйти из того положения можно таким вот образом:
MODULE_VAR main_module_tick18 = { TICK18 };
FLOAT64 get_tick18() { return main_module_tick18.var_value.n; }
FLOAT64 main_module_tick18_prev = 0;
...
// Update уровня логики
void FSAPI logic_level_update(PGAUGEHDR pgauge, SINT32 service_id, UINT32 extra_data)
{
// Используем только PANEL_SERVICE_PRE_UPDATE
// (инициализация и деинициализация в module_init и module_deinit)
if (service_id != PANEL_SERVICE_PRE_UPDATE)
return;
// Выполняем код уровня логики один раз каждый тик.
// Вне зависимости от того прописан ли прибор уровня логики и в ВК и в 2D кабине.
lookup_var(&main_module_tick18);
if (main_module_tick18.var_value.n == main_module_tick18_prev)
return;
// to do
// ...
// Обязательно запоминаем номер текущего тика
main_module_tick18_prev = main_module_tick18.var_value.n;
}
Собственно в // to do // … и крутим всю логику. Запускаться будет она один раз каждую 1/18 секунды, так как, если TICK18 у нас не изменился, то значит мы сейчас сидим в CallBack-е второго экземпляра прибора, а в этом случае мы CallBack-функцию прибора покидаем.
Это могут быть просто некоторые короткие вычисления, необходимые для данного прибора. Или это может быть вызов из невидимого прибора (который прописываем и в ВК и в 2D кабине) основной функции (метода) всей страшно сложной логики, страшно сложных систем, какого-нибудь приборного комплекса.
… (В ВК, если не ошибаюсь, нет никакой разницы, куда прописать невидимый прибор логики ([VcockpitXX]), CallBack всегда будет вызываться симом. В 2D, прибор, который будет крутить весь уровень логики необходимо прописать в окно, которое обязательно открывается автоматом при входе в 2D кабину. Как правило это окно с ident=MAIN_PANEL)
Сообщение отредактировано serg_p: 11 January 2012 — 15:47
gosha-z
11.01.2012 в 07:28
Серег, ты забыл одну маленькую вещь: это тяжелое наследие FS2004. В FSX это решается простым вынесением логики в in-process .dll
serg_p
11.01.2012 в 12:11
Во первых — это очень простой вариант, который будет работать и в FS9. Хотя в FS9 можно конечно сделать свой модуль и подсесть на системное событие, которое срабатывает вместе с PANEL_SERVICE_PRE_UPDATE. Но для чего городить огород, если все можно дешево и сердито реализовать в виде приборов.
Во вторых.
Как я понял, для FSX, ты имеешь в виду случай, когда dll прописывается в DLL.xml, что бы она загружалась вместе с симом. Но здесь мне приходит на ум только один вариант. С помощью функции SimConnect-а — SimConnect_SubscribeToSystemEvent, подписаться на системное событие «6Hz». Но! Хоть, как говорит MS, джой читается именно с этой частотой (This is the same rate that joystick movement events are transmitted) и тут для отработки ввода от джоя вроде бы больше и не надо, этой частоты обновления скорее всего не хватит для реализации собственных ПИД регуляторов, фильтров, следящих систем и т.д. 18 герц уже может и нормально, но 6 герц для своей навороченной логики — это маловато.
Ну и вообще, мне кажется, что лепить свою dll, которая будет висеть в памяти, пока сим загружен — как-то не ахти. Причем тут ведь не важно, используешь ли ты модель в данный момент, для которой ты прилепил к симу дополнительную dll или не используешь, dll будет висеть в памяти. Тут конечно можно, наверное, определить загружен ли самолет или нет, и в зависимости от этого уже создавать/убивать необходимые для работы структуры данных, но, по моему мнению все это гемор.
По моему мнению гораздо проще и надежней все реализовывать в виде приборов. Тут и обновление логики четко синхронизировано с отображением и частота обновления (18Гц) вполне приемлема для реализации всяких своих фишек и dll, в которой реализуются приборы, загружается и выгружается вместе с самолетом.
Сообщение отредактировано serg_p: 11 January 2012 — 15:48
icebear
11.01.2012 в 12:52
Два вопроса: в симе действительно принудительно крутиться цикл неактивного элемента? Т.е. по сути нельзя находится одновременно в ВК и в 2Д, но можно в ВК открыть какую-либо панель, на которой юзается прибор, находящийся в ВК. Но это частный случай я бы сказал, а вот в нормальном состоянии неужели два цикла? Сергей, при каких условиях ты наткнулся на это? Второй вопрос: разве ВК обновляется так же с «частотой 18Гц»?
Сообщение отредактировано icebear: 11 January 2012 — 12:52
serg_p
11.01.2012 в 13:20
Почему два цикла?
Цикл один.
В каждой итерации пробегаются по очереди все приборы, прописанные в Panel.cfg, начиная с [Window00] и заканчивая последней [VcockpitXX]. Соответственно, если, например, у тебя прибор прописан в двух 2D окнах, плюс еще в какой-нибудь [VcockpitXX] — его CallBack будет вызываться три раза, если ты зашел в ВК и плюс к этому хоть по одному разу отобразил оба 2D окна. Т.е. сим начинает крутить CallBack прибора только, если он его должен визуализировать. Причем, после того, как сим визуализировал экземпляр прибора, его Callback будет всегда вызываться симом, вплоть до окончания полета, вне зависимости от того будет ли еще отображаться этот экземпляр или нет.
CallBack-и приборов с одним STATIC, с флагом HIDDEN, тоже крутятся, несмотря на то, что битмап прибора не отрисовывается.
Все это можно легко проверить в отладчике.
Сообщение отредактировано serg_p: 11 January 2012 — 13:33
FortRoss8
12.01.2012 в 16:21
да особого смысла выносить в отдельные потоки нет, если только ты не считаешь всю динамику полностью. Ну и работа с недокументированностями фс9 и с коннектом — это немножко разные разности
icebear604
13.01.2012 в 08:38
да особого смысла выносить в отдельные потоки нет, если только ты не считаешь всю динамику полностью. Ну и работа с недокументированностями фс9 и с коннектом — это немножко разные разности
ты шаман, тебе виднее просто у меня до сих пор шок от провала фпс в первой версии кпи, из-за которого у меня развилось маниакальное влечение к потокам, директиксу и т.п. и обязательно всё это в одну корзину 😀 вот кто-бы ещё время дал обо всём этом подумать….
undefined
serg_p591
20.01.2012 в 09:57
Вот собственно, что у меня получилось.
Прибор нужно прописать один раз, где-нибудь в Panel.cfg.
При инициализации загружается явным образом (с помощью LoadLibrary) SimConnect.dll для FSX SP1. Папка, откуда грузится SimConnect.dll должна лежать в рядом с этой dll. Можно положить, в какую-нибудь подпапку. Путь к подпапке прописан в paths.h.
Я упустил одну важную вещь, когда мы выше говорили про запуск логики. Кроме системного события «6Gz», в FSX есть еще событие «Frame». Как я понял, какие в данный момент FPS, с такой частотой и срабатывает это событие. Все хозяйство описано в sim.cpp. Update уровня логики запускается в SimConnectDispatchProc вот в этом месте:
case SIMCONNECT_RECV_ID_EVENT_FRAME:
{
SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;
switch(evt->uEventID)
{
// Notifications every visual frame. Срабатывает столько раз в секунду сколько FPS
case cliEventFrame:
{
lookup_var(&simTick18);
if (simTick18.var_value.n > tick18Prev)
{
// Вызываем обновление логики 18 раз в сеунду
// Если EVENT_FRAME крутится быстрей 18гц - пропускаем эти события
sim_LogicLevel->Update();
}
tick18Prev = simTick18.var_value.n;
}
break;
}
}
break;
есть флаг IMAGE_HIDDEN, в сдк к сожалению только написано: «…не показывать это изображение до тех пор, пока код датчика конкретно не вызовёт его. Это динамически изменяется.»
Подскажите плиз, кто знает, какой строкой «вызвать» изображение, я так понял это делается в секции колбэк. Спасибо за ответы.
serg_p591
01.07.2012 в 10:32
FLOAT64 FSAPI callback_function(PELEMENT_NEEDLE pelement)
{
if ([некое условие])
{
SHOW_IMAGE(pelement);
return [возвращаем нужное значение для управления битмапом];
}
else
{
HIDE_IMAGE(pelement);
return 0.0; // например, 0, ну или другое значение, устанавливающее битмап в исходную позицию
}
}
Сами макросы делают вот что:
SHOW_IMAGE(element):
element->image_flags &= ~IMAGE_HIDDEN
HIDE_IMAGE(element):
element->image_flags |= IMAGE_HIDDEN
Собственно это все в gauhes.h
По аналогии можете производить операции с другими флагами.
Важно!
Ни в коем случае не присваиваем флаг битовому полю image_flags.
Работаем исключительно с битвыми операциями:
| — для поднятия флага
и
обязательно сначала ~ к флагу, затем обязательно & с битовым полем и флагом — для сброса флага в 0.
Edited by serg_p
seycovip3008
01.07.2012 в 13:58
Спасибо большое! Сделал подсветку прибора от выключателя, со шкалой разобрался (с помощью MAKE_ICON, 0/-1)
, а со стрелкой — надеюсь с флагом должно получится…
Всё получилось, ещё раз спасиб.
Edited by seyco
seycovip3008
02.07.2012 в 21:44
Сталкнулся еще вот с таким вопросом, в этой функции мне непонятно что означают названия условий:
Спасибо большое! Останется еще разобраться, как лучше и проще организовать озвучку приборов… Кроме как с помощью Direct Sound вариантов пока не нашел, да и если честно, кроме документации (общего описания) в нете пока тоже ничего не нашел. В консольном окне делал, это просто, но не с помощью Direct Sound. А как в симулятор запихнуть..? Если есть у кого примеры, поделитесь пожалуйста, буду признателен.
icebear604
03.07.2012 в 15:02
Спасибо большое! Останется еще разобраться, как лучше и проще организовать озвучку приборов… Кроме как с помощью Direct Sound вариантов пока не нашел, да и если честно, кроме документации (общего описания) в нете пока тоже ничего не нашел. В консольном окне делал, это просто, но не с помощью Direct Sound. А как в симулятор запихнуть..? Если есть у кого примеры, поделитесь пожалуйста, буду признателен.
В списке тем сверху есть тему по поводу озвучки их ХМЛ гауг, есть смысл её посмотреть, ибо л-переменные можно писать/читать в любых гаугах.
seycovip3008
03.07.2012 в 19:25
В списке тем сверху есть тему по поводу озвучки их ХМЛ гауг, есть смысл её посмотреть, ибо л-переменные можно писать/читать в любых гаугах.
Спасиб, я не читал, не тратил драгоценное время, думал к С++ не подойдет…
icebear604
03.07.2012 в 19:34
Спасиб, я не читал, не тратил драгоценное время, думал к С++ не подойдет…
Я вижу что и поиском не пользовался Всё-таки «раздобуть» книгу Гриффитса и прочитай хотя-бы её, там и про звуки есть.
seycovip3008
03.07.2012 в 19:44
Поиском пользовался, но он зараза такую кучу выдает, можно ночь искать, голова кругом, уже было такое, Гриффитсона пытался найти, когда понял что она на инглишь, охота пропала, да и сылка попалась битая. У меня к сожалению с английским очень плохо, приходится сначала переводить, потом вникать… Пока повременю, очень интересно к моему первому прибору подключить звук.
Гриффитсона наконец скачал , уже легче
Edited by seyco
seycovip3008
04.07.2012 в 16:52
Всем привет. Уже несколько дней и ночей потратил в поисках нужной информации, по поводу реализации звуков в кабине (для начала в консольной панели), но получается хожу вокруг да около, а цели добиться не могу. С++ начал изучать недавно, до этого работал в ассемблере (давно). Сделал свой первый прибор на С++ (радиовысотомер), подключил пока к 2м тумблерам — питание и подсветка приборов, завязал логику. Всё работает, теперь осталось разобраться, как подключить звук… Вот тут посыпались вопросы, которые разрешить сам не могу.
Хотелось реализовать задуманное с помощью DirectSound и как можно проще, без наворотов, но чтоб несколько звуков можно было проиграть. Почитал статей кучу, собрал несколько примеров, там по одному звуку только, без буферов, скачал DS SDK8, наваротов… Наконец, нашел что-то похожее, на то, что мне нужно, а собрать до конца не могу (хотел для начала, чтоб в консоли проиграл звук, а как подключить нужный файл — торможу.
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========
Догадываюсь, наверное из-за отсутствия строк, где нужно добавить сам файл, могу ошибаться. Вытащить нужное из других готовых консольных примеров SDK не смог, везде своя лексика, мало опыту еще.
Остается просить опытных программистов помочь разобраться здесь или может кто подскажет, где найти похожий готовый пример для консоли, я даже не надеюсь о большем… (для сима).
Заранее благодарен.
Edited by seyco
Jazz218
04.07.2012 в 17:17
Я целей и задач не знаю, но может быть что-то попроще можно использовать? Например, winmm какойнить…
HINSTANCE hDLL;
hDLL = LoadLibrary(«pnk_154m_3_024.gau»);
pAdr = (GAUGESLINKAGE *)GetProcAddress(hDLL, «Linkage»);
HBITMAP hb = LoadBitmap(hDLL,MAKEINTRESOURCE(4976));
DeleteObject(hb);
FreeLibrary(hDLL);
Но это когда мы точно знали что номер битмапа 4976. А как узнать этот номер? Наиболее быстрый способ это подсмотреть в отладчике в таком коде (перебирает все элементы)
GAUGESLINKAGE * pAdr;
HINSTANCE hDLL;
hDLL = LoadLibrary(«pnk_154m_3_024.gau»);
pAdr = (GAUGESLINKAGE *)GetProcAddress(hDLL, «Linkage»);
PELEMENT_HEADER el_list;
int i=0;
while (pAdr->gauge_header_ptr[i]!=NULL)
{
el_list = *pAdr->gauge_header_ptr[i]->elements_list;
while (el_list!=NULL)
{
if (el_list->next_element!=NULL)
el_list = *el_list->next_element;
else
el_list = NULL;
}
i++;
}
Именно так!
Спасибо за подсказку про IMAGE_CREATE_DIBSECTION! Получил «pelement->hdc;» и прочие указатели, щас пытаюсь вытащить оттуда картинку.
Проблема:
Если прописать прибор и в ВК и в 2D кабине, то после того, как побывали хоть раз в ВК и хоть раз открыли 2D окно, в котором он прописан в 2D кабине — CallBack прибора с service_id == PANEL_SERVICE_PRE_UPDATE будет вызываться дважды. Это очень плохо. Собственно то, что некоторые программисты могут не учитывать этот факт, приводит к тому, что прибор нельзя прописать и в 2D кабине и в ВК, когда в PRE_UPDATE, например, что-нибудь инкрементируется (т.е. когда в вычислениях есть рекурсия по данным). Понятно, что в таком случае, инкрементироваться все будет дважды.
Если я ничего не упустил, то выйти из того положения можно таким вот образом:
MODULE_VAR main_module_tick18 = { TICK18 }; FLOAT64 get_tick18() { return main_module_tick18.var_value.n; } FLOAT64 main_module_tick18_prev = 0; ... // Update уровня логики void FSAPI logic_level_update(PGAUGEHDR pgauge, SINT32 service_id, UINT32 extra_data) { // Используем только PANEL_SERVICE_PRE_UPDATE // (инициализация и деинициализация в module_init и module_deinit) if (service_id != PANEL_SERVICE_PRE_UPDATE) return; // Выполняем код уровня логики один раз каждый тик. // Вне зависимости от того прописан ли прибор уровня логики и в ВК и в 2D кабине. lookup_var(&main_module_tick18); if (main_module_tick18.var_value.n == main_module_tick18_prev) return; // to do // ... // Обязательно запоминаем номер текущего тика main_module_tick18_prev = main_module_tick18.var_value.n; }Собственно в
// to do
// …
и крутим всю логику. Запускаться будет она один раз каждую 1/18 секунды, так как, если TICK18 у нас не изменился, то значит мы сейчас сидим в CallBack-е второго экземпляра прибора, а в этом случае мы CallBack-функцию прибора покидаем.
Это могут быть просто некоторые короткие вычисления, необходимые для данного прибора.
Или это может быть вызов из невидимого прибора (который прописываем и в ВК и в 2D кабине) основной функции (метода) всей страшно сложной логики, страшно сложных систем, какого-нибудь приборного комплекса.
…
(В ВК, если не ошибаюсь, нет никакой разницы, куда прописать невидимый прибор логики ([VcockpitXX]), CallBack всегда будет вызываться симом. В 2D, прибор, который будет крутить весь уровень логики необходимо прописать в окно, которое обязательно открывается автоматом при входе в 2D кабину. Как правило это окно с ident=MAIN_PANEL)
Сообщение отредактировано serg_p: 11 January 2012 — 15:47
Во вторых.
Как я понял, для FSX, ты имеешь в виду случай, когда dll прописывается в DLL.xml, что бы она загружалась вместе с симом. Но здесь мне приходит на ум только один вариант. С помощью функции SimConnect-а — SimConnect_SubscribeToSystemEvent, подписаться на системное событие «6Hz». Но! Хоть, как говорит MS, джой читается именно с этой частотой (This is the same rate that joystick movement events are transmitted) и тут для отработки ввода от джоя вроде бы больше и не надо, этой частоты обновления скорее всего не хватит для реализации собственных ПИД регуляторов, фильтров, следящих систем и т.д. 18 герц уже может и нормально, но 6 герц для своей навороченной логики — это маловато.
Ну и вообще, мне кажется, что лепить свою dll, которая будет висеть в памяти, пока сим загружен — как-то не ахти. Причем тут ведь не важно, используешь ли ты модель в данный момент, для которой ты прилепил к симу дополнительную dll или не используешь, dll будет висеть в памяти. Тут конечно можно, наверное, определить загружен ли самолет или нет, и в зависимости от этого уже создавать/убивать необходимые для работы структуры данных, но, по моему мнению все это гемор.
По моему мнению гораздо проще и надежней все реализовывать в виде приборов. Тут и обновление логики четко синхронизировано с отображением и частота обновления (18Гц) вполне приемлема для реализации всяких своих фишек и dll, в которой реализуются приборы, загружается и выгружается вместе с самолетом.
Сообщение отредактировано serg_p: 11 January 2012 — 15:48
Сообщение отредактировано icebear: 11 January 2012 — 12:52
Цикл один.
В каждой итерации пробегаются по очереди все приборы, прописанные в Panel.cfg, начиная с [Window00] и заканчивая последней [VcockpitXX]. Соответственно, если, например, у тебя прибор прописан в двух 2D окнах, плюс еще в какой-нибудь [VcockpitXX] — его CallBack будет вызываться три раза, если ты зашел в ВК и плюс к этому хоть по одному разу отобразил оба 2D окна. Т.е. сим начинает крутить CallBack прибора только, если он его должен визуализировать. Причем, после того, как сим визуализировал экземпляр прибора, его Callback будет всегда вызываться симом, вплоть до окончания полета, вне зависимости от того будет ли еще отображаться этот экземпляр или нет.
CallBack-и приборов с одним STATIC, с флагом HIDDEN, тоже крутятся, несмотря на то, что битмап прибора не отрисовывается.
Все это можно легко проверить в отладчике.
Сообщение отредактировано serg_p: 11 January 2012 — 13:33
да особого смысла выносить в отдельные потоки нет, если только ты не считаешь всю динамику полностью. Ну и работа с недокументированностями фс9 и с коннектом — это немножко разные разности
ты шаман, тебе виднее
просто у меня до сих пор шок от провала фпс в первой версии кпи, из-за которого у меня развилось маниакальное влечение к потокам, директиксу и т.п. и обязательно всё это в одну корзину 😀 вот кто-бы ещё время дал обо всём этом подумать….
undefined
Вот собственно, что у меня получилось.
Прибор нужно прописать один раз, где-нибудь в Panel.cfg.
При инициализации загружается явным образом (с помощью LoadLibrary) SimConnect.dll для FSX SP1. Папка, откуда грузится SimConnect.dll должна лежать в рядом с этой dll. Можно положить, в какую-нибудь подпапку. Путь к подпапке прописан в paths.h.
Я упустил одну важную вещь, когда мы выше говорили про запуск логики. Кроме системного события «6Gz», в FSX есть еще событие «Frame». Как я понял, какие в данный момент FPS, с такой частотой и срабатывает это событие. Все хозяйство описано в sim.cpp. Update уровня логики запускается в SimConnectDispatchProc вот в этом месте:
case SIMCONNECT_RECV_ID_EVENT_FRAME: { SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData; switch(evt->uEventID) { // Notifications every visual frame. Срабатывает столько раз в секунду сколько FPS case cliEventFrame: { lookup_var(&simTick18); if (simTick18.var_value.n > tick18Prev) { // Вызываем обновление логики 18 раз в сеунду // Если EVENT_FRAME крутится быстрей 18гц - пропускаем эти события sim_LogicLevel->Update(); } tick18Prev = simTick18.var_value.n; } break; } } break;ps_tu144_various_20120120_1320.zip
Edited by serg_p
хм, пустой проект для сим коннекта. многие тут такое искали, спасибо
undefined
Доброе время суток!
У меня вопрос к специалистам, в секции кода прибора, например стрелки:
…
MAKE_NEEDLE //
(
alt_needle,
BMP_ALT_NEEDLE,
&alt_list_5,
NULL,
IMAGE_USE_TRANSPARENCY|IMAGE_USE_ERASE|IMAGE_USE_LUMINOUS|IMAGE_HIDDEN,
0,
95, 108,
12, 70,
RADIO_HEIGHT,alt_needle_cb,
alt_nonlinearity,
3
)…
есть флаг IMAGE_HIDDEN, в сдк к сожалению только написано: «…не показывать это изображение до тех пор, пока код датчика конкретно не вызовёт его. Это динамически изменяется.»
Подскажите плиз, кто знает, какой строкой «вызвать» изображение, я так понял это делается в секции колбэк. Спасибо за ответы.
FLOAT64 FSAPI callback_function(PELEMENT_NEEDLE pelement) { if ([некое условие]) { SHOW_IMAGE(pelement); return [возвращаем нужное значение для управления битмапом]; } else { HIDE_IMAGE(pelement); return 0.0; // например, 0, ну или другое значение, устанавливающее битмап в исходную позицию } }Сами макросы делают вот что:
SHOW_IMAGE(element):
HIDE_IMAGE(element):
Собственно это все в gauhes.h
По аналогии можете производить операции с другими флагами.
Важно!
Ни в коем случае не присваиваем флаг битовому полю image_flags.
Работаем исключительно с битвыми операциями:
| — для поднятия флага
и
обязательно сначала ~ к флагу, затем обязательно & с битовым полем и флагом — для сброса флага в 0.
Edited by serg_p
Спасибо большое! Сделал подсветку прибора от выключателя, со шкалой разобрался (с помощью MAKE_ICON, 0/-1)
, а со стрелкой — надеюсь с флагом должно получится…
Всё получилось, ещё раз спасиб.
Edited by seyco
Сталкнулся еще вот с таким вопросом, в этой функции мне непонятно что означают названия условий:
void FSAPI sound_gau_cb ( PGAUGEHDR pgauge, int service_id, UINT32 extra_data )
{
switch(service_id)
{
case PANEL_SERVICE_CONNECT_TO_WINDOW: // extra_data = PANEL_WND
…
break;
case PANEL_SERVICE_PRE_INSTALL: // «install_routine()» // extra_data = resource_handle
…
break;
case PANEL_SERVICE_PRE_INITIALIZE: // «initialize_routine()»
…
break;
case PANEL_SERVICE_PRE_UPDATE: // «update_routine()»
…
break;
case PANEL_SERVICE_PRE_DRAW: // «draw_routine()»
…
break;
case PANEL_SERVICE_PRE_KILL: // «kill_routine()»
…
break;
}
}
Если кто знает подскажите пожалуйста или ссылочку киньте, где подсматреть можно…
И как правильно прописать вызов этой функции. Спасибо.
Edited by seyco
Это стандартный gauge callback, прописывается в макросе инициализации гауги, который выглядит как
GAUGE_HEADER_FS800([GAUGE ID],[GAUGE_WIDTH],[GAUGE_NAME],&[GAUGE ELEMENT LIST],[GAUGE MOUSE RECT],sound_gau_cb,0,0)
Описание service_id найдёшь в gauges.h и книге Гриффитса (Creating C-Gauges.pdf, искать на авсимкоме).
И ещё: есть уже тема по созданию гауг на С, имеет смысл в неё писать http://www.avsim.su/forum/topic/85531-davayte-eshyo-raz-pogovrim-o-sozdanii-priborov-na-si/
Edited by icebear
Спасибо большое! Останется еще разобраться, как лучше и проще организовать озвучку приборов… Кроме как с помощью Direct Sound вариантов пока не нашел, да и если честно, кроме документации (общего описания) в нете пока тоже ничего не нашел. В консольном окне делал, это просто, но не с помощью Direct Sound. А как в симулятор запихнуть..? Если есть у кого примеры, поделитесь пожалуйста, буду признателен.
В списке тем сверху есть тему по поводу озвучки их ХМЛ гауг, есть смысл её посмотреть, ибо л-переменные можно писать/читать в любых гаугах.
Спасиб, я не читал, не тратил драгоценное время, думал к С++ не подойдет…
Я вижу что и поиском не пользовался
Всё-таки «раздобуть» книгу Гриффитса и прочитай хотя-бы её, там и про звуки есть.
Поиском пользовался, но он зараза такую кучу выдает, можно ночь искать, голова кругом, уже было такое, Гриффитсона пытался найти, когда понял что она на инглишь, охота пропала, да и сылка попалась битая. У меня к сожалению с английским очень плохо, приходится сначала переводить, потом вникать… Пока повременю, очень интересно к моему первому прибору подключить звук.
Гриффитсона наконец скачал , уже легче
Edited by seyco
Всем привет. Уже несколько дней и ночей потратил в поисках нужной информации, по поводу реализации звуков в кабине (для начала в консольной панели), но получается хожу вокруг да около, а цели добиться не могу. С++ начал изучать недавно, до этого работал в ассемблере (давно). Сделал свой первый прибор на С++ (радиовысотомер), подключил пока к 2м тумблерам — питание и подсветка приборов, завязал логику. Всё работает, теперь осталось разобраться, как подключить звук… Вот тут посыпались вопросы, которые разрешить сам не могу.
Хотелось реализовать задуманное с помощью Direct Sound и как можно проще, без наворотов, но чтоб несколько звуков можно было проиграть. Почитал статей кучу, собрал несколько примеров, там по одному звуку только, без буферов, скачал DS SDK8, наваротов… Наконец, нашел что-то похожее, на то, что мне нужно, а собрать до конца не могу (хотел для начала, чтоб в консоли проиграл звук, а как подключить нужный файл — торможу.
http://subscribe.ru/…54450.html#ds41
Здесь используются только базовые функции и интерфейсы, что сделает код независимым от версии DirectX !
#include <dsound.h>
#include <stdafx.h>
#include <Windows.h>
//#include <mmsystem.h>
int main ()
{
//идентификатор окна
HWND hWnd = NULL;
// Создаем объект аудиоустройства
HRESULT hRes;
LPDIRECTSOUND pDSound;
if (FAILED(hRes = DirectSoundCreate(NULL, &pDSound, NULL))) return hRes;
// Задаем модель взаимодействия (уровень привилегий обращения к звуковой аппаратуре)
// при воспроизведении звука с другими работающими приложениями, иначе вторичные буфера не будет микшироваться
if (FAILED(hRes = pDSound->SetCooperativeLevel(hWnd, DSSCL_NORMAL)))
return hRes;
// Далее приступим к созданию вторичного аудиобуфера. Для начала зададим его формат:
WAVEFORMATEX waveFmt;
waveFmt.wFormatTag = WAVE_FORMAT_PCM;
waveFmt.nChannels = 1;
waveFmt.nSamplesPerSec = 8000;
waveFmt.wBitsPerSample = 8;
waveFmt.nBlockAlign = (WORD)(waveFmt.wBitsPerSample * waveFmt.nChannels / 8);
waveFmt.nAvgBytesPerSec = waveFmt.nSamplesPerSec * waveFmt.nBlockAlign;
waveFmt.cbSize = 0;
// Далее следует заполнить структуру с информацией о создаваемом буфере. В данном случае
// мы создаем буфер с параметрами, описываемыми структурой waveFmt и размером, достаточным для размещения 4 с звука.
DSBUFFERDESC dsBufDesc;
ZeroMemory(&dsBufDesc, sizeof(dsBufDesc));
dsBufDesc.dwSize = sizeof(dsBufDesc);
dsBufDesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY;
dsBufDesc.dwBufferBytes = waveFmt.nAvgBytesPerSec * 4;
dsBufDesc.dwReserved = 0;
dsBufDesc.lpwfxFormat = &waveFmt;
// После этих подготовительных операций можно непосредственно создать сам буфер:
LPDIRECTSOUNDBUFFER pDsBuffer;
if (FAILED(hRes = pDSound->CreateSoundBuffer(&dsBufDesc, &pDsBuffer, NULL))) return hRes;
//И заполнить его данными:
if (FAILED(hRes = OnBufferLost(pDsBuffer, 440.0))) return hRes;
//Рассмотрим процедуру инициализации буфера данными на примере его восстановления:
HRESULT OnBufferLost(LPDIRECTSOUNDBUFFER lpDSBuffer, float flFreq )
{
HRESULT hRes;
PUCHAR pLockBuf;
DWORD dwBufSize;
WAVEFORMATEX waveFmt;
do hRes = lpDSBuffer->Restore();
while (hRes == DSERR_BUFFERLOST);
if ( FAILED( hRes )) return hRes;
if ( FAILED( hRes = lpDSBuffer->Lock(0, 0, (LPVOID*)&pLockBuf, &dwBufSize, NULL, 0, DSBLOCK_ENTIREBUFFER))) return hRes;
if ( FAILED( hRes = lpDSBuffer->GetFormat(&waveFmt, sizeof(waveFmt), NULL))) return hRes;
for (int i = 0; i < dwBufSize; ++i)
{
pLockBuf = (UCHAR)(64.0 * (1.0 + cos(2.0*3.1416*i*flFreq/waveFmt.nSamplesPerSec)));
}
return lpDSBuffer->Unlock( (LPVOID)pLockBuf, dwBufSize, NULL, 0);
}
// Механизм извещений
LPDIRECTSOUNDNOTIFY lpDsNotify;
DSBPOSITIONNOTIFY PositionNotify;
// Требуем нужный нам интерфейс IDirectSoundNotify
if (FAILED(hRes = pDsBuffer->QueryInterface(IID_IDirectSoundNotify,(LPVOID*)&lpDsNotify))) return hRes;
PositionNotify.dwOffset = DSBPN_OFFSETSTOP;
PositionNotify.hEventNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
hRes = lpDsNotify->SetNotificationPositions(1, &PositionNotify);
// Освобождаем не нужный более интерфейс
lpDsNotify->Release();
// А вот теперь можно и воспроизвести буфер:
while (pDsBuffer->Play(0, 0, 0 ) == DSERR_BUFFERLOST) OnBufferLost(pDsBuffer, 440.0);
// Ожидаем окончания воспроизведения буфера
WaitForSingleObject(PositionNotify.hEventNotify, INFINITE);
// По окончанию работы культурные люди прибирают за собой:
CloseHandle( PositionNotify.hEventNotify );
pDsBuffer->Release();
pDSound->Release();
// Воспроизведение нескольких буферов
//pDsBuffer_1 -> Play(0,0,0);
//pDsBuffer_2 -> Play();
//pDsBuffer_3 -> Play();
return 0;
}
В данный момент при компиляции возникает одна ошибка:
1>—— Построение начато: проект: 03, Конфигурация: Debug Win32 ——
1> 03.cpp
1>d:документыvisual studio 2010projects 3 3 3.cpp(24): error C2065: hWnd: необъявленный идентификатор
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========
Догадываюсь, наверное из-за отсутствия строк, где нужно добавить сам файл, могу ошибаться. Вытащить нужное из других готовых консольных примеров SDK не смог, везде своя лексика, мало опыту еще.
Остается просить опытных программистов помочь разобраться здесь или может кто подскажет, где найти похожий готовый пример для консоли, я даже не надеюсь о большем… (для сима).
Заранее благодарен.
Edited by seyco
Я целей и задач не знаю, но может быть что-то попроще можно использовать? Например, winmm какойнить…
http://msdn.microsoft.com/en-us/library/windows/desktop/dd743680(v=vs.85).aspx
Edited by Jazz