Уголок программиста (1 онлайн

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
Я чет побаиваюсь и того и другого. Мне интересен PyGTK, но ближайший гуй попробую-таки делать в QT для самообразования, хоть мне он и показался перебором по сложности для большинства задач)

Python чем категорически пока еще не может заменить собой полностью C++
Разные сферы применения. Недавно на хабре писали, что питон удобнее для сложных научных расчетов, поскольку легче подождать интерпретатор, чем подождать, пока отработает компилятор. Да и вообще - один из самых скоростных с точки зрения разработки языков. Грубо говоря, 3D принтер. Разрешение так себе, скорость не ахти, но сразу видишь, что получится, и можешь позволить тучу итераций. Плюсы же, грубо говоря, линия производства пластиковых деталей. Долго заводится, требует гораздо более высокой квалификации, быстро едет на оптовых заказах :)

P.S. на этих двух языках свет клином не сошелся ;) И вообще мейнстрим, вроде как, Java) Мне вот интересно было б потыкать D, Go, почему-то, менее интересно, но все равно, потыкать хочется. Rust, опять жею Но все равно, селдующим учить буду плюсы
 
Последнее редактирование:
  • Like
Реакции: Alex Longard и SuperDroid

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
@SuperDroid, Да, примерно так, но насколько оправдан таймер внутри объекта - еще вопрос)
Можно по разному делать. Вот допустим, если есть внешний рендер, представляющий из себя бесконечный цикл, каждая итерация которого изменяет временную константу и время в нем просчитывается(по типу игрушек).
И у вас есть какой-то список (массив) разнородных объектов, которые как-то движутся по своим траекториям, доступный рендеру. Один из которых ваш объект с формулой S=f(t).
Тогда можно, допустим сделать интерфейс со временем, какой-нибудь ITime с пропертей time. Потом в объекте реализовать интерфейс ITime (по сути дела объявить эту проперти).
В рендере каждую итерацию проходить по всем объектам, преобразовывать их в ITime и заполнять у них time. Вот так можно применить полиморфизм.
Общно, для всех объектов массива одинаково.
Внутри цикла будет одна строчка что-то типа такого
ITime(current_obj).time = current_time;

А внутри объекта описать метод, возвращающий пройденный путь в зависимости от его внутреннего time без входных параметров.

И тогда вы будете получать при вызове этого метода в любое время текущий пройденный путь объектом от "начала времен".
Можно пойти еще дальше...
Если вы этот метод вынесете в интерфейс IDistance и реализуете его для каждого объекта из списка(метод decimal Distance()), то потом вы опять воспользовавшись полиморфизмом, будете получать текущие пройденные расстояния у любого объекта из массива в любой момент.
Всего одна строчка в цикле, а объектов может быть сотни и тысячи и они разные внутри:

dist_obj = IDistance(current_obj).Distance;

[DOUBLEPOST=1524632951][/DOUBLEPOST]Процедурный подход такой красоты и унификации работы с разнородными данными не предоставит.
 
Последнее редактирование:
  • Like
Реакции: SuperDroid

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
А в деле унификации в ООП можно пойти еще дальше (зависит от языка). Но это уже идет усложнение.
Метод вычисления расстояния Distance() на самом деле объявить делегатом, а в конструктор объекта или в инициализационный метод, который будет вызван при конструировании объекта, например билдером, передавать лямбду с конкретной реализацией формулы S=f(t). И тогда можно будет для каждого такого экземпляра класса на еще этапе конструирования задавать свою функцию S=f(t). А код, применяющий полиморфизм через интерфейс, одинаково будет получать пройденные расстояния от "начала времен" для любого объявленного таким образом объекта.
[DOUBLEPOST=1524633789][/DOUBLEPOST]Если попробовать нечто подобное реализовать для процедурного подхода, то ИМХО врядли что-то красивое и неуродливое получится)))
 
Последнее редактирование:
  • Like
Реакции: SuperDroid

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
Для того, чтобы реализовать такую концепцию на ООП, конечно появляется куча классов, интерфейсы, классы обслуживающие классы (билдеры например, или фабрики). Каждый такой класс обычно идет отдельными файлами (хороший тон - не лепить все классы в один файл, нормальное правило - один класс один файл и название у файла должно быть по названию класса. Для больших проектов оправдано - не придется мерджить в системах контроля версий, если изменения затрагивают какой-то конкретный класс, и не затрагивают другие классы).
Но оно того стоит в данном конкретном случае. Все написанное мое личное мнение и может не совпадать с мнением других участников форума))) В срач вступать не хочу. Интересны другие мнения и опыт - проекты бывают разные, языки их возможности - тем более.
 
  • Like
Реакции: SuperDroid и Alex Longard

Alex Longard

Well-Known Member
10 Май 2015
1.941
1.232
113
36
München->Deutschland, Київ->Україна
@Zildjian сказал(а):
Это что ж вы такое рисуете и каким способом, что оно столько времени рендерится?
отрисовывался сигнал в реалтайме с выхода синтезатора, сэмпл гиперсав от вируса длительностью в 1 секунду рисовался около минуты стандартными средствами QT.
Мне потом на codenet подсказали вариант для реализации такой отрисовки, но на тот момент у меня уже интерес к QT наглухо пропал.

