Sound I: The easiest way (C & ASM with SDCC)

Pincha aquí para verlo en español

In this tutorial we will get started in the use of sound as simple as possible, for this we will use the firmware as we did from Basic, using the functions sound, ent and env. In the user manuals we will find many references to sound, ent and env:

manual

 

Sound instruction corresponds to the firmware command 0xBCAA (SOUND QUEUE), ent corresponds to 0xBCBF (SOUND TONE ENVELOPE) and env with 0xBCBC (SOUND AMPL ENVELOPE). The only peculiarity of calling these firmware functions is that they need the parameters are stored in a buffer housed in the central 32K of RAM, ie, between 0x4000 and 0xC000. For our example I've put a defined memory position they occupy, but depending on the size and position of our program / game could collide and would have to move to another memory location. I have also used in the example 0xBCAD instruction (SOUND CHECK) to check if the channel was broadcasting sound (so you can wait for it to finish).

Here's a complete example, with 4 functions sound, ent, env and soundstatus as well as a series of sounds / effects to prove they work:

////////////////////////////////////////////////////////////////////////
// Sound01.c
// Mochilote - www.cpcmania.com
////////////////////////////////////////////////////////////////////////
#include <stdio.h>

//Firmware requires it in the central 32K of RAM (0x4000 to 0xC000), move it as you need...
#define SOUND_BUFF 0x4FF6 //9 bytes
#define ENT_BUFF 0x4FE6 //16 bytes
#define ENV_BUFF 0x4FD6 //16 bytes

////////////////////////////////////////////////////////////////////////
//sound
////////////////////////////////////////////////////////////////////////
unsigned char bQueue = 0;
unsigned char sound(unsigned char nChannelStatus, int nTonePeriod, int nDuration, unsigned char nVolume, char nVolumeEnvelope, char nToneEnvelope, unsigned char nNoisePeriod)
{
  //This function uses 9 bytes of memory for sound buffer. Firmware requires it in the central 32K of RAM (0x4000 to 0xC000)
  /*
    The bytes required to define the sound are as follows
    byte 0 - channel status byte
    byte 1 - volume envelope to use
    byte 2 - tone envelope to use
    bytes 3&4 - tone period
    byte 5 - noise period
    byte 6 - start volume
    bytes 7&8 - duration of the sound, or envelope repeat count 
  */
  
  __asm
    LD HL, #SOUND_BUFF

    LD A, 4 (IX) ;nChannelStatus
    LD (HL), A
    INC HL

    LD A, 10 (IX) ;nVolumeEnvelope
    LD (HL), A
    INC HL

    LD A, 11 (IX) ;nToneEnvelope
    LD (HL), A
    INC HL

    LD A, 5 (IX) ;nTonePeriod
    LD (HL), A
    INC HL
    LD A, 6 (IX) ;nTonePeriod
    LD (HL), A
    INC HL

    LD A, 12 (IX) ;nNoisePeriod
    LD (HL), A
    INC HL

    LD A, 9 (IX) ;nVolume
    LD (HL), A
    INC HL

    LD A, 7 (IX) ;nDuration
    LD (HL), A
    INC HL
    LD A, 8 (IX) ;nDuration
    LD (HL), A
    INC HL

    LD HL, #SOUND_BUFF
    CALL #0xBCAA ;SOUND QUEUE
  
    LD HL, #_bQueue
    LD (HL), #0
    JP NC, _EndSound
    LD (HL), #1
    _EndSound:
  __endasm;
  
  return bQueue;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
//ent
////////////////////////////////////////////////////////////////////////
void ent(unsigned char nEnvelopeNumber, unsigned char nNumberOfSteps, char nTonePeriodOfStep, unsigned char nTimePerStep)
{
  //This function uses 16 bytes of memory for ent buffer. Firmware requires it in the central 32K of RAM (0x4000 to 0xC000)
  
  __asm
    LD HL, #ENT_BUFF

    LD A, #0x1
    LD (HL), A
    INC HL

    LD A, 5 (IX) ;nNumberOfSteps
    LD (HL), A
    INC HL

    LD A, 6 (IX) ;nTonePeriodOfStep
    LD (HL), A
    INC HL

    LD A, 7 (IX) ;nTimePerStep
    LD (HL), A
    INC HL

    LD A, 4 (IX) ;nEnvelopeNumber
    LD HL, #ENT_BUFF
    CALL #0xBCBF ;SOUND TONE ENVELOPE
  __endasm;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
//env
////////////////////////////////////////////////////////////////////////
void env(unsigned char nEnvelopeNumber, unsigned char nNumberOfSteps, char nSizeOfStep, unsigned char nTimePerStep)
{
  //This function uses 16 bytes of memory for env buffer. Firmware requires it in the central 32K of RAM (0x4000 to 0xC000)
  
  __asm
    LD HL, #ENV_BUFF

    LD A, #0x1
    LD (HL), A
    INC HL

    LD A, 5 (IX) ;nNumberOfSteps
    LD (HL), A
    INC HL

    LD A, 6 (IX) ;nSizeOfStep
    LD (HL), A
    INC HL

    LD A, 7 (IX) ;nTimePerStep
    LD (HL), A
    INC HL

    LD A, 4 (IX) ;nEnvelopeNumber
    LD HL, #ENV_BUFF
    CALL #0xBCBC ;SOUND AMPL ENVELOPE
  __endasm;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
//soundcheck
////////////////////////////////////////////////////////////////////////
unsigned char nSoundCheck = 0;
unsigned char soundcheck(unsigned char nChannelStatus)
{
  __asm
  LD A, 4 (IX) ;nChannelStatus
  CALL #0xBCAD; SOUND CHECK
  LD HL, #_nSoundCheck
  LD (HL), A
  __endasm;
  
  return (nSoundCheck & 0x80);
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
//main
////////////////////////////////////////////////////////////////////////
main()
{
  int aSounds[12] = { 478, 451, 426, 402, 379, 358, 338, 319, 301, 284, 268, 253 };
  int n = 0;

  printf("1\n\r");

  for(n=0; n < 12; n++)
  {
    while(!sound(1, aSounds[n], 20, 15, 0, 0, 0));
  }

  while(soundcheck(1));
  printf("2\n\r");

  ent(1, 20, -11, 1);
  sound(1, 200, 20, 15, 0, 1, 0);

  while(soundcheck(1));
  printf("3\n\r");

  ent(1, 20, -11, 1);
  sound(1, 428, 10, 15, 0, 1, 0);

  while(soundcheck(1));
  printf("4\n\r");

  env(1, 25, 15, 5);
  ent(1, 25, 120, 6);
  sound(1, 428, 25, 15, 1, 1, 14);

  while(soundcheck(1));
  printf("5\n\r");

  sound(1, 200, 20, 15, 0, 0, 0);
  
  while(soundcheck(1));
  printf("6\n\r");
  
  env(1, 10, 1, 100);
  sound(1, 284, 1000, 1, 1, 0, 0);
  
  while(soundcheck(1));
  printf("7\n\r");

  ent(1, 100, 2, 2);
  sound(1,284,200,15,0,1,0);
  
  while(soundcheck(1));
  printf("8\n\r");

  ent(1, 100, -2, 2);
  sound(1, 284, 200, 15, 0, 1, 0);
  
  while(soundcheck(1));
  
  return 0;
}
////////////////////////////////////////////////////////////////////////

In this simple way we have a basic sound, well documented with many examples in the manuals and magazines with printed games. You could download a zip with all files (source code, bat to compile, binary and dsk's) here: Sound_I.zip

 

www.CPCMania.com 2014