Registrarse

[pokeemerald] Añadiendo MIDIs: Paso a paso

Zvleon

Usuario de oro
Primero que todo, quiero dejar claro unos puntos importantes:
  • En este tutorial no se va a explicar como arreglar MIDIs o que programas utilizar. Se asume que el lector tiene el MIDI listo para ser insertado.
  • No manejo toda la información del tema, pero el plan es darle soporte e ir actualizando a medida que descubra más cosas o por ciertas actualizaciones de pokeemerald algunos pasos dejen de funcionar.
  • Es mi primer post en el foro, y tampoco es que sea experto en el tema, así que probablemente se me van a pasar cosas por alto o diré cosas erradas. Pido paciencia (?)
  • Si, soy Trickster :^)
Teniendo esos puntos en claro, podemos partir.

Paso 0: Nociones básicas

Es importante tener en cuenta como funcionan los instrumentos en un MIDI:
  • Los instrumentos se encuentran en un banco de instrumentos que está asociado a lo que sea que está reproduciendo el MIDI (véase FL Studio o el mismo reproductor multimedia de Windows) y normalmente estos están ordenados. Por ejemplo, los primeros 20 son instrumentos de tecla, como pianos, órganos, xilófonos, etc. Los bronces y vientos están entre el 56-79 y así.
  • Cada canal/track del MIDI tiene asociado un instrumento o voz, y esta voz puede cambiar en el transcurso de la canción mediante eventos. Por ejemplo, el track de la bassline puede ir alternando entre pick bass y slap bass. Esto escapa al alcance del tutorial, pero creo que es importante tenerlo en cuenta.
Paso 1: Ubicar el MIDI
Para esto basta con agarrar el MIDI y copiarlo en ./sound/songs/midi. Aunque esto no basta para hacerlo funcional en el juego.​
Paso 2: Reportarle al compilador la existencia del archivo
En la carpeta raíz de pokeemerald se encuentra el archivo songs.mk.Para poder definir el MIDI dentro del archivo seguimos la siguiente estructura:​
Makefile:
$(MID_SUBDIR)/nombre_midi.s: %.s: %.mid[/INDENT][/INDENT]
[INDENT][INDENT](MID) $< $@ -E -R$(STD_REVERB) -GXXX -V090
Donde GXXX corresponde al VOICEGROUP que usará la canción. Algunos se preguntarán ¿Que es el voicegroup? Lo veremos en siguiente punto pero básicamente, es como el banco de instrumentos que mencionamos en el paso 0.​
Paso 3: Definir el VOICEGROUP

El voicegroup como se mencionó antes, es una suerte de banco de instrumentos, solo que este no los contiene, es una referencia. La manera en la que se define es la siguiente: Si en mi MIDI usé el instrumento 17(Percussion Organ) entonces tengo que definirlo en el slot 17 del voicegroup.​
Pro Tip: Si editan esto con cualquier editor de texto somo Sublime Text o VS Code, entonces toman el ID en el banco de instrumentos (en este caso, el 17) y le suman 3. El resultado representa el número de línea en el editor de texto donde debería ir Percussion Organ.
A continuación les dejo un ejemplo de voicegroup que podrían usar ustedes. Contiene la mayoría de los instrumentos disponibles en el juego.​
Enriquecido (Código BB):
.align 2
voicegroup196:: @ 86A8CBC
    voice_keysplit_all voicegroup002  @ 86A8CBC
    voice_keysplit voicegroup005, KeySplitTable1  @ 86A8CC8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8CD4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8CE0
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_detuned_ep1_low, 255, 249, 0, 165  @ 86A8CEC
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_detuned_ep1_high, 255, 188, 103, 165  @ 86A8CF8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D04
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D10
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D1C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D28
    voice_directsound 60, 0, DirectSoundWaveData_heart_of_asia_gamelan, 255, 188, 139, 239  @ 86970E8
    voice_directsound 60, 0, DirectSoundWaveData_sc88_glockenspiel, 255, 188, 103, 165
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D4C
    voice_directsound 60, 0, DirectSoundWaveData_sc88_xylophone, 255, 188, 103, 165
    voice_directsound 60, 0, DirectSoundWaveData_sc88_tubular_bell, 255, 165, 90, 216  @ 86A8D64
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D70
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D7C
    voice_directsound 60, 0, DirectSoundWaveData_sc88_organ2, 255, 0, 255, 127  @ 86A8D88
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8D94
    voice_directsound 60, 0, DirectSoundWaveData_emu_ii_pipe_organ, 255, 188, 103, 165
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8DAC
    voice_directsound 60, 0, DirectSoundWaveData_sc88_accordion, 255, 188, 103, 165
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8DC4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8DD0
    voice_directsound 60, 0, DirectSoundWaveData_sc88_nylon_str_guitar, 128, 249, 25, 127  @ 86A8DDC
    voice_directsound 60, 0, DirectSoundWaveData_sc88_nylon_str_guitar, 255, 165, 128, 204  @ 86A8DE8
    voice_directsound 60, 0, DirectSoundWaveData_unused_electric_guitar, 255, 165, 128, 204  @ 86A8DE8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E00
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E0C
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_overdrive_guitar, 255, 0, 255, 127  @ 86A8E18
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_distortion_guitar_high, 255, 165, 154, 165  @ 86A8E24
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E30
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E3C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E3C
    voice_directsound 60, 0, DirectSoundWaveData_sc88_fretless_bass, 255, 255, 0, 200
    voice_directsound 60, 0, DirectSoundWaveData_sc88_fretless_bass, 255, 255, 0, 200
    voice_directsound 60, 0, DirectSoundWaveData_jv1080_slap_bass, 255, 224, 0, 204
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E78
    voice_directsound 60, 0, DirectSoundWaveData_sc88_synth_bass, 255, 165, 128, 204
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E90
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8E9C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8EA8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8EB4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8EC0
    voice_directsound 60, 0, DirectSoundWaveData_sc88_pizzicato_strings, 255, 165, 128, 204
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8ED8
    voice_directsound 60, 0, DirectSoundWaveData_sc88_harp, 255, 165, 128, 204
    voice_directsound 60, 0, DirectSoundWaveData_sc88_timpani, 255, 246, 0, 226  @ 86A8EF0
    voice_keysplit voicegroup006, KeySplitTable2  @ 86A8EFC
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F08
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F14
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F20
    voice_directsound 60, 0, DirectSoundWaveData_classical_choir_voice_ahhs, 255, 246, 0, 226
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F44
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F44
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F50
    voice_keysplit voicegroup007, KeySplitTable3  @ 86A8F5C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F68
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F74
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F80
    voice_keysplit voicegroup009, KeySplitTable5  @ 86A8F8C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8F98
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_distortion_guitar_low, 255, 165, 180, 165  @ 86A8FA4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FB0
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FBC
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FC8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FD4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FE0
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FEC
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A8FF8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9004
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9010
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A901C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9028
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9034
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9040
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A904C
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_shakuhachi, 255, 246, 0, 226
    voice_directsound 60, 0, DirectSoundWaveData_sd90_classical_whistle, 255, 246, 0, 226
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9070
    voice_square_1_alt 0, 1, 0, 2, 7, 2  @ 86A907C
    voice_square_2_alt 3, 0, 3, 6, 2  @ 86A9088
    voice_square_2_alt 3, 0, 2, 6, 5  @ 86A9094
    voice_programmable_wave_alt ProgrammableWaveData_86B4890, 0, 3, 6, 5  @ 86A90A0
    voice_square_2_alt 0, 0, 2, 6, 5  @ 86A90AC
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A90B8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A90C4
    voice_programmable_wave_alt ProgrammableWaveData_86B4850, 0, 7, 15, 1  @ 86A90D0
    voice_programmable_wave_alt ProgrammableWaveData_86B4830, 0, 7, 15, 0  @ 86A90DC
    voice_programmable_wave_alt ProgrammableWaveData_86B4910, 0, 1, 9, 2  @ 86A90E8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A90F4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9100
    voice_square_2_alt 2, 0, 2, 6, 3  @ 86A910C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9118
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9124
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9130
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A913C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9148
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9154
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9160
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A916C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9178
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9184
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9190
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A919C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91A8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91B4
    voice_directsound 60, 0, DirectSoundWaveData_unknown_koto_high, 255, 246, 0, 226
    voice_directsound 60, 0, DirectSoundWaveData_unknown_koto_low, 255, 246, 0, 226
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91D8
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91E4
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91F0
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A91FC
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9208
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9214
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9220
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A922C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9238
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9244
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9250
    voice_directsound 60, 0, DirectSoundWaveData_sd90_special_scream_drive, 255, 0, 255, 165  @ 86A925C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9268
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9274
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9280
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A928C
    voice_square_1 0, 2, 0, 0, 15, 0  @ 86A9298
    voice_noise_alt 0, 0, 2, 6, 2  @ 86A92A4
    voice_noise_alt 0, 0, 1, 6, 0  @ 86A92B0
Aquí defini el voicegroup196.inc o G196. Estos archivos están ubicados en ./sound/voicegroups/. Este es un archivo conformado solo por macros que siguen la siguiente estructura:​
Enriquecido (Código BB):
    .macro voice_directsound base_midi_key, pan, sample_data_pointer, attack, decay, sustain, release
    .byte 0
    _voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
    .endm

    .macro voice_directsound_no_resample base_midi_key, pan, sample_data_pointer, attack, decay, sustain, release
    .byte 8
    _voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
    .endm

    .macro voice_directsound_alt base_midi_key, pan, sample_data_pointer, attack, decay, sustain, release
    .byte 16
    _voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
    .endm

    .macro _voice_directsound base_midi_key, pan, sample_data_pointer, attack, decay, sustain, release
    .byte \base_midi_key
    .byte 0
    .if \pan != 0
    .byte (0x80 | \pan)
    .else
    .byte 0
    .endif
    .4byte \sample_data_pointer
    .byte \attack
    .byte \decay
    .byte \sustain
    .byte \release
     .endm
Los más importantes son voice_directsound y voice_keysplit_all. Donde el primero permite cargar un instrumento, como​
DirectSoundWaveData_sc88_fretless_bass o DirectSoundWaveData_sd90_classical_overdrive_guitar, mientras que el segundo permite agarrar múltiples samples y asociarlos a una nota. Esto se utiliza particularmente para la batería, la cual esta conformada por distintos samples como el snare o el hi-hat. Personalmente no se si sea prudente entrar en detalles con esto porque no lo entiendo del todo, pero voicegroup002 siento que es un buen ejemplo si desean entenderlo.

Edit(25/09/2020): A pedido de Jaizu voy a ahondar un poco más en esto para que se entienda mejor. Como ejemplo tomaré a voice_direct_sound pues como dije previamente no tengo mucho manejo con los otros:
  • base_midi_key: Este parámetro representa la tonalidad base del sample utilizado como instrumento. Por ejemplo, si un instrumento tiene este parámetro como 60, significa que su nota base es un DO de la quinta octava. Una octava tiene 7 notas naturales y 5 semitonos (para los que no entienden de esto, las notas naturales son las blancas de un piano, mientras que los semitonos son las negras) así que tomando el DO de la primera octava como el valor inicial y ahora sabiendo que cada octava tiene 12 notas en total, entonces tenemos 60/12 = 5 lo que corresponde a la quinta octava previamente mencionada.
    ¿Cuál es la utilidad de esto? Muchas veces los samples no vienen grabados en la nota Do, que es lo normal, así que hay que "transponer" la nota para que suene como corresponda, así que este parámetro en términos simples "afina" el instrumento.
  • pan: En los MIDIs, el pan corresponde a por donde sale el audio. Si el valor está en el rango de los negativos, significa que se escuchará más fuerte por el speaker izquierdo, y si está en el rango positivo, por el derecho. Este es un truquillo que permite darle más textura y dinamismo a una canción. Claramente esto es algo que se debe tocar en el MIDI, no en la configuración del sample. Es mejor dejarlo seteado en 0.
  • sample_data_pointer: Este indica el instrumento que se utilizará en este banco del voicegroup. Si queremos usar una trompeta, entonces buscamos el nombre del sample y lo insertamos aquí, el cual sería DirectSoundWaveData_sc88_trumpet_72. Ahora bien, la trompeta es uno de esos instrumentos que utiliza el keysplit. Esto está definido en el voicegroup007, así que como recomendación, si quieren usar trompetas, entonces usen voice_keysplit voicegroup007, KeySplitTable3.
  • attack, decay, sustain y release: Estos parámetros corresponden a como el sample "toca" las notas. Con esto me refiero a la intensidad base, a cuanto se demora en sonar o cuando dejará de hacerlo. No me he metido mucho con ésto, así que personalmente recomiendo ir viendo otros voicegroups que utilicen el mismo instrumento que quieran usar y copian estos parametros.
Una cosa importante que hay que dejar en claro en este punto es que, tal y como se mencionó en puntos previos, los bancos de MIDIs suelen tener 128 instrumentos, pero este no es el caso de pokeemerald. Instrumentos como Music Box, Pipe Organ o Acoustic Bass no existen, razón por la cual existen espacios en blanco en forma de voice_square en el voicegroup. Tal vez alguno se preguntará si es posible añadirlos, y si, lo es. He agregado algunos samples adicionales pero necesito aprender algunas cosas extra como por ejemplo: loopear dichos samples para que funcionen como deben, así que de momento, no tengo planes de explicarlo.​
Dejando todo eso de lado, una vez tengan listo su voicegroup tienen que incluirlo en la lista de todos los voicegroups que existen en el juego. Esto se encuentra en sound/voice_groups.inc

Paso 4: Darle a la canción un ID y un nombre
Cada canción debe tener un ID, el cual es utilizado parámetro por las funciones que reproducen la canción. Esto se hace en el archivo include/constants/songs.h. En cuanto al nombre, nos vamos a sound/song_table.inc. Por consistencia, debe ser el mismo nombre utilizado en songs.mk

Paso 5: Definir la ruta
Al igual que todos los archivos que existen en el juego, tienen que ser definidos en ld_script.txt para que el compilador pueda dar con ellos. Así que en el bloque de song_data debemos agregar la siguiente linea:​
Enriquecido (Código BB):
 sound/songs/midi/nombre_midi.o(.rodata);

Con todo esto su MIDI ya debería estar listo y podrán compilar sin problemas. Si siguieron todo como corresponde, la canción debería poder usarse desde Porymap o ser cambiada en batallas también. Adjunto algunos ejemplos de cosas que he hecho con esto:



Espero que el tutorial sea de utilidad para alguien y que el Jaizu me deje en paz con los MIDIs. Trataré de estar atento por si me falta algo o si alguien no entiende algo
 
Última edición:

Zvleon

Usuario de oro
He actualizado el tutorial para ahondar un poco más en los voicegroups. Espero sea de utilidad.
 

TJLoyd

Pequeño saltamontes
I was wondering if you could add the tutorial for that music player that you're using in the video and can you use it while also playing through the game?
 

Zvleon

Usuario de oro
I was wondering if you could add the tutorial for that music player that you're using in the video and can you use it while also playing through the game?
I have no plans to make a tutorial for that menu anytime soon. It's part of my personal project and one of his "special features", but i'm gonna release the source code eventually.
 

Jack Johnson

Hoenn Adventures Dev
Miembro del equipo
Administrador
¿Cómo habría que crear el bucle? ¿Hay que hacerlo a posteriori como en binario o metiéndolo como un MIDI normal serviría?

Edito: Al abrir los MIDI vanilla he visto que el sistema es el mismo. Crear marcadores con Anvil Studio así: [ bucle ].
 
Última edición:

Zvleon

Usuario de oro
¿Cómo habría que crear el bucle? ¿Hay que hacerlo a posteriori como en binario o metiéndolo como un MIDI normal serviría?

Edito: Al abrir los MIDI vanilla he visto que el sistema es el mismo. Crear marcadores con Anvil Studio así: [ bucle ].
Basta con hacer el loop con los marcadores de Anvil Studio. Las herramientas de compilación hacen el trabjo
 
Arriba