OpenAL - Verweis auf nicht aufgelöstes externes Symbol

Stansfield

Cadet 2nd Year
Registriert
Dez. 2007
Beiträge
25
Hallo Forengemeinde,

seit neurem beschäftige ich mich mit OpenAL in C++. Ich arbeite unter Windows 7 mit Visual Studio 2010 Express. Ich habe mir ein kleines Projekt angelegt, bei dem ich jedoch jetzt an einem Punkt angelangt bin, wo ich allein nicht mehr weiter weiß:

Ich habe mir eine Klasse alSound angelegt, wobei jede Instanz eine .wav-Datei hält und diese unter anderem überhaupt erstmal laden, dann abspielen oder pausieren kann.

Hier die alSound.h:

Code:
#include <al.h>
#include <alut.h>
#include <alc.h>

class alSound
{
	public:
		ALboolean	LoadSound(char fname[40], ALboolean looping);
		ALboolean	SetProperties(float x, float y, float z, float vx, float vy, float vz);
		void			SetSourceRelative();
		void			PlaySound();
		void			PauseSound();
		void			StopSound();
		void			DestroySound();

	private:
		ALuint		alSource;
		ALuint		alBuffer;
		ALenum		format;
		ALvoid*		data;
		ALsizei		size;
		ALsizei		frequency;
		ALboolean	loop;
	
};

... und die zugehörige alSound.cpp

Code:
#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <iostream>

#include "alSound.h"


ALboolean
alSound::LoadSound(char fname[40], ALboolean looping)
{
	alGenBuffers(1, &alBuffer);
	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;
		
	alutLoadWAVFile(fname, &format, (void **) &data, &size, &frequency, &loop);
	alBufferData(alBuffer, format, data, size, frequency);
	alutUnloadWAV(format, data, size, frequency);
				
	alGenSources(1, &alSource);
	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;

	alSourcei(alSource, AL_BUFFER, alBuffer);
	alSourcef(alSource, AL_PITCH, 1.0f);
	alSourcef(alSource, AL_GAIN, 1.0f);
	alSourcei(alSource, AL_LOOPING, looping);

	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;

	return AL_TRUE;
}


ALboolean
alSound::SetProperties(float x, float y, float z, float vx, float vy, float vz)
{
	alSource3f(alSource, AL_POSITION, x,y,z);
	alSource3f(alSource, AL_VELOCITY, vx,vy,vz);

	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;
	
	return AL_TRUE;
}


void 
alSound::SetSourceRelative()
{
	alSourcei(alSource,AL_SOURCE_RELATIVE,AL_TRUE);
}


void 
alSound::PlaySound()
{
	alSourcePlay(alSource);
}


void 
alSound::PauseSound()
{
	alSourcePause(alSource);
}


void 
alSound::StopSound()
{
	alSourceStop(alSource);
}


void 
alSound::DestroySound()
{
	alDeleteSources(1, &alSource);
	alDeleteBuffers(1, &alBuffer);
}


In der main.cpp will ich nun ein solche Instanz erzeugen und eine underwater.wav laden.

Code:
#include <stdlib.h>
#include <conio.h>
#include <math.h>
#include <iostream>
#include "alSound.h"

ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };
ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };
ALfloat ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };

void SetListenerValues()
{
	alListenerfv(AL_POSITION,    ListenerPos);
	alListenerfv(AL_VELOCITY,    ListenerVel);
	alListenerfv(AL_ORIENTATION, ListenerOri);
}


int main(int argc, char *argv[]) {
	alutInit(NULL, 0);
	alGetError();
	SetListenerValues();
	alSound sounds[3];
	sounds[0].LoadSound("wavdata/underwater.wav", 1);
	sounds[0].SetProperties(8.5f, 0.0f, 15.0f, 0.0f, 0.0f, 0.0f);
	
        sounds[0].PlaySound();

	sounds[0].DestroySound();
	alutExit();
}


Dabei gibt er mir folgenden Fehler aus:

Code:
1>------ Erstellen gestartet: Projekt: alSound, Konfiguration: Debug Win32 ------
1>  main.cpp
1>  alSound.cpp
1>f:\alsound\alsound.cpp(19): warning C4996: 'alutLoadWAVFile': wurde als veraltet deklariert
1>          f:\alsound\includes\alut.h(113): Siehe Deklaration von 'alutLoadWAVFile'
1>f:\alsound\alsound.cpp(21): warning C4996: 'alutUnloadWAV': wurde als veraltet deklariert
1>          f:\alsound\includes\alut.h(116): Siehe Deklaration von 'alutUnloadWAV'
1>  Code wird generiert...
1>main.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall alSound::PlaySound(void)" (?PlaySound@alSound@@QAEXXZ)" in Funktion "_main".
1>F:\alSound\Debug\alSound.exe : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.
========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========

Kommentiere ich allerdings die sounds[0].PlaySound() aus, läuft das Programm wunderbar durch, nur das ich natürlich nichts höre. Nur was soll dieser ungültige Verweis bedeuten?


Vielen Dank für alle, die sich die Mühe machen.

Gruß,
Stansfield
 
"Verweis auf nicht aufgelöstes externes Symbol" bedeutet: es fehlt ein Symbol (Variable, häufiger aber Funktion), das extern definiert sein muss, da dieses zwar deklariert, aber nicht implementiert wurde - beispielsweise durch C/C++-Sourcecode).

Mit anderen Worten: die passende Bibliothek (lib) fehlt.
 
Nee mit einer Bibliothek hat das nichts zu tun. Hier beschwert sich der Linker über alSound::PlaySound(void).

Kann es sein, dass du vergessen hast diese Methode zu implementieren? Oder dass die Implementierung vielleicht eine andere Methodensignatur hat als die Deklaration?
 
Ah - ich Blindfisch - alSound ist ja seine eigene Klasse...
Nun ja - dann fehlt natürlich die Implementierung.
 
Würde jetzt mal spontan vermuten das der PreProzessor die alSound.h Datei 2x mal einbindet, da hier bei der Header Datei die Includewatch- Irgendwas-Dinger fehlen. Da aber die alSound.h Datei sowohl in main.cpp als auch in alSound.cpp inkludiert wird, gibts dann beim Linken Probleme. Das könnte man durch folgende Varianten ändern:

Bei Visual Studio kannst du folgendes am Anfang jeder(!) Header Datei verwenden:
Code:
#pragma once

oder du machst es allgemein für die meisten Compiler gängig:

Code:
#ifndef ALSOUND_H // einfach Name der Header-Datei in Großbuchstaben und den Punkt durch "_" ersetzen
#define ALSOUND_H // muss das gleiche sein wie in der oberen Zeile

#include <al.h>
#include <alut.h>
#include <alc.h>

class alSound
{
	public:
		ALboolean	LoadSound(char fname[40], ALboolean looping);
		ALboolean	SetProperties(float x, float y, float z, float vx, float vy, float vz);
		void			SetSourceRelative();
		void			PlaySound();
		void			PauseSound();
		void			StopSound();
		void			DestroySound();

	private:
		ALuint		alSource;
		ALuint		alBuffer;
		ALenum		format;
		ALvoid*		data;
		ALsizei		size;
		ALsizei		frequency;
		ALboolean	loop;
	
};

#endif

Gewöhne dir das schnell an, sonst bekommst du massive Probleme bei Programmen die mehr als nur Hello World präsentieren... ;-) Eine der beiden Varianten solltest du in jeder Header-Datei anwenden.

Viel Erfolg...
Rossibaer

PS: Im übrigen sagt dir der Compiler, dass du 2 veraltete Funktionen verwendest (LoadWAVFile und UnloadWAVFile). Schau mal in die aktuelle Doku von den OpenAL Bibliotheken nach wie die neuen Funktionen heißen und verwende diese. Ggfs. sind dann andere Parameter notwendig, sollte aber kein Problem darstellen. Vorerst kannst du die alten Funktionen noch verwenden, jedoch ist absehbar, dass neue Versionen von den OpenAL Bibliotheken diese 2 Funktionen nicht mehr unterstützen werden und du beim nächsten Update ein nicht funktionierendes Programm hast.
 
Zuletzt bearbeitet:
Besten Dank für eure Antworten.

@ IceMatrix und XunnD: Die playSound() war schon richtig implementiert, das sollte eigentlich gepasst haben.

