Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Linux/Unix ::  Verzögerungsfreier Soundserver     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
lakiday
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.03.2010
Beiträge: 6
Beitrag lakiday Mitglied 16:55:18 03.03.2010   Titel:   Verzögerungsfreier Soundserver            Zitieren

Hallo,
für mein Program benötige ich eine verzögerungsfreie Soundausgabe, d.h. wenn ich meine „play“ funktion aufrufe muss sofort der Sound ertönen. Ich habe schon OpenAl und Alsa ausprobiert, aber ich habe jeweils eine kurze Verzögerung. Deswegen habe ich versucht, das ganze direkt auf der Soundkarte mit „/dev/dsp“auszugeben. Da ich auch mehrere Sounds gleichzeitig abspielen möchte, habe ich mir einen kleinen Soundserver geschrieben, allerdings habe ich wieder eine kleine Verzögerung. Hier mein Code:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
class PlaybackDsp : public Playback {



int playIdBuf;
std::vector<int> playing;
int currPlaying;
std::map<int, std::string> id_file;
std::map<int, unsigned int> id_pos;

...

void play(std::string filename);
static void* sound_server( void* ptr );
void mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length);

}

PlaybackDsp::play(std::string filename) {

    //überprüfung ob sound vorhanden ist...
    ...

    //sound zur playlist hinzufügen

    playing.push_back(playIdBuf);
    id_file[playIdBuf] = filename;
    id_pos[playIdBuf] = 0;
    playIdBuf++;

}

void* PlaybackDsp::sound_server( void* ptr ) {
    PlaybackDsp* _this = (PlaybackDsp*) ptr;
   
    unsigned int bufferSize = 100;
    unsigned char* buffer;
    buffer = new unsigned char[bufferSize];
    std::vector<int> toDelete;
   
    //sound server main loop
    while(true) {
       
        //clear buffer
        for(unsigned int i = 0; i < bufferSize; i++) {
            buffer[i] = 0;
        }
       
        //mix current playing files into buffer
        std::vector<int>::iterator iter = _this->playing.begin();
        _this->currPlaying = _this->playing.size();
        while( iter != _this->playing.end() ) {
           
            _this->mix(buffer, bufferSize, _this->sounds[_this->id_file[*iter]]->data(), _this->sounds[_this->id_file[*iter]]->size(), _this->id_pos[*iter], bufferSize);
           
            if( _this->id_pos[*iter] + bufferSize < _this->sounds[_this->id_file[*iter]]->size() ) {
                _this->id_pos[*iter] += bufferSize;
            } else {
                toDelete.push_back(*iter);
            }
           
            iter++;
        }
       
        //write data in sound device
        if (write(_this->fd, buffer, bufferSize) == -1) {
            std::cerr << "Error writing to \"/dev/dsp\" !";
            continue;
        }
       
        //remove played sounds from playlist
        std::vector<int>::iterator itd = toDelete.begin();
        for(; itd < toDelete.end(); itd++) {
            int id = *itd;
           
            _this->id_file.erase(id);
            _this->id_pos.erase(id);
           
            std::vector<int>::iterator it = _this->playing.begin();
            while( it != _this->playing.end() ) {
                if(*it == id) {
                    it = _this->playing.erase(it);
                } else {
                    it++;
                }
            }
           
        }
        toDelete.clear();
    }
   
    delete[] buffer;
   
    return 0;
}

void PlaybackDsp::mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length) {
   
    switch(sampleSize) {
        case 8:
            //...
            break;
       
        case 16: {
            short* dest_s = reinterpret_cast<short*>(dest);
            short* src_s = reinterpret_cast<short*>(src);
           
            unsigned int length;
            if(src_pos+src_length > src_size) {
                length = src_size-src_pos;
            } else {
                length = src_length;
            }
            if(length > dest_size) {
                length = dest_size;
            }
           
            for(unsigned int i = 0; i < length/2; i++) {
                dest_s[i] += src_s[src_pos/2+i]/2;
            }
           
            dest = reinterpret_cast<unsigned char*>(src_s);
           
            break;
        }
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
class PlaybackDsp : public Playback {



int playIdBuf;
std::vector<int> playing;
int currPlaying;
std::map<int, std::string> id_file;
std::map<int, unsigned int> id_pos;

...

void play(std::string filename);
static void* sound_server( void* ptr );
void mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length);

}

PlaybackDsp::play(std::string filename) {

//überprüfung ob sound vorhanden ist...
...

//sound zur playlist hinzufügen

playing.push_back(playIdBuf);
id_file[playIdBuf] = filename;
id_pos[playIdBuf] = 0;
playIdBuf++;

}

void* PlaybackDsp::sound_server( void* ptr ) {
PlaybackDsp* _this = (PlaybackDsp*) ptr;

unsigned int bufferSize = 100;
unsigned char* buffer;
buffer = new unsigned char[bufferSize];
std::vector<int> toDelete;

//sound server main loop
while(true) {

//clear buffer
for(unsigned int i = 0; i < bufferSize; i++) {
buffer[i] = 0;
}

//mix current playing files into buffer
std::vector<int>::iterator iter = _this->playing.begin();
_this->currPlaying = _this->playing.size();
while( iter != _this->playing.end() ) {

_this->mix(buffer, bufferSize, _this->sounds[_this->id_file[*iter]]->data(), _this->sounds[_this->id_file[*iter]]->size(), _this->id_pos[*iter], bufferSize);

if( _this->id_pos[*iter] + bufferSize < _this->sounds[_this->id_file[*iter]]->size() ) {
_this->id_pos[*iter] += bufferSize;
} else {
toDelete.push_back(*iter);
}

iter++;
}

//write data in sound device
if (write(_this->fd, buffer, bufferSize) == -1) {
std::cerr << "Error writing to \"/dev/dsp\" !";
continue;
}

//remove played sounds from playlist
std::vector<int>::iterator itd = toDelete.begin();
for(; itd < toDelete.end(); itd++) {
int id = *itd;

_this->id_file.erase(id);
_this->id_pos.erase(id);

std::vector<int>::iterator it = _this->playing.begin();
while( it != _this->playing.end() ) {
if(*it == id) {
it = _this->playing.erase(it);
} else {
it++;
}
}

}
toDelete.clear();
}

delete[] buffer;

return 0;
}

void PlaybackDsp::mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length) {

switch(sampleSize) {
case 8:
//...
break;

case 16: {
short* dest_s = reinterpret_cast<short*>(dest);
short* src_s = reinterpret_cast<short*>(src);

unsigned int length;
if(src_pos+src_length > src_size) {
length = src_size-src_pos;
} else {
length = src_length;
}
if(length > dest_size) {
length = dest_size;
}

for(unsigned int i = 0; i < length/2; i++) {
dest_s[i] += src_s[src_pos/2+i]/2;
}

dest = reinterpret_cast<unsigned char*>(src_s);

break;
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
class PlaybackDsp : public Playback {



int playIdBuf;
std::vector<int> playing;
int currPlaying;
std::map<int, std::string> id_file;
std::map<int, unsigned int> id_pos;

...

void play(std::string filename);
static void* sound_server( void* ptr );
void mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length);

}

PlaybackDsp::play(std::string filename) {

    //überprüfung ob sound vorhanden ist...
    ...

    //sound zur playlist hinzufügen

    playing.push_back(playIdBuf);
    id_file[playIdBuf] = filename;
    id_pos[playIdBuf] = 0;
    playIdBuf++;

}

void* PlaybackDsp::sound_server( void* ptr ) {
    PlaybackDsp* _this = (PlaybackDsp*) ptr;
   
    unsigned int bufferSize = 100;
    unsigned char* buffer;
    buffer = new unsigned char[bufferSize];
    std::vector<int> toDelete;
   
    //sound server main loop
    while(true) {
       
        //clear buffer
        for(unsigned int i = 0; i < bufferSize; i++) {
            buffer[i] = 0;
        }
       
        //mix current playing files into buffer
        std::vector<int>::iterator iter = _this->playing.begin();
        _this->currPlaying = _this->playing.size();
        while( iter != _this->playing.end() ) {
           
            _this->mix(buffer, bufferSize, _this->sounds[_this->id_file[*iter]]->data(), _this->sounds[_this->id_file[*iter]]->size(), _this->id_pos[*iter], bufferSize);
           
            if( _this->id_pos[*iter] + bufferSize < _this->sounds[_this->id_file[*iter]]->size() ) {
                _this->id_pos[*iter] += bufferSize;
            } else {
                toDelete.push_back(*iter);
            }
           
            iter++;
        }
       
        //write data in sound device
        if (write(_this->fd, buffer, bufferSize) == -1) {
            std::cerr << "Error writing to \"/dev/dsp\" !";
            continue;
        }
       
        //remove played sounds from playlist
        std::vector<int>::iterator itd = toDelete.begin();
        for(; itd < toDelete.end(); itd++) {
            int id = *itd;
           
            _this->id_file.erase(id);
            _this->id_pos.erase(id);
           
            std::vector<int>::iterator it = _this->playing.begin();
            while( it != _this->playing.end() ) {
                if(*it == id) {
                    it = _this->playing.erase(it);
                } else {
                    it++;
                }
            }
           
        }
        toDelete.clear();
    }
   
    delete[] buffer;
   
    return 0;
}

void PlaybackDsp::mix(unsigned char* dest, unsigned int dest_size, unsigned char* src, unsigned int src_size, unsigned int src_pos, unsigned int src_length) {
   
    switch(sampleSize) {
        case 8:
            //...
            break;
       
        case 16: {
            short* dest_s = reinterpret_cast<short*>(dest);
            short* src_s = reinterpret_cast<short*>(src);
           
            unsigned int length;
            if(src_pos+src_length > src_size) {
                length = src_size-src_pos;
            } else {
                length = src_length;
            }
            if(length > dest_size) {
                length = dest_size;
            }
           
            for(unsigned int i = 0; i < length/2; i++) {
                dest_s[i] += src_s[src_pos/2+i]/2;
            }
           
            dest = reinterpret_cast<unsigned char*>(src_s);
           
            break;
        }
    }
}


Wie bekomme ich eine verzögerungsfreie Soundausgabe, oder mit welcher Bibliothek ist das möglich?

2. Frage:
Beim zusammenmixen von Sound halbiere ich zuerst die Amplitude um kein übersteuern der Sounds zu bekommen. Wenn ich jedoch mehrere habe, könnte es immer noch übersteuern, aber die Amplitude immer kleiner zu machen ist ja keine Lösung. Wie füge ich am besten die Sounds zusammen?

Mit freundlichen Grüßen
Lukas


Zuletzt bearbeitet von lakiday am 16:59:16 03.03.2010, insgesamt 1-mal bearbeitet
YASC
Mitglied

Benutzerprofil
Anmeldungsdatum: 06.01.2005
Beiträge: 398
Beitrag YASC Mitglied 18:14:16 03.03.2010   Titel:              Zitieren

Zur 1. Frage:
Jack ist der übliche Kandidat.

_________________
http://www.yasc.org
Erscheinen Sie, sonst weinen Sie!
ProgChild
Autor

Benutzerprofil
Anmeldungsdatum: 29.12.2003
Beiträge: 2261
Beitrag ProgChild Autor 13:01:01 07.03.2010   Titel:              Zitieren

Wie hier schon erwähnt wurde, kannst du jackd nutzen. Das wäre wohl am einfachsten.

Je nach dem, was du vorhast, könntest du aber auch mit ALSA weiter kommen. Einfach mal den Puffer kleiner machen. Je kleiner der Puffer, um so geringer ist die Latenzzeit. Nichts anderes macht auch jackd. Wenn das dann noch nicht reicht, kannst du die Real-Time-Erweiterung der Kernels installieren. Die hilft dir aber nur etwas, wenn dein Puffer so klein ist, dass es zu underruns kommt.

_________________
meine Homepage | Artikel: GNU Autotools (PDF) | Software: Wallpaper Action, Netwalker | Bibliotheken: FoxTray
lakiday
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.03.2010
Beiträge: 6
Beitrag lakiday Mitglied 16:22:36 08.03.2010   Titel:              Zitieren

Hallo,
danke für die bisherigen Antworten. Mit Jack bekomme ich nun eine verzögerungsfreie Ausgabe, allerdings bleibt Frage 2, wie ich das parallele Abspielen mehrerer Sound realisiere. Mein bisheriges Vorgehen:

1. Laden der Sounds mit libsnd
2. Ins richtige Format mit libsamplerate konvertieren
3. In meiner "play" Funktion füge ich den abzuspielenden Sound in meine play liste hinzu

4. Im Process Callback von Jack addiere ich nun die einzelnen Samples der Sounds
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {
   
    PlaybackJack* _this = (PlaybackJack*) arg;
   
    //grab output buffer
    sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
    sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );
   
    //for each required sample
    for(jack_nframes_t i = 0; i < nframes; i++) {
       
        sample_t tmp_l = 0;
        sample_t tmp_r = 0;
        std::map<int, sample_t*>::iterator iter = _this->playing.begin();
        while( iter != _this->playing.end() ) {
            int id = iter->first;
           
            if(_this->playing_offset[id]+1 < _this->playing_samples[id]) {
                tmp_l += _this->playing[id][_this->playing_offset[id]]/2;
                tmp_r += _this->playing[id][_this->playing_offset[id]+1]/2;
                _this->playing_offset[id]++;
            } else {
                _this->playing.erase(id);
                _this->playing_samples.erase(id);
                _this->playing_offset.erase(id);
            }
           
            iter++;
        }
       
        out_l[i] = tmp_l;
        out_r[i] = tmp_r;
    }
   
    return 0;      
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {

PlaybackJack* _this = (PlaybackJack*) arg;

//grab output buffer
sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );

//for each required sample
for(jack_nframes_t i = 0; i < nframes; i++) {

sample_t tmp_l = 0;
sample_t tmp_r = 0;
std::map<int, sample_t*>::iterator iter = _this->playing.begin();
while( iter != _this->playing.end() ) {
int id = iter->first;

if(_this->playing_offset[id]+1 < _this->playing_samples[id]) {
tmp_l += _this->playing[id][_this->playing_offset[id]]/2;
tmp_r += _this->playing[id][_this->playing_offset[id]+1]/2;
_this->playing_offset[id]++;
} else {
_this->playing.erase(id);
_this->playing_samples.erase(id);
_this->playing_offset.erase(id);
}

iter++;
}

out_l[i] = tmp_l;
out_r[i] = tmp_r;
}

return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {
   
    PlaybackJack* _this = (PlaybackJack*) arg;
   
    //grab output buffer
    sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
    sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );
   
    //for each required sample
    for(jack_nframes_t i = 0; i < nframes; i++) {
       
        sample_t tmp_l = 0;
        sample_t tmp_r = 0;
        std::map<int, sample_t*>::iterator iter = _this->playing.begin();
        while( iter != _this->playing.end() ) {
            int id = iter->first;
           
            if(_this->playing_offset[id]+1 < _this->playing_samples[id]) {
                tmp_l += _this->playing[id][_this->playing_offset[id]]/2;
                tmp_r += _this->playing[id][_this->playing_offset[id]+1]/2;
                _this->playing_offset[id]++;
            } else {
                _this->playing.erase(id);
                _this->playing_samples.erase(id);
                _this->playing_offset.erase(id);
            }
           
            iter++;
        }
       
        out_l[i] = tmp_l;
        out_r[i] = tmp_r;
    }
   
    return 0;      
}

Ist dieses Vorgehen sinnvoll? Und wie addiere ich die Samples richtig, damit es zu keiner Übersteuerung und Lautstärkenänderung der Sounds kommt?

Mit freundlichen Grüßen
Lukas
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 22819
Beitrag rüdiger Moderator 20:46:06 08.03.2010   Titel:              Zitieren

2.
Als naiven Ansatz würde ich die Streams addieren und dann abschneiden.

also
C/C++ Code:
o = i0 + i1;
if(o > max) o = max;
C/C++ Code:
o = i0 + i1;
if(o > max) o = max;
C/C++ Code:
o = i0 + i1;
if(o > max) o = max;


Wobei du natürlich einen möglichen Integer-Overflow durch die Addition auch abfangen solltest.

_________________
.


Zuletzt bearbeitet von rüdiger am 20:47:51 08.03.2010, insgesamt 2-mal bearbeitet
noobLolo
Unregistrierter




Beitrag noobLolo Unregistrierter 01:01:46 09.03.2010   Titel:              Zitieren

was denkt ihr von fließkommazahlen fürs mixen von sounddateien hab mal gehört das neuere bild/ton/video programme langsam umsteigen bzw. schon umgestiegen sind :confused:

lg lolo
lakiday
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.03.2010
Beiträge: 6
Beitrag lakiday Mitglied 17:23:55 10.03.2010   Titel:              Zitieren

Hallo,
Jack arbeitet mit floats. Wie überprüfe ich da auf ein Overflow und was wäre dann das sinnvollste? Einfach auf den maximal Wert setzen hört sich dann ja nicht sonderlich gut an.

Jetzt ist aber noch ein weiteres Problem aufgetreten. Wenn ich mehr als 7 sounds gleichzeitig abspiele benötigt mein Callback zu lange und Jack verwirft mein callback, sodass nichts mehr abgespielt wird. Wie kann ich mein callback noch optimieren?

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {
   
    PlaybackJack* _this = (PlaybackJack*) arg;
   
    pthread_mutex_lock(&_this->mutex);
       
        //grab output buffer
        sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
        sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );
       
        //for each required sample
        for(jack_nframes_t i = 0; i < nframes; i++) {
           
            sample_t tmp_l = 0;
            sample_t tmp_r = 0;
           
            std::map<int, std::string>::iterator iter = _this->playing.begin();
            while( iter != _this->playing.end()) {
               
                if(_this->playing_offset[iter->first]+1 < _this->length[iter->second]) {
                    tmp_l += _this->sounds[iter->second][_this->playing_offset[iter->first]];
                    tmp_r += _this->sounds[iter->second][_this->playing_offset[iter->first]+1];
                    _this->playing_offset[iter->first]+=2;
                } else {
                    _this->playing.erase(iter->first);
                    _this->playing_offset.erase(iter->first);
                }
               
                iter++;
            }
            out_l[i] = tmp_l;
            out_r[i] = tmp_r;
        }
   
    pthread_mutex_unlock(&_this->mutex);
   
    return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {

PlaybackJack* _this = (PlaybackJack*) arg;

pthread_mutex_lock(&_this->mutex);

//grab output buffer
sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );

//for each required sample
for(jack_nframes_t i = 0; i < nframes; i++) {

sample_t tmp_l = 0;
sample_t tmp_r = 0;

std::map<int, std::string>::iterator iter = _this->playing.begin();
while( iter != _this->playing.end()) {

if(_this->playing_offset[iter->first]+1 < _this->length[iter->second]) {
tmp_l += _this->sounds[iter->second][_this->playing_offset[iter->first]];
tmp_r += _this->sounds[iter->second][_this->playing_offset[iter->first]+1];
_this->playing_offset[iter->first]+=2;
} else {
_this->playing.erase(iter->first);
_this->playing_offset.erase(iter->first);
}

iter++;
}
out_l[i] = tmp_l;
out_r[i] = tmp_r;
}

pthread_mutex_unlock(&_this->mutex);

return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int PlaybackJack::process_cb(jack_nframes_t nframes, void *arg) {
   
    PlaybackJack* _this = (PlaybackJack*) arg;
   
    pthread_mutex_lock(&_this->mutex);
       
        //grab output buffer
        sample_t *out_l = (sample_t *) jack_port_get_buffer( _this->output_port_l, nframes );
        sample_t *out_r = (sample_t *) jack_port_get_buffer( _this->output_port_r, nframes );
       
        //for each required sample
        for(jack_nframes_t i = 0; i < nframes; i++) {
           
            sample_t tmp_l = 0;
            sample_t tmp_r = 0;
           
            std::map<int, std::string>::iterator iter = _this->playing.begin();
            while( iter != _this->playing.end()) {
               
                if(_this->playing_offset[iter->first]+1 < _this->length[iter->second]) {
                    tmp_l += _this->sounds[iter->second][_this->playing_offset[iter->first]];
                    tmp_r += _this->sounds[iter->second][_this->playing_offset[iter->first]+1];
                    _this->playing_offset[iter->first]+=2;
                } else {
                    _this->playing.erase(iter->first);
                    _this->playing_offset.erase(iter->first);
                }
               
                iter++;
            }
            out_l[i] = tmp_l;
            out_r[i] = tmp_r;
        }
   
    pthread_mutex_unlock(&_this->mutex);
   
    return 0;
}


Sollte ich das ganze mit normalen arrays realisieren und nicht std::map benutzen, oder gibt es da keinen großen Geschwindigkeitsunterschied?
Ich habe auch schon versucht die Buffer Größe von Jack zu verkleinern (momentan 1024) aber dann brauch mein callback immer zu lang.

Mit freundlichen Grüßen
Lukas
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 22819
Beitrag rüdiger Moderator 18:00:35 10.03.2010   Titel:              Zitieren

lakiday schrieb:
Hallo,
Jack arbeitet mit floats. Wie überprüfe ich da auf ein Overflow und was wäre dann das sinnvollste? Einfach auf den maximal Wert setzen hört sich dann ja nicht sonderlich gut an.


Bei Floats limitiert man sich ja eh auf den Bereich -1.0f bis 1.0f. Du hast also keine Probleme mit potentiellen Overflows.

Zitat:
Sollte ich das ganze mit normalen arrays realisieren und nicht std::map benutzen, oder gibt es da keinen großen Geschwindigkeitsunterschied


Eine Map ist ziemlich aufwendig! Du solltest lieber std::unordered_map oder einen std::vector/std::array benutzen, wenn es geht.

_________________
.
lakiday
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.03.2010
Beiträge: 6
Beitrag lakiday Mitglied 20:50:42 11.03.2010   Titel:              Zitieren

Hallo,
ich hab jetzt das ganze auf normale arrays umgestellt. Jetzt kann ich bei gleicher Buffer Größe ca. 350 sounds gleichzeitig abspielen.

Vielen Dank für die Antworten!

Mit freundlichen Grüßen
Lukas
dooooomi
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.01.2007
Beiträge: 273
Beitrag dooooomi Mitglied 17:00:16 12.03.2010   Titel:              Zitieren

Noch eine Anmerkung hierzu: Im JACK Process Callback ist genaugenommen alles tabu, was den Thread auf unbestimmte Zeit blockieren könnte. In dem von dir geposteten Code verstößt du an zwei Stellen gegen diese Regel:

C/C++ Code:
pthread_mutex_lock(&_this->mutex);
C/C++ Code:
pthread_mutex_lock(&_this->mutex);
C/C++ Code:
pthread_mutex_lock(&_this->mutex);

C/C++ Code:
_this->playing_offset.erase(iter->first);
C/C++ Code:
_this->playing_offset.erase(iter->first);
C/C++ Code:
_this->playing_offset.erase(iter->first);


Klar, der Code läuft trotzdem irgendwie, aber wenn er auch bei niedriger Latenz wirklich zuverlässig und ohne Aussetzer funktionieren soll, solltest du auf solche Dinge achten und die Laufzeit so deterministisch wie möglich halten. Wenn dein Callback zu lange braucht, wartet die Soundkarte schließlich vergeblich auf neue Daten. Und das betrifft ggf. nicht nur dein eigenes Programm, sondern auch andere, "unschuldige" JACK-Clients die gleichzeitig laufen und durch die Verzögerung nicht mehr rechtzeitig zum Zuge kommen.

_________________
It's not a feature, it's a bug!
C/C++ Forum :: Linux/Unix ::  Verzögerungsfreier Soundserver   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.