Gå til innhold

Anbefalte innlegg

Hei. Jeg skal lage et program som spiller av en tone når jeg trykker på en tast. Om jeg må lage lydfilen på forhånd (som mp3, wav eller lignende, for så å få programmet til å spille den av) eller om programmet selv lager tonen (trenger ikke være mer enn en sinustone), går egentlig for det samme, selvom det siste er å foretrekke.

 

Det jeg lurer på er hvordan man i det hele tatt kan få et program, skrevet i C, til å spille av lyd.

Lenke til kommentar
Videoannonse
Annonse

For å få programmert noe lyd i C er du nødt til å jobbe opp mot eksterne API-er. Og det finnes mange av dem. Kommer an på hvilket OS du sitter på så klart.

 

Geir:

Er ikke OpenAL et ganske tungt API å jobbe opp mot? Trenger absolutt ikke noe som OpenAL for å generere en sinus-tone.

 

Hvis du sitter på Linux kan du prøve denne koden. Den spiller av A-dur og A-moll skalaen :3

 

Simpel OSS-kode følger under. Prinsippet for å spille av lyd er stort sett det samme, men du vil kanskje benytte deg av andre funksjoner.

#include <sys/soundcard.h>
#include <math.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>


void generate_sine(int fd, char *buffer, int size, int samplerate, int halftone)
{
  int count;
  for( count = 0; count < size; count++ )
  {
  // Generer en sinusfunksjon med frekvens avhenging av halvtone
  buffer[count] = (int) 0xFF/2*sin(2*3.1415*440*powf(2, (float)halftone/12)*(float)count/(float)samplerate);
  }
  write( fd, buffer, size );
}


int main()
{
  int fd = open("/dev/dsp", O_WRONLY, 0);

  // 8-bit
  int format = AFMT_S8;
  ioctl( fd, SNDCTL_DSP_SETFMT, &format );

  // Mono
  int stereo = 0;
  ioctl( fd, SNDCTL_DSP_STEREO, &stereo );

  // 44100 Hz samplerate
  int samplerate = 44100;
  ioctl( fd, SNDCTL_DSP_SPEED, &samplerate );

  // 0.25s med lyd
  char *buffer = malloc ( samplerate/4 );

  // Dur-skala :3
  int halftone_major[8] = {0, 2, 4, 5, 7, 9, 11, 12};
  int halftone_minor[8] = {0, 2, 3, 5, 7, 8, 10, 12};
  int count;
  for ( count = 0; count < 8; count++ )
  {
  generate_sine(fd, buffer, samplerate/4, samplerate, halftone_major[count]);
  }
  for ( count = 0; count < 8; count++ )
  {
  generate_sine(fd, buffer, samplerate/4, samplerate, halftone_minor[count]);
  }


  close( fd );
  return 0;
}

Endret av TheMaister
Lenke til kommentar

Takk for svar :yes:

 

TheMaister: Jeg sitter på Linux, men jeg får ikke koden til å fungere. På linjen

 

char *buffer = malloc ( samplerate/4 );

 

får jeg feilen "invalid conversion from 'void*' to 'char*'". Noen forslag?

 

GeirGrusom: Hvordan er det å lære seg å bruke openAL. Jeg har litt knapt med tid.

 

Takk for all hjelp!

Lenke til kommentar
Yes! Der funka det :D Tusen takk!

 

Tror ikke jeg bruker C++. Filen heter i hvert fall *.c.

 

Det at filen slutter på .c betyr bare at filen slutter på .c

Det er compileren du bruker som bestemmer hvilket språk som ligger i filen. GCC skal prøve å gjette på compiler etter filtype, men dersom du tvinger frem bruk av C++ (for eksempel ved å bruke g++) så spiller det ingen rolle hva extension til fila er.

Lenke til kommentar

Noe lignende i OpenAL:

#include <AL.H>
#include <ALC.H>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define PI 3.1415

void CreateSineWave(short* buffer, int samples, int sample_rate, double frequency, double amplitude)
{
double sample_increment = (PI * 2) / sample_rate;
double period = 0;
amplitude = amplitude > 1 ? 1 : (amplitude < 0 ? 0 : amplitude);
for(int i = 0; i < samples; i++)
{
	double sinp = sin(period += sample_increment * frequency) * amplitude;
	short val = (short)(sinp * 32767);
	buffer[i] = val;
}
}

int main(int argc, char** argv)
{
ALCdevice *device = alcOpenDevice(NULL);
ALCcontext* ctx = NULL;
if(device)
{
	ctx = alcCreateContext(device, NULL);
	alcMakeContextCurrent(ctx);
}
else
{
	printf("Failed to open audio device.");
	return 1;
}

const int sample_rate = 44100;
const int samples = 4 * sample_rate;
short sinewave[samples];	// Lag et fire sekunder langt buffer

CreateSineWave(sinewave, samples, sample_rate, 500, .1);

unsigned int buffer = 0;
unsigned int source = 0;

alGenBuffers(1, &buffer);
alGenSources(1, &source);

alBufferData(buffer, AL_FORMAT_MONO16, sinewave, sizeof(sinewave), sample_rate);
alSourcei(source, AL_BUFFER, buffer);
alSourcePlay(source);

getchar();

alcDestroyContext(ctx);
return 0;
}

 

Så det skal ikke så mye til for å gjøre enkle ting. Det er dog ingen innebygget støtte for noen lydformater (på samme måte som det ikke er noen innebygget støtte for bildeformater i OpenGL) men ALC inneholder en funksjon for å laste .WAV filer. Utover det, er det ingen kunst å bruke libvorbisfile for å spille av Ogg Vorbis filer. Det er kanskje mulig å bruke DirectShow på Windows også, men jeg har ikke vært borti DirectShow i C++.

 

edit: MP3 og Ogg Vorbis er støttet gjennom extensions.

Endret av GeirGrusom
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...