Синтезаторы цифровой музыки.
я думаю, целая музыкальная сцена была затронута доступностью дешевых полифонических синтезаторов. Ранние полифонические синтезаторы, где эффективно несколько аналоговых синтезаторов (дискретный или использующий CEM или микросхемы SSM). Они были и дорогими и очень liited. В течение 80-х первые цифровые системы прибыли (я не уверен, но я думаю, что Kurzweil был одним из первых). Сегодня, главным образом все являются цифровыми - даже аналоговые обычно являются "виртуальным anlog".
отношения
РЕДАКТИРОВАНИЕ: ой - я просто узнал, что CMI fairlight был изобретен в 1978. Поэтому забудьте вышеупомянутое - извините.
Используйте метапрограмму шаблона. (Отредактировано в ответ на комментарий).
#include <iostream>
#include <ostream>
using namespace std;
template <int N>
struct P
{
enum { val = P<N/2>::val * 2 };
};
template <>
struct P<0>
{
enum { val = 1 };
};
template <class T>
struct PadSize
{
enum { val = P<sizeof (T) - 1>::val - sizeof (T) };
};
template <class T, int N>
struct PossiblyPadded
{
T payload;
char pad[N];
};
template <class T>
struct PossiblyPadded<T, 0>
{
T payload;
};
template <class T>
struct Holder : public PossiblyPadded<T, PadSize<T>::val>
{
};
int main()
{
typedef char Arr[6];
Holder<Arr> holder;
cout << sizeof holder.payload << endl;
// Next line fails to compile if sizeof (Arr) is a power of 2
// but holder.payload always exists
cout << sizeof holder.pad << endl;
}
Вероятно, наиболее очевидным способом было бы просто использовать тернарный оператор:
#define LOG2_CONST(n) ((n) <= 1 ? 0 :
((n) <= 2 ? 1 :
((n) <= 4 ? 2 :
/* ... */
))))))))))))))))))))))))))))))
#define PADDED_STRUCT(ResultName, BaseName) \
typedef union { BaseName data; char pad[1 << LOG2_CONST(sizeof(BaseName))]; } ResultName
Почему бы не использовать объединение?
union Message
{
struct internal_
{
unsigned long member1;
/* more members */
};
char[64];
};
или еще лучше использовать анонимные структуры
union Message
{
struct
{
unsigned long member1;
/* more members */
};
char[64];
};
Таким образом, вы можете получить доступ к членам следующим образом: Message.member1;
Изменить: очевидно, это не решает вашу проблему больше 64, но обеспечивает более чистый способ заполнения.
Вы уже используете #pragma pack
, я не знаю, какой компилятор (ы) вы используете конкретно, но вы должны посмотреть, поддерживают ли они аргументы для пакета, который контролируйте выравнивание / заполнение, а затем вы можете просто полностью избавиться от поля заполнения. Я знаю, что MSVC версия пакета прагм
поддерживает это, как и GCC .
Одним из способов решения проблемы было бы заменить жестко запрограммированный 64 с кратным размеру (длинным), превращая заполнение примерно в следующее:
char pad[4*sizeof(unsigned long) - sizeof(internal_)];
Это некрасиво, но должно быть переносимым на 64-битные.
Тем не менее, API, который требует, чтобы размер сообщения был мощным из 2 звучит немного странно и похоже на проблему дизайна. Требовать, чтобы размер был четным числом, имеет смысл, поскольку на некоторых процессорах взимается штраф за доступ к данным по нечетным адресам, но ваш пакет #pragma почти делает это неизбежным.
Вы можете макрос это следующим образом (для 32-битной архитектуры):
#define align_step(N, shift) ((N) | ((N) >> shift))
#define align_up(N) (align_step(align_step(align_step(align_step(align_step((N)-1, 1), 2), 4), 8), 16) + 1)
#define alignment_padding(N) (align_up((N)) - (N))
Затем вы можете применить это, используя уловку объединения или другие средства. В вашем примере:
#pragma pack(1)
struct Message
{
struct internal_
{
unsigned long member1;
unsigned long member2;
unsigned long member3;
/* more members */
} internal;
char pad[alignment_padding(sizeof(internal_))];
};
#pragma pack()
Как насчет того, чтобы просто написать небольшую оболочку вокруг функции отправки и получения сообщения, которая обрабатывает сообщение любого размера, и они просто выделяют больший буфер (следующая степень 2) и очищают его, скопируйте структуру в начало и отправьте его вместе.
Вы можете получить константу времени компиляции для размера структуры, округленную до степени двойки, используя шаблоны:
template<int N, int C = 1>
struct Recurse
{
enum {result = Recurse<N/2, C*2>::result};
};
template<int C>
struct Recurse<0, C>
{
enum {result = C};
};
template<typename T>
struct Calc
{
enum {size = Recurse<sizeof(Test)-1>::result};
};
struct Test
{
int a;
double b;
double c;
};
int main()
{
std::cout << sizeof(Test) << " -> " << Calc<Test>::size << std::endl;
return 0;
}
Тогда значение заполнения должно быть простым.
union Message
{
struct
{
unsigned long member1;
unsigned long member2; //...
};
char pad[1 << 5]; //change 5 to whatever size you need...
};
Было бы немного чище.
Мне нравится ответ Ники , особенно часть с анонимными структурами.
Единственное, что не удалось решить, - это проблема с размером более 64 байтов, но это можно решить, условно объявив элемент структуры char
if sizeof (long) == 8 и объявив char [64] в противном случае.
Хорошо, я нашел ответ, который действительно искал. По сути, вам нужно вызвать LocalFileSettingsProvider.Upgrade. Однако, поскольку я буду развертывать с помощью ClickOnce, он сделает это за вас автоматически.
Q: Хорошо, но как мне узнать, когда вызывать Upgrade?
A: Хороший вопрос. В Clickonce, когда вы устанавливаете новую версию своего приложения, ApplicationSettingsBase обнаружит ее и автоматически обновит настройки для вас в момент загрузки настроек. В случаях, не связанных с Clickonce, автоматическое обновление отсутствует - вам нужно вызвать обновление самостоятельно. Вот одна идея для определения, когда вызывать Upgrade:
Имейте логическую настройку CallUpgrade и присвойте ей значение по умолчанию true. Когда ваше приложение запустится, вы можете сделать что-то вроде: