Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Pretty much, I've got some wave files for wave, drum and base that I want to use as a background theme for a game I'm working on.
How do I convert them into hex or whatever it is I need to do and get them into my project?
Offline
What audio engine are you using ?
Offline
actually I had done it on an old Yamaha keyboard then transcribed it to 8bit using Audacity, however that's been put out the window. I have coded a tune, the next step for me is working out how to pretty much multithread so that the song plays in the background while your doing other stuff. So for example, how would I press SELECT half way through the song causing the game to stop the song and exit the menu. Here is the code:
while(looping1 != loops1){
looping1 = looping1 + 1;
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
//square 1 (NR10-14)
NR10_REG = 0x00;
NR11_REG = 0x00;
NR12_REG = 0xAA;
NR13_REG = 0x00;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x22;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x55;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x33;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x00;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x33;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x22;
NR14_REG = 0x87;
delay(tempo1);
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x00;
NR14_REG = 0x87;
delay(tempo1);
}
Last edited by jobalisk (2017-10-04 20:27:59)
Offline
Ok, I actually fixed this in the end using some rather cunning code I cooked up myself, works perfectly:
unsigned int MusicLooper = 0; //where the tune is at
void ThemeMusicPlay1()
{
NR52_REG = 0x80; //turn sound channel on
NR51_REG = 0x11; //set which channel we are using
NR50_REG = 0x44; //set volume for left and right speakers
if (MusicLooper == 1){
//square 1 (NR10-14)
NR10_REG = 0x00; //set sweep (like going down gradually) off
NR11_REG = 0x00; //tone
NR12_REG = 0xAA; //how long the sound is
NR13_REG = 0x00; //note (I think 00 is C)
NR14_REG = 0x87; //something else to do with notes I think
}
else if (MusicLooper == 800){ //the loops are the timer, each loop will play one of these and continue on until the loop is broken
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x22;
NR14_REG = 0x87;
}
else if (MusicLooper == 1600){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x55;
NR14_REG = 0x87;
}
else if (MusicLooper == 2400){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x33;
NR14_REG = 0x87;
}
else if (MusicLooper == 3200){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x00;
NR14_REG = 0x87;
}
else if (MusicLooper == 4000){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x33;
NR14_REG = 0x87;
}
else if (MusicLooper == 4800){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA;
NR13_REG = 0x22;
NR14_REG = 0x87;
}
else if (MusicLooper == 5600){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xAA; //AA goes on forever
NR13_REG = 0x00;
NR14_REG = 0x87;
}
else if (MusicLooper == 6200){
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xF3;
NR13_REG = 0xFF; //no sound, just a good way of cutting an AA
NR14_REG = 0x87;
}
else if (MusicLooper == 6400){
MusicLooper = 0;
}
}
printf("\n\n\n\n\n\n MID AUTUMN\n WIND\n\n\n\n\n\n");
delay(2000);
printf("\n\n\n\n\n\n PRESS START\n"); //wait for start
SWITCH_ROM_MBC1(8);
while(MusicLooper != 10000){
if(joypad() == J_START){ //if start is pressed stop the music and end the loop
NR10_REG = 0x00;
NR11_REG = 0x10;
NR12_REG = 0xF3;
NR13_REG = 0xFF; //no sound, just a good way of cutting an AA
NR14_REG = 0x87;
SWITCH_ROM_MBC1(1);
break;
}
else{
ThemeMusicPlay1(); //otherwise keep playing!
}
MusicLooper += 1; //keep adding one on to continue the song.
}
Just ignore the comments.
Offline
To play music, there are two options: Either you use an existing player (like GBTPlayer or Carillon) or you go for the do-it-youself approach. I have no experience with any of the players, so I can't help you with them. But what you're trying to do in your code example is the do-it-youself approach. I'll give you a brief explanation on how that can work and a code example. I'm not saying that it's the only, easiest or smartest way but it's one that works. Proceed as follows:
1. Set up a data array with values that represent the sounds you want to play (MusicData in the example below).
2. Write a function (PlaySound in the example below) that reads one value from your data array, translates it into the respective values for the Game Boy's sound registers and writes the respective values to the sound registers. Make sure that this function only plays one sound at a time depending on the value of a counter variable (SongCounter in the example below). It is not supposed to play the complete song.
3. Write an interrupt service routine that will be triggered by the timer interrupt. Each time the timer interrupt service routine is called, it increases a counter variable (SongInterruptCounter in the example below). If the counter reaches a maximum (SongSpeed in the example below), it resets the SongInterruptCounter to zero, increases the SongCounter by one and calls the PlaySound function. If the SongCounter reaches the end of the song (SongLength in the example), it must also be reset to zero, so the song loops.
4. In your main function you only have to take the following steps:
a. Initialize the Game Boy's sound unit.
b. Initialize your variables (SongCounter, SongInterruptCounter, SongSpeed, SongLength).
c. Set up the timer interrupt.
d. Enter your main loop. Do, whatever your game needs to do. The music will play in the background.
#include <\gb\gb.h> #include <stdio.h> UINT16 SongLength; UINT8 SongSpeed; UINT8 SongInterruptCounter; UINT16 SongCounter; const UINT8 MusicData[] = { // Data array that contains the notes of your song. }; void PlaySound() { // Read the value at the position of SongCounter from the MusicData array... // ...translate it into the respective values for the sound registers... // ...and write these values to the registers. // Make sure you only play one note at a time. // For testing purposes you can ignore the array and always play the same note. } void TimerISR() { SongInterruptCounter++; if (SongInterruptCounter == SongSpeed) { PlaySound(); SongCounter++; if (SongCounter == SongLength) SongCounter = 0; SongInterruptCounter = 0; } } void main() { // Initialize sound unit. NR52_REG = 0x80; NR51_REG = 0xFF; NR50_REG = 0x77; // Dont' forget to initialize the waveform data for channel 3 if you want to use it. // Initialize variables. SongInterruptCounter = 0; SongCounter = 0; SongSpeed = 20; // Higher value results in a slower tempo. SongLength = 327; // Number of notes of your song. // Set up the timer interrupt. disable_interrupts(); add_TIM(TimerISR); enable_interrupts(); TAC_REG = 0x06; set_interrupts(TIM_IFLAG); // Main loop. while(!0) { // Fill in the code for your game here. The music will play in the background. } }
Offline
thank you, as you can see by the above post I have worked out a way of doing it myself but this is quite useful. I can't however get more than 1 channel to play at once, not sure why.
Offline
The above code can be shortened a little if you use a switch statement instead of all those else if statements.
https://www.tutorialspoint.com/cprogram … t_in_c.htm
Last edited by chris (2017-10-07 23:47:35)
Offline
Here's how I do music:
First, I figure out the notes to play and put them in the code like so:
const unsigned char level1_notes_2[] = { 14, 64, 94, 14, 64, 94, 14, 64, 94, 44, 94, 4, 44, 74, 94, 44, 74, 94, 44, 74, 94, 74, 64, 44, 44 }; const unsigned char level1_notes[] = { 144, 164, 144, 94, 44, 94, 44, 94, 144, 164, 144, 164, 94, 164, 204, 164, 144, 94, 144, 164, 204, 164, 144, 94, 144, 44 }; const unsigned char level1_notelength[] = { 48, 16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 96, 48, 16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 96 };
Then I made a music_player part like so. (This is where the switch function comes in handy, for different songs)
void music_player() { NR52_REG = 0x80; // POWER SOUNDS NR50_REG = 0xCC; // MASTER VOLUME NR51_REG = 0xff; // L/R ENABLES NR12_REG = 0xd0; // SQUARE 1 volume (I thought that was controlled by NR50!) NR22_REG = 0xd0; if (tsnote<0) NR12_REG = 0x00, NR22_REG = 0x00; //if gameinprocess =2 then game has begun. Otherwise, 0 means it's at the title screen. switch (gameinprocess) { case 2: NR11_REG = 0x86; NR14_REG = 0x86; NR24_REG = 0x87; if (tsnote>25) tsnote=0, titlescreentimer2=0, tsnote2=0; NR13_REG = level1_notes[tsnote]; NR23_REG = level1_notes_2[tsnote2]; break; case 0: NR11_REG = 0x86; NR14_REG = 0x87; NR24_REG = 0x86; NR21_REG = 0x86; if (tsnote>36) tsnote=0, titlescreentimer2=0, tsnote2=0; NR13_REG = nr13_ts_notes[tsnote]; NR23_REG = nr23_ts_notes[tsnote2]; break; } }
Then, inside the main loop, I pointed to the music_player like so:
// play the song. songtimer++, titlescreentimer2++; length=level1_notelength[tsnote]; if (songtimer>length) tsnote++, songtimer=0, music_player(); if (titlescreentimer2>32) tsnote2++, titlescreentimer2=0, music_player();
I figured this out all by myself and my experience with C.
Offline
jobalisk wrote:
thank you, as you can see by the above post I have worked out a way of doing it myself but this is quite useful. I can't however get more than 1 channel to play at once, not sure why.
I guess the reason is that you change the value of NR51_REG before you play each sound. Try to set NR51_REG only once in the initialization procedure of your game and set it to 0xFF. That will waste a bit of battery life on the real hardware but should enable you to use all channels simultaneously.
Last edited by Jonas (2017-10-08 08:20:05)
Offline