(c) Иван Рощин, Москва ZXNet : 500:95/462.53 E-mail: bestview@mtu-net.ru WWW : http://www.ivr.da.ru Изменение порядка каналов в модулях Impulse Tracker ═══════════════════════════════════════════════════ Введение ──────── Иногда бывает надо изменить порядок каналов в музыкальном модуле, написанном в Impulse Tracker, - например, чтобы каналы с одним инструментом располагались рядом для облегчения последующего редактирования. Но в самом Impulse Tracker нет удобного способа это сделать. Можно, конечно, добиться нужного результата с помощью копирования блоков, но это большой объём ручной работы. Я пробовал найти в Интернете готовую программу для изменения порядка каналов в it-файлах или хотя бы упоминание о ней. Увы, безуспешно - хотя, например, для xm-файлов (Fast Tracker) такая программа была обнаружена. Ничего не оставалось, как написать программу самому. :) До этого мне уже приходилось изучать формат модулей IT, когда я писал конвертор Pro Tracker 3 -> Impulse Tracker, так что задача не показалась сложной. Текст программы ─────────────── /* ============================= File: "reord_it.c" Compiler: Turbo C 2.0 ============================= */ #include #include #include #define byte unsigned char /* 1 байт. */ #define word unsigned int /* 2 байта. */ /* ==================== Описание функций ==================== */ int get_new_order (char* s); int read_2 (char** s, int* n1, int* n2); FILE* fopen_1 (char* name, char* mode); void fclose_1 (FILE* f); int fgetc_1 (FILE* f); void fputc_1 (int c, FILE* f); void fseek_1 (FILE* f, long offset, int whence); /* ======================= Переменные ======================= */ int new_order[64]; /* Для каждого канала здесь хранится его новый номер. */ byte pan_vol_old[128]; /* Массивы со старыми и новыми */ byte pan_vol_new[128]; /* значениями начальной панорамы */ /* и громкости каналов. */ /* ================== Пошла сама программа ================== */ int main (int argc, char *argv[]) { FILE *f_src; int i,j; printf ("\n\ ┌──────────────────────────────────────────────────────────┐\n\ │Program for reordering channels in Impulse Tracker modules│\n\ │(c) Ivan Roshin, Moscow, 18 Jul 2004 │\n\ │E-mail: bestview@mtu-net.ru WWW: http://www.ivr.da.ru│\n\ └──────────────────────────────────────────────────────────┘\n\ "); if (argc!=3) { printf ("\n\ Syntax: reord_it.exe NewChannel=OldChannel,... it-file\n\n\ Example: for swap channels 2 and 5, and swap channels 1 and 3\n\ in it-file 'demo.it', type:\n\n\ reord_it.exe 2=5,5=2,1=3,3=1 demo.it\n\n"); exit(1); } /* Обрабатываем указанный в командной строке аргумент, определяющий новый порядок расположения каналов. */ if (get_new_order(argv[1])) {printf ("\nIncorrect argument!\n\n"); exit (1);} /* Открываем исходный файл. */ f_src=fopen_1(argv[2],"rb+"); printf ("File: %s ",argv[2]); /* =================== Создание bak-файла =================== */ { FILE *f_bak; char name_bak[13]; /* Формируем имя bak-файла из имени исходного файла. */ i=0; while (!((argv[2][i]=='.')||(argv[2][i]==0))) { name_bak[i]=argv[2][i]; i++; if (i>8) {printf ("\nIncorrect file name!\n\n"); exit (1);} } strcpy(name_bak+i,".bak"); /* Копируем содержимое исходного файла в bak-файл. */ f_bak=fopen_1(name_bak,"wb"); while ((i=fgetc_1(f_src))!=EOF) fputc_1 (i,f_bak); fclose_1(f_bak); } /* =================== Обработка it-файла =================== */ /* Проверка сигнатуры: первые 4 байта - "IMPM". */ { byte signature[4]; fseek_1 (f_src,0L,SEEK_SET); if (fread(&signature,(size_t)4,1,f_src)!=1) {printf ("\nRead error!\n\n"); exit (1);} if (strncmp(signature,"IMPM",(size_t)4)!=0) {printf ("\nIncorrect file format!\n\n"); exit (1);} } /* Читаем начальные значения панорамы и громкости каналов, меняем их порядок в соответствии с массивом new_order и записываем обратно. */ fseek_1 (f_src,0x40L,SEEK_SET); if (fread(&pan_vol_old,(size_t)128,1,f_src)!=1) {printf ("\nRead error!\n\n"); exit (1);} for (i=0;i<64;i++) { pan_vol_new[new_order[i]-1]=pan_vol_old[i]; /* Panning */ pan_vol_new[new_order[i]-1+64]=pan_vol_old[i+64]; /* Volume */ } fseek_1(f_src,0x40L,SEEK_SET); if (fwrite(&pan_vol_new,(size_t)128,1,f_src)!=1) {printf ("\nWrite error!\n\n"); exit (1);} /* Обработка паттернов. */ { word OrdNum; /* Кол-во позиций. */ word InsNum; /* Кол-во инструментов. */ word SmpNum; /* Кол-во сэмплов. */ word PatNum; /* Кол-во паттернов. */ long current_p; /* Смещение до текущего паттерна. */ word rows; /* Кол-во строк в текущем паттерне. */ fseek_1(f_src,0x20L,SEEK_SET); OrdNum=fgetc_1(f_src); OrdNum|=fgetc_1(f_src)<<8; InsNum=fgetc_1(f_src); InsNum|=fgetc_1(f_src)<<8; SmpNum=fgetc_1(f_src); SmpNum|=fgetc_1(f_src)<<8; PatNum=fgetc_1(f_src); PatNum|=fgetc_1(f_src)<<8; for (i=0;i