Wie auch immer, mit Rossibaers Tipp hat dann aber alles geklappt, danke dir. Diese Präprozessorgeschichte war mir immer schleierhaft. Hab mich dann mal jetzt belesen - so schwer ist es ja garnicht :rolleyes:


Würde gern noch ein paar weitere Fragen generell zu OpenAL stellen:

  1. Wie schaffe ich es, die alutLoadWAVFile und alutUnloadWAV korrekt zu implementieren? Laut Definition verlangt erstere:
    Code:
     alutLoadWAVFile (ALbyte *fileName, ALenum *format, void **data, ALsizei *size, ALsizei *frequency, ALboolean *loop);
    Also soll der Filename als Byte übergeben werden? Wie kriegt man sowas hin?
    Warum er bei der UnloadWAV meckert, bleibt mir ein Rätsel. Laut Definition braucht er
    Code:
    alutUnloadWAV (ALenum format, ALvoid *data, ALsizei size, ALsizei frequency);
    Von mir bekommt er extakt das Gleiche...
  2. Warum wurde AL_VELOCITY geschaffen? Man muss sich um die Positionsverschiebung doch sowieso selbst kümmern - soweit ich das verstanden habe. Sprich man muss die AL_POSITION immer um einer Vektor verändern, was bringt mir da die AL_VELOCITY?

    Die Geschwindigkeit beeinflußt jedoch nicht die Position des Objektes. OpenAL berechnet die Geschwindigkeit nicht aus aufeinanderfolgenden Änderungen mit AL_POSITION, ebenso wenig wird die Position des Objektes über die Zeit anhand der angegebenen Geschwindigkeit angepasst. Jede derartige Berechnung bleibt der Anwendung überlassen.
    aus http://wiki.delphigl.com/index.php/alSource#AL_VELOCITY
  3. Ich schaffe es leider nicht, für die AL_DIRECTION eine Wirkung zu erzielen. Beispielsweise veränder ich die Position der Source auf (5.0f, 0.0f, 0.0f) und die Direction auf (1.0f, 0.0f, 0.0f), was also heißt, dass die Source rechts ist und auch dahin abstrahlt. Änder ich die Direction auf (-1.0f, 0.0f, 0.0f), also zum Listener hin, ändert sich rein garnichts an der Lautstärke.


Vielleicht findet sich ja jemand, der ein paar Antworten hat :)
Danke!
 
Zu 1. Es wird nicht ein ALByte übergeben sondern ein Zeiger auf ein ALByte. Das ist ein riesen Unterschied. Stell dir vor der Zeiger zeigt nur auf das 1. ALbyte eines Arrays von mehreren aufeinander folgenden ALbytes und die Funktion alutLoadWAVFile() macht nichts weiter als von Anfang bis Ende des Arrays die einzelnen Byte einzulesen und als Dateinamen zu interpretieren. Somit übergibst du nicht nur 1 Byte an die Funktion sondern mehrere. Mal angenommen du hast ein Array von char

Code:
// dein Dateipfad als Char-Array
char data[] = "C:\\TEMP\\MyFile.wav";
// dann kannst du das auch als einen Zeiger auf das Array "interpretieren":
char * myFileAsCharPointer = data;
// von hier an könntest du nun mal einen Cast machen:
ALbyte * myFileAsALbytePointer = (ALbyte *) filename;
// Und nun das ganze an die Funktion übergeben:
alutLoadWAVFile (myFileAsALbytePointer /*, die restlichen Parameter hier noch einfügen */);

Sorry für mein eingerostetes Halbwissen, C/C++ ist nicht so mein Fachgebiet. Sicher gibts da bessere Wege (z.B. bei dem Cast). Jedoch könntest du mal das ausprobieren. Kannst ja gerne mal schreiben ob es funktioniert oder nicht.

Zu 2. und 3) Ich kenne OpenAL nicht, habe nur durch deinen Post erfahren dass es das überhaupt gibt. ;) Danke dir, dass du meinen Horizont "erweitert" hast. Also bitte schreib von Zeit zu Zeit mal was darüber, dann hab ich auch noch was davon ...

Viele Grüße
Rossibaer
 
Zurück
Oben