@Alex_V сказал(а):
Собственно, зачем меня в эту степь вообще понесло. Есть желание написать некую рулилку синтом, но готовые решения типа ctrlr не устраивают из-за ограниченности возможностей по построению гуя.
Есть luavst, это типа скриптоуправляемый плагин для работы с миди.
Интересовался им до тех пор пока не познакомился с рипером)))

@pse, вы уже раньше писали - ООП для больших проэктов и чтоб без гемора, но процедурный стиль никуда и никогда не денется, тут уже прийдется выбирать - либо скорость разработки и удобство кода, либо скорость работы конечного продукта.
Я знаю человека который уже больше 30 лет пишет на ассемблере и нифига непонимает ни в ООП ни в современных парадигмах))) Когда я заикнулся на тему того что оформить классом будет удобней и наглядней код для контроллера, я потом услышал много мата и рассуждения что сейчас жопорукая молодеж только может писать стихи в коде и дебаггером пользоваться неумеют))))
 
Последнее редактирование:

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
я потом услышал много мата и рассуждения что сейчас жопорукая молодеж только может писать стихи в коде и дебаггером пользоваться неумеют))))
и это верно)))
Для контроллера критически важна скорость работы и объемы памяти, а с ооп он не получит ни того ни другого. Ардуино вон взять. Там памяти как кот наплакал)))
 

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
ООП для больших проэктов и чтоб без гемора, но процедурный стиль никуда и никогда не денется,
Я рассматриваю ООП как некий следующий уровень абстракции - развитие процедурно-функциональной парадигмы.
По сути дела, там же вызываются теже самые процедуры-функции, которые работают с такими же структурами данных.
Просто компоновка другая + расширение возможностей за счет новых появившихся абстракций и терминов.
Если посмотреть на трассировку выполнения программы в ООП и в процедурном стиле - ничего по факту не меняется - последовательный вызов функций одна за другой и последовательное выполнение кода.
[DOUBLEPOST=1524640444][/DOUBLEPOST]
может писать стихи в коде
Напомнило:
/*
Стихотворение на OpenEdge 4GL
Copyright: (C) 2005 Serguey Klimoff (bulkl0DD)
Filename: POEM.P
Comment: Запускается под PROGRESS v.v.9-10
Parameters:
Uses:
Used by:
Created: 07.03.2005 16:34 ksv
Modified: 07.03.2005 16:37 ksv
Modified:
*/ /* Commented by KSV: Инициализация стихотворения */
DEFINE VARIABLE Eight_March AS DATE NO-UNDO.
DEFINE TEMP-TABLE Our_Women
FIELD xx AS CHAR.
DEFINE TEMP-TABLE Resort
FIELD xx AS CHAR.
DEFINE TEMP-TABLE Your_Work
FIELD xx AS CHAR.
DEFINE TEMP-TABLE the_Beauty_Place
FIELD xx AS CHAR.
DEFINE TEMP-TABLE Another_Face
FIELD xx AS CHAR.

DEFINE VARIABLE All_That AS CHARACTER NO-UNDO.
DEFINE VARIABLE You_Want AS CHARACTER NO-UNDO.
DEFINE VARIABLE the_Sky AS CHARACTER NO-UNDO.
DEFINE VARIABLE Midnight AS HANDLE NO-UNDO.
DEFINE VARIABLE Black_Unix_Screen AS CHARACTER NO-UNDO.
DEFINE VARIABLE ALL_Your_Sorrow AS CHARACTER NO-UNDO.
DEFINE VARIABLE Your_Login AS CHARACTER NO-UNDO FORM "x(40)" LABEL "С 8-м Марта, Милые Женщины! )".
OPEN QUERY Free FOR EACH Our_Women.
FORM the_Sky ALL_Your_Sorrow WITH FRAME xx.
FORM Your_Login WITH FRAME f SIDE-LABELS.
DEFINE VARIABLE Again AS DATE NO-UNDO.
DEFINE VARIABLE We AS LOGICAL NO-UNDO.
DEFINE VARIABLE Should AS LOGICAL NO-UNDO.
DEFINE VARIABLE Say AS LOGICAL NO-UNDO.
DEFINE VARIABLE Your AS LOGICAL NO-UNDO.
DEFINE VARIABLE Cares AS LOGICAL NO-UNDO.
DEFINE VARIABLE The_Dream_Is AS LOGICAL NO-UNDO.


/* Commented by KSV: Стихотворение на PROGRESS 4GL. */
/* Commented by KSV: Женщинам-разработчикам на PROGRESS 4GL посвящается... */
/* Commented by KSV: Мечта */
Eight_March EQ Again. TODAY. /*Сегодня снова 8 марта */
FOR EACH Our_Women: We. Should. Say./*И каждой женщине нам надо сказать: */
DELETE Your_Work. FIND FIRST Resort/*Выкинь всю свою работу и найди для начала курорт, */
WHERE /* You */ CAN-DO(All_That,You_Want) /*где ты можешь делать все что захочешь. */
NO-ERROR. FIND the_Beauty_Place /*Но не ошибись! Найди такое чудесное место */
WHERE NOT CAN-FIND(Another_Face). /*где не будет никого (это мягко сказано ) */
HIDE All_Your_Sorrow. GET FIRST Free. /*Забудь про все свои печали, и стань, наконец, свободной, */
RUN TO_THE_WARM_AND_TENDER_SEA. /*быстрее беги к теплому ласковому морю. */
CLEAR ALL. Your. Cares. VIEW the_Sky. /*Выкинь из головы все свои заботы и посмотри на это прекрасное небо */
WAIT-FOR /* an */ ENTRY OF Midnight. /*Дождись наступления ночи, */
the_Sky EQ Black_Unix_Screen. /*И когда небо станет таким же темным как экран юникса */
The_Dream_Is. END./* Ты поймешь, что сон закончился */
SET Your_Login. /* и пора работать " */


http://www.openedge.ru/read/347
 

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
Если посмотреть на трассировку выполнения программы в ООП и в процедурном стиле - ничего по факту не меняется - последовательный вызов функций одна за другой и последовательное выполнение кода.
Не факт. Взять хотя бы пример из моего недавнего поста (часть 1). Простые числа занимают одномерный массив, а только аллокация объектов - 2 3-хмерных :) Оно и по скорости, о по объему данных в памяти раличается. Я, конечно, понимаю, что на уровне машины различия чуть меньше, но все равно есть. Объект, это априори область в памяти, которая распарсивается при доступе к атрибутам, и методы, наверняка, складируются тоже не как единичное прерывание, а как минимум, дублируется в той же дате объектов дополнительными аллокаторами.
 

Alex_V

Active Member
12 Апр 2017
484
231
43
Я рассматриваю ООП как некий следующий уровень абстракции - развитие процедурно-функциональной парадигмы.
Мне все-таки кажется, что ключевое отличие - наличие в объектных моделях понятия объекта и его состояния. При этом язык вовсе не обязательно должен быть объектно-ориентированным. Вот, например, WinAPI. Там применен вполне объектный подход, но сам API при этом - процедурный.
 
Последнее редактирование:
  • Like
Реакции: pse

buncker

=)
26 Ноя 2002
10.297
4.756
113
44
МО
нормально живут плюсы и в микроконтроллерах
если человек не понимает как работают механизмы языка то ему критические по скорости выполнения или объему кода вещщи ни на каом языке не дано будет реализовать

Одна только инкапсуляция данных и методов \ области видимости данных и методов класса плюс управляемая аллокация памяти (под данные и под код) дают большой выигрышь в скорости написания \ легкости чтения \ правильности структуризации \ общей стабильности архиетктуры и абсолютно нолевые накладные расходы
 

Zildjian

Unreal Member
23 Июл 2011
1.287
553
113
35
Москва
сэмпл гиперсав от вируса длительностью в 1 секунду рисовался около минуты стандартными средствами QT.
"Стандартные средства Qt" (и таки да, он Qt, а не QT) подразумевают как минимум 4 разных способа рендеринга, каким именно вы пользовались? Причем все 4 дают очень хороший результат, как по скорости, так и по качеству рендеринга. Семпл в 1 секунду это максимум 192 тысячи точек, это пшик, там нечему рисоваться минуту. Я рендерю 2D графики похожей детальности в своем проекте, все анимации при зумировании и скролле плавные, рендеринг быстры. Рендерю через QPainter. Что-то не так с вашим кодом.
Но использовать Qt для гуя плагинов это конечно очень странное решение, он хорош для большого кроссплатформенного standalone софта. И да - Qt это далеко не только либа для рисования гуя.


ООП для больших проэктов и чтоб без гемора, но процедурный стиль никуда и никогда не денется, тут уже прийдется выбирать - либо скорость разработки и удобство кода, либо скорость работы конечного продукта
Вновь не понимаю, что что ж вы такое пишете (или на чем выполняете) что у вас классы тормозят работу программы? У меня есть прога целиком на Qt, работающая в реальном времени, рендерящая графику, вытаскивающая данные из других программ, и все это с загрузкой меньше 1% достаточно среднего процессора. И с множественным наследованием, и динамическое аллокацией памяти и даже RTTI. Чот ничего не тормозит.


бсолютно нолевые накладные расходы
Вот-вот
 

Zildjian

Unreal Member
23 Июл 2011
1.287
553
113
35
Москва
Я вот как раз плагинов писать не собираюсь.
А для стандалон софта отличный вариант, особенно если требуется серьезный гуй. Она умеет и в хорошую многопоточность, и кроссплатформенная. Размер либ, которые надо за собой таскать, конечно великоват, особенно если использовать QML, там добавляется куча дополнительных файлов, но для серьезного софта это не проблема.

Скоростью разработки и скоростью выполнения программы я полностью доволен
 

Alex Longard

Well-Known Member
10 Май 2015
1.941
1.232
113
36
München->Deutschland, Київ->Україна
@Zildjian, я писал wt редактор, алгоритмы для отрисовки волны сдернул из игрового движка.
Я ООП по большей части понимал сам, так как в институте мы учили языки с процедурным и функциональным подходом, а на c++ больше времени уделяли разработке алгоритмов и анализ.
Мне проще на чистом C написать изврат со struct чем заморачиватся с классами и продумыванием что будет изолировано а что полиморфным.

PS: кто-то тут на форуме писал что нереально написать vst плагин на асме и без ООП, вот опровержение)))
; //
; // ASMCrusher.asm - VST эффект биткрашер
; // © Кривоус Анатолий Анатольевич (The trick), 2016
; //

format PE GUI 4.0 DLL at 11000000h

include 'include\win32wx.inc'

; // Базовый интерфейс VST эффекта
struct AEEffect
magic dd ?; // Сигнатура 'VstP'
dispatcher dd ?; // Процедура диспечеризации
process dd ?
setParameter dd ?; // Установка параметра
getParameter dd ?; // Получение параметра
numPrograms dd ?
numParams dd ?
numInputs dd ?; // Количество входных каналов
numOutputs dd ?; // Количество выходных каналов
flags dd ?; // Флаги
resvd1 dd ?
resvd2 dd ?
initialDelay dd ?
realQualities dd ?
offQualities dd ?
ioRatio dd ?
object dd ?; // Указатель на объект эффекта
user dd ?
uniqueId dd ?; // Уникальный ИД эффекта
version dd ?; // Версия эффекта
processReplacing dd ?; // Процедура обработки звука
processDoubleReplacing dd ?
future db 56 dup (?)
ends

; // Объект эффекта ASMCrusher
struct ASMCrusher
ae AEEffect ?; // Базовый интерфейс AEEffect
sampleRate dd ?; // Частота дискретизации
volume dd ?; // Громкость 0..1 (0..100%)
downsampling dd ?; // Частота среза 0..1 (0..SampleRate)
quantize dd ?; // Битность 0..1 (2 ^ (value * 15 + 1))
lValue dd ?; // Текущее значение семпла левого канала
rValue dd ?; // Текущее значение семпла правого канала
sampleCounter dd ?; // Счетчик семплов фильтра
ends

NUMBER_OF_PARAMETERS= 3; // Количество параметров эффекта
UNIQUE_ID= 1234567; // Уникальный ИД эффекта
VERSION = 1; // Версия эффекта
PAR_VOLUME= 0; // Индексы параметров ...
PAR_DOWNSAMPLING= 1
PAR_QUANTIZE= 2

kEffectMagic= 0x56737450; // Сигнатура AEEffect
audioMasterVersion= 1; // Версия хоста

; // Максимальные размеры строк
kVstMaxParamStrLen= 8
kVstMaxVendorStrLen= 64
kVstMaxProductStrLen= 64
kVstMaxEffectNameLen= 32

effClose= 1; // Событие вызывается когда эффект уничтожается
effSetSampleRate= 10; // Событие установки частоты дискретизации
effGetParamName = 8; // Событие получения имени параметра
effGetParamLabel= 6; // Событие получения метки единиц измерения параметра
effGetParamDisplay= 7; // Событие получения метки значения параметра
effGetEffectName= 45; // Событие получения имени эффекта
effGetVendorString= 47; // Событие получения имени производителя
effGetProductString= 48; // Событие получения имени продукта
effGetVendorVersion= 49; // Событие получения версии

effFlagsCanReplacing= 16
effFlagsNoSoundInStop= 512

section '.idata' import data readable writeable

library kernel, 'kernel32.dll', \
msvcrt, 'msvcrt.dll'

import kernel,\
GetProcessHeap, 'GetProcessHeap', \
HeapAlloc, 'HeapAlloc', \
HeapFree, 'HeapFree', \
lstrcpynA, 'lstrcpynA'

import msvcrt, \
sprintf, 'sprintf'

data export
export 'AsmCrusher.DLL', Main, 'VSTPluginMain'
end data

section '.reloc' data readable discardable fixups
section '.text' code readable executable

EFFECT_NAME db 'ASMCrusher', 0
VENDOR_NAME db 'Кривоус Анатолий Анатольевич (The trick)', 0
PRODUCT_NAME db 'ASMCrusher', 0
PARAM_NAME_1 db 'Volume', 0
PARAM_NAME_2 db 'Frequency', 0
PARAM_NAME_3 db 'Quantize', 0
PARAM_LABEL_1 db '%', 0
PARAM_LABEL_2 db 'Hz', 0
PARAM_LABEL_3 db 'Levels', 0
PARAM_FORMAT_1 db '%d%%', 0
PARAM_FORMAT_2 db '%dHz', 0
PARAM_FORMAT_3 db '%d', 0

PARAMS_LIST dd PARAM_NAME_1, PARAM_NAME_2, PARAM_NAME_3; // Имена параметров
LABELS_LIST dd PARAM_LABEL_1, PARAM_LABEL_2, PARAM_LABEL_3; // Метки единиц измерения параметров
FORMATS_LIST dd PARAM_FORMAT_1, PARAM_FORMAT_2, PARAM_FORMAT_3 ; // Форматы параметров

entry EntryPoint

; // Точка входа DLL
proc EntryPoint, hinstDLL, fdwReason, lpvReserved
mov eax, 1
ret
endp

; // Выделить память
proc MemAlloc, size
invoke HeapAlloc, <invoke GetProcessHeap>, HEAP_NO_SERIALIZE OR HEAP_ZERO_MEMORY, [size]
ret
endp

; // Освободить память
proc MemFree, pMem
invoke HeapFree, <invoke GetProcessHeap>, [pMem], HEAP_NO_SERIALIZE
ret
endp

; // Вызывается при создании нового экземпляра VST эффекта
proc Main c audioMaster

; // Проверяем версию
cinvoke audioMaster, 0, audioMasterVersion, 0, 0, 0, 0
.if eax = 0
ret
.endif

stdcall CreateASMCrusher

ret

endp

; // Создать объект ASMCrusher
proc CreateASMCrusher uses ebx

stdcall MemAlloc, sizeof.ASMCrusher

.if eax = 0
ret
.endif

mov ebx, eax
lea eax, [ebx + ASMCrusher.ae]

mov [eax + ASMCrusher.ae.magic], kEffectMagic
mov [eax + ASMCrusher.ae.dispatcher], Dispatcher
mov [eax + ASMCrusher.ae.setParameter], SetParameter
mov [eax + ASMCrusher.ae.getParameter], GetParameter
mov [eax + ASMCrusher.ae.processReplacing], ProcessReplacing
mov [eax + ASMCrusher.ae.numInputs], 2
mov [eax + ASMCrusher.ae.numOutputs], 2
mov [eax + ASMCrusher.ae.numParams], NUMBER_OF_PARAMETERS
mov [eax + ASMCrusher.ae.flags], effFlagsCanReplacing OR effFlagsNoSoundInStop
mov [eax + ASMCrusher.ae.uniqueId], UNIQUE_ID
mov [eax + ASMCrusher.ae.version], VERSION
mov [eax + ASMCrusher.ae.object], ebx

; // Загрузка значений по умолчанию
mov [eax + ASMCrusher.sampleRate], 44100
mov [eax + ASMCrusher.volume], 1.0
mov [eax + ASMCrusher.downsampling], 1.0
mov [eax + ASMCrusher.quantize], 1.0
mov [eax + ASMCrusher.lValue], 0.0
mov [eax + ASMCrusher.rValue], 0.0
mov [eax + ASMCrusher.sampleCounter], 0.0

mov eax, ebx

ret

endp

; // Процедура диспетчеризации
proc Dispatcher c, pEffect, uOpcode, uIndex, value, lpPtr, opt

mov ecx, [pEffect]
mov ecx, [ecx + AEEffect.object]

.if [uOpcode] = effClose
; // Удалить VST эффект
stdcall MemFree, ecx
xor eax, eax
.elseif [uOpcode] = effSetSampleRate
; // Установить частоту дискретизации
mov eax, [opt]
mov [ecx + ASMCrusher.sampleRate], eax
xor eax, eax
.elseif [uOpcode] = effGetParamName
; // Получить имя параметра
mov eax, [uIndex]
invoke lstrcpynA, [lpPtr], [PARAMS_LIST + eax * 4], kVstMaxParamStrLen
xor eax, eax
.elseif [uOpcode] = effGetParamLabel
; // Получить имя параметра в окне (надпись)
mov eax, [uIndex]
invoke lstrcpynA, [lpPtr], [PARAMS_LIST + eax * 4], kVstMaxParamStrLen
xor eax, eax
.elseif [uOpcode] = effGetEffectName
; // Получить имя эффекта
invoke lstrcpynA, [lpPtr], EFFECT_NAME, kVstMaxEffectNameLen
xor eax, eax
.elseif [uOpcode] = effGetVendorString
; // Получить имя производителя
invoke lstrcpynA, [lpPtr], VENDOR_NAME, kVstMaxVendorStrLen
xor eax, eax
.elseif [uOpcode] = effGetProductString
; // Получить имя продукта
invoke lstrcpynA, [lpPtr], PRODUCT_NAME, kVstMaxProductStrLen
xor eax, eax
.elseif [uOpcode] = effGetVendorVersion
; // Получить версию
mov eax, VERSION
.elseif [uOpcode] = effGetParamDisplay
; // Получить значение параметра (надпись)
.if [uIndex] = PAR_VOLUME

; // volume * 100
mov eax, 100.0
movd xmm0, eax
mulss xmm0, [ecx + ASMCrusher.volume]
cvtss2si eax, xmm0

cinvoke sprintf, [lpPtr], [FORMATS_LIST + PAR_VOLUME * 4], eax

.elseif [uIndex] = PAR_DOWNSAMPLING

stdcall CalcDownsamplingFreq, [ecx + ASMCrusher.sampleRate], [ecx + ASMCrusher.downsampling]
cinvoke sprintf, [lpPtr], [FORMATS_LIST + PAR_DOWNSAMPLING * 4], eax

.elseif [uIndex] = PAR_QUANTIZE

stdcall CalcLevels, [ecx + ASMCrusher.quantize]
cinvoke sprintf, [lpPtr], [FORMATS_LIST + PAR_QUANTIZE * 4], eax

.endif

xor eax, eax
.else
xor eax, eax
.endif

ret

endp

; // Получить параметр
proc GetParameter c, pEffect, uIndex

mov ecx, [pEffect]
mov ecx, [ecx + AEEffect.object]

.if [uIndex] = PAR_VOLUME
fld [ecx + ASMCrusher.volume]
.elseif [uIndex] = PAR_DOWNSAMPLING
fld [ecx + ASMCrusher.downsampling]
.elseif [uIndex] = PAR_QUANTIZE
fld [ecx + ASMCrusher.quantize]
.else
fldz
.endif

ret
endp

; // Установить параметр
proc SetParameter c, pEffect, uIndex, fValue

mov ecx, [pEffect]
mov ecx, [ecx + AEEffect.object]
mov eax, dword [fValue]

.if [uIndex] = PAR_VOLUME
mov [ecx + ASMCrusher.volume], eax
.elseif [uIndex] = PAR_DOWNSAMPLING
mov [ecx + ASMCrusher.downsampling], eax
.elseif [uIndex] = PAR_QUANTIZE
mov [ecx + ASMCrusher.quantize], eax
.endif

ret

endp

; // Процедура обработки звука, вызывается хостом
proc ProcessReplacing c uses esi edi ebx, pEffect, pInputs, pOutputs, sampleFrames

mov esi, [pInputs]
mov edi, [pOutputs]
mov ebx, [pEffect]
mov ebx, [ebx + AEEffect.object]

; // Обрабатываем левый канал
stdcall ApplyEffectToChannel, ebx, dword [esi], dword [edi], dword [sampleFrames], dword [ebx + ASMCrusher.lValue]
mov [ebx + ASMCrusher.lValue], eax

; // Обрабатываем правый канал
stdcall ApplyEffectToChannel, ebx, dword [esi + 4], dword [edi + 4], dword [sampleFrames], dword [ebx + ASMCrusher.rValue]
mov [ebx + ASMCrusher.rValue], eax

ret

endp

; // Применить эффект к буферу
; // Возвращает значение семпла
proc ApplyEffectToChannel uses esi edi ebx, pObject, pInput, pOutput, nCount, fValue

mov ebx, [pObject]
mov esi, [pInput]
mov edi, [pOutput]

; // Вычисляем количество уровней
stdcall CalcLevels, [ebx + ASMCrusher.quantize]
cvtsi2ss xmm1, eax

; // Вычисляем количество семплов для частоты среза
mov eax, 2.0
movd xmm0, eax
divss xmm0, [ebx + ASMCrusher.downsampling]

; // Восстанавливаем регистр счетчика фильтра
movss xmm2, [ebx + ASMCrusher.sampleCounter]

; // Загружаем граничные значения
mov eax, 1.0
movd xmm3, eax
mov eax, -1.0
movd xmm4, eax

; // Загружаем значение громкости в регистр
movss xmm6, [ebx + ASMCrusher.volume]

; // Загружаем сохраненное значение семпла и применяем уровень громкости
movd xmm5, [fValue]
mulss xmm5, xmm6

; // Задаем количество семплов
mov ecx, [nCount]

; // Проход по семплам
.PROCESS_SAMLE:

; // Увеличиваем счетчик регистра фильтра
addss xmm2, xmm3
comiss xmm2, xmm0
; // Если количество семлов превышает порог, загружаем новый
jb .STORE_SAMPLE

; // Сравниваем с 1
comiss xmm3, dword [esi]
jb .SET_MAX
; // Сравниваем с -1
comiss xmm4, dword [esi]
ja .SET_MIN
movss xmm5, dword [esi]

.CALC_SAMPLE:
; // Сохраняем семп в регистр edx
movd edx, xmm5
; // Вычисляем семпл по формуле int(sample * levels) / levels
mulss xmm5, xmm1
cvtss2si eax, xmm5
cvtsi2ss xmm5, eax
divss xmm5, xmm1

; // Изменяем громкость
mulss xmm5, xmm6
; // Обновляем downsampling регистр
subss xmm2, xmm0

jmp .STORE_SAMPLE

.SET_MAX:
movss xmm5, xmm3
jmp .CALC_SAMPLE
.SET_MIN:
movss xmm5, xmm4
jmp .CALC_SAMPLE

.STORE_SAMPLE:

; // Сохраняем текущий семпл
movss dword [edi], xmm5
add edi, 4
add esi, 4

loop .PROCESS_SAMLE

; // Сохраняем значения
movd [ebx + ASMCrusher.sampleCounter], xmm2

; // Возвращаем значение семпла
mov eax, edx

ret

endp

; // Получить реальную частоту ресемплинга на основании значения downsampling
; // Вычисляем по формуле int(downsampling * samplerate * 0.5)
proc CalcDownsamplingFreq, sampleRate, downsampling

mov eax, 0.5
movd xmm0, eax
mulss xmm0, [downsampling]
mulss xmm0, [sampleRate]
cvtss2si eax, xmm0

ret

endp

; // Посчитать количество уровней сигнала на основании значения quantize
; // Вычисляем по формуле int(2 ^ (quantize * 15 + 1)))
proc CalcLevels, quantize

mov eax, 2
mov ecx, 15.0
movss xmm0, [quantize]
movd xmm1, ecx
mulss xmm0, xmm1
cvtss2si ecx, xmm0
shl eax, cl

ret

endp
 
  • Like
Реакции: SuperDroid

SuperDroid

Well-Known Member
4 Май 2006
1.725
3.396
113
rmmedia.ru
други, всегда интересовало, если приложение не кроссплатформенно, то это просто из-за того, что скомпилировано оно только под одну операционку, для другой операционки код приложения надо лишь перекомпилировать и все, или что-то и в самом коде придется все же переписать?
 

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
@SuperDroid, смотря какой язык и какие библы.
Допустим, питону пох на операционку в большинстве случаев, т.к. изначально линуксового вида команды модуля os или sys на винде и маках работают, согласно ОС. Однако, даже там часто приходится, в зависимости от системы, на которой скрипт запускается что-то менять.
С другими языками как повезет, но в общем случае, портирование требует усилий, иногда очень больших) С другой стороны, можно сразу писать в кроссплатформенном фреймворке, типа тех же Qt и JUCE, и в большей части случаев будет требоваться только перекомпиляция, да.
 
  • Like
Реакции: SuperDroid

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
Я понял, что наступаю второй раз на грабли связной архитектуры, еще раз перечитал про SOLID, и попробовал сделать табличку со всеми атрибутами и методами для разных типов (классов), а потом попробовал для них выделить родителей (справа)
Есть комментарии по архитектуре, может я что-то опять не учитываю?
архитектура данных KSP.jpg

в xls: https://yadi.sk/i/faSiBYJ63UrgeQ
 

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
ухх...ничего не понял из таблицы. Лучше бы диаграмму классов нарисовал в бесплатной Visual Studio например)
Из SOLID самый геморный и трудно понятный для меня - это имхо - это барабары лисков))) Типа, что должна быть возможность вместо суперкласса подставить его наследника без изменения логики работы программы и наследники должны дополнять поведения класса, а не изменять его. Вроде на словах и простых примерах из сети просто (все почему-то приводят классику квадрат и прямоугольник, а в жизни все не так просто оказывается), а на деле не очень, когда коснется именно конкретно реализуемой архитектуры. Можно запросто поломать эту барбару обыкновенным перекрытием метода в подклассе.
 

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
@pse, да я тут уже 5 листов диаграммами изрисовал, все равно лажа получается.
Дочитаю вечерком банду четырех, еще раз попробую.
А вообще у меня такой вопрос с подвохом: а что если строить архитектуру с реализации? Написал реализацию, завернул в интерфейс, написал вторую реализацию, завернул в схожий интерфейс, завернул в родителя?
Или надежнее все-таки просто классы меньше делать и больше компоновать, а идти сверху?
 

Zildjian

Unreal Member
23 Июл 2011
1.287
553
113
35
Москва
заморачиватся с классами и продумыванием что будет изолировано а что полиморфным
ООП это не про продумывание изоляции, а про максимальное переиспользование кода и заворачивание логики работы в черный ящик, при котором для использования извне пофик, как этот черный ящик работает
 
  • Like
Реакции: pse

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
@PianoIst, Даже не знаю, что ответить, так как не разу не системный архитектор)). Думаешь, делаешь реализацию в крупных блоках, потом уменьшаешь уровни абстракции . Потом, по ходу, приходят мысли, как сделать лучше, что можно вынести -> рефактришь свой код. Хорошая мысль может придти вообще в неожиданном месте, например за рулем, стоя в пробке))) в какой-то момент осознаешь - что тот кусок, который тебе казался классным и по месту вчера - сегодня уже кажется чужеродным, например, нарушает принцип S в SOLID (ну или при реализации сталкиваешься с тем, что нужно какой-то кусок переиспользовать, а код не готов к такому повороту)

Иногда наоборот, сначала делаешь низкий уровень абстракции, а потом укрупняешь и встраиваешь.

[DOUBLEPOST=1524913223][/DOUBLEPOST]У кого-то может по-другому в силу своего опыта, у меня так получается. Делая новый проект, очень много рефакторю.
Тут должна быть еще интуиция - нужно предугадать как код может меняться в будущем, наскольлко масштабируема получается система. Где-то читал про правило - 80% кода пишешь покрывая текущие потребности - 20% - задел на будущее, на расширение, чтобы потом тупиком не было. Грамотно спроектированную систему имхо при возникновении новых требований достаточно несильно подрефачить для того, чтобы она начала удовлетворять новым дополнительным требованиям и при этом не сваливаться в неуправляемое нечто с ошибками по уже реализованному функционалу.
 
Последнее редактирование:
  • Like
Реакции: PianoIst

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
Если у тебя есть уже какой-то код - то это хорошо, нужно только подумать, как завернуть его. Причем в нашем деле я допустим начинаю воздерживаться от слова "правильно". Кто знает как правильно сделать? Да никто. Есть очень много разных мнений, чего делать, чего не делать. Как лучше сделать, как хуже. Но они остаются лишь мнениями, с которыми кто-то согласен или не согласен, не больше того.
Вот такой вот момент: допустим, у нас на работе периодически проходят тестирование разработчиков. Всем выдается одинаковое задание, потом через неделю, другую, забирают результаты и смотрят. Так вот, при том, что задание дается вполне конкретное, но без технических заморочек, еще ни один разработчик не повторился в реализации, если явно не сдирал у соседа (мне было интересно, и я смотрел потом результаты). Вот так вот - каждый понимает задание по своему в силу своего уникального опыта разработки и знаний.
 
  • Like
Реакции: PianoIst

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
@PianoIst, Попробуй применять I и D в SOLID. Но опять таки принцип I гласит, что "много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения". С этим согласен, но тут возникает другая проблема - взрыв интерфейсов, когда их становится настолько много, что просто начинаешь в них путаться. Нужен какой-то компромисс между дроблением и укрупнением интерфейсов. А четкой грани нет.
 
  • Like
Реакции: PianoIst

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
Принцип L в SOLID можно обходить(формально), делая запечатанные (sealed)/финальные (final) классы и наследуясь с абстрактных. Но следует помнить, что любое внесение изменений в такой абстрактный класс (особенно если класс на продакшене уже вышел) повлечет (может повлечь) за собой изменение в работе всех наследников. По идее, это прикроют юниттесты, если они (нормально) написаны. Но четкой грани, что есть нормально, а что нет - нет.
[DOUBLEPOST=1524916226][/DOUBLEPOST]@PianoIst, Да и вообще, систему, если это не программа в стиле Hello World, полностью соответствующую SOLID имхо построить очень сложно (может и невозможно). Всегда где-то есть отступление от того или иного принципа., это всегда какие-то компромиссы.
 
  • Like
Реакции: PianoIst

Alex_V

Active Member
12 Апр 2017
484
231
43
ООП это не про продумывание изоляции, а про максимальное переиспользование кода
ООП замечательно может существовать вообще без code reuse. Мало того, вполне имеются объектные модели, где это невозможно. Вот как по мне лично, ключевые особенности объектных моделей - объекты с состояниями и полиморфизм. Остальное может быть полезным дополнением. А может и вовсе отсутствовать.


Всегда где-то есть отступление от того или иного принципа., это всегда какие-то компромиссы.
Любые подходы, как бы они там ни назывались, SOLID или еще там как-то, не должны превращаться в догмы. Это просто наборы некоторых принципов, которым можно следовать, а можно и нет. В любом случае, это не стоит делать слепо.
 
  • Like
Реакции: pse и Zildjian

Zildjian

Unreal Member
23 Июл 2011
1.287
553
113
35
Москва
ООП замечательно может существовать вообще без code reuse
Естественно, core reuse это не условие, а приятный бонус.

Вот как по мне лично, ключевые особенности объектных моделей - объекты с состояниями и полиморфизм
Вот полиморфизмом пользуюсь крайне редко. А объекты с состояниями да - это ключевая фишка.

Это просто наборы некоторых принципов, которым можно следовать, а можно и нет. В любом случае, это не стоит делать слепо.
Плюсмнога
 

pse

Active Member
21 Сен 2003
911
179
43
44
Белгород, Алматы
В любом случае, это не стоит делать слепо.
Согласен +100500, но и пренебрегать ими тоже чревато последствиями. Чтобы воспользоваться любым из них - нужно пропустить через себя то, что каждый принцип проповедует. Тогда не просто сможешь слепо следовать, но и грамотно объяснить, почему здесь вот так, а не иначе, а тут вот так)
 

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
немного ночного юмора:
Код:
Traceback (most recent call last):
  File "E:\progr\PyKSP\tests\test_datatypes.py", line 166, in test_properties
    bad_obj = badCallableA()
  File "E:\progr\PyKSP\datatypes.py", line 115, in __init__
    can not be overloaded. If You have, You have broken the class')
datatypes.GetYourNastyHandsOffError: __call__ method of callable object can not be overloaded. If You have, You have broken the class
 

EUGEN27771

Well-Known Member
23 Апр 2010
2.293
1.995
113
@PianoIst,
А что-где поискать про реализацию кучи своими руками?
Сейчас я задумался о реалиации динамической памяти. Но, коль таковой изначально в KSP не предусмотрено, надо (хотя я уже задумываюсь, надо ли) изобретать велосипед. И нашел пару статей про совсем машинные реализации, но чет пока переваривать сложно. Может есть уже какие реализации, или алгоритмы, человечески описанные?
Случайно наткнулся на тему. Верно ли я понимаю, что ситуация примерно такая - имеется кусок локальной памяти.
Вы хотите использовать его как кучу, и для этого нужен менеджер кучи. То есть, на уровне скрипта нужно обеспечить выделение и перераспределение участков памяти из этого конкретного куска. В eel была такая ситуация, если помните - там один кусок памяти, даже массивов как таковых нет. И вот именно по такой схеме все стало выглядеть гораздо веселей. Нужны ф-и malloc(), free(), realloc() - названия по аналогии с си-шными, хотя это неважно.
 

PianoIst

Well-Known Member
19 Май 2010
4.091
4.143
113
29
Kirchberg, kreis Zwickau
soundcloud.com
@EUGEN27771, совершенно правильно понимаете :) Пока я эту идею отложил в очень долгий ящик, пытаюсь реализовать хотя бы базовый статический функционал. Как раз пост пишу с вопросом по конкретному фрагменту.
И вот именно по такой схеме все стало выглядеть гораздо веселей
По такой схеме конечно веселей, хотя суть, в принципе не меняется, только для работы с массивами еще несколько условий в функции надо будет добавлять.
 

Сейчас онлайн (Пользователей: 0, Гостей: 1)