Skip to content

Commit

Permalink
sound copy first fix and better tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Borishkof committed Nov 24, 2024
1 parent 1fd41e2 commit aec7da7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 10 deletions.
52 changes: 47 additions & 5 deletions src_c/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,19 +838,61 @@ snd_copy(pgSoundObject *self, PyObject *_null)
pgSoundObject *new_sound;
Mix_Chunk *new_chunk;

CHECK_CHUNK_VALID(chunk, -1);
// Validate the input chunk
CHECK_CHUNK_VALID(chunk, NULL);

// Create a new sound object
new_sound =
(pgSoundObject *)pgSound_Type.tp_new(Py_TYPE(self), NULL, NULL);
if (!new_sound) {
PyErr_SetString(PyExc_RuntimeError,
"Failed to allocate memory for new sound object");
return NULL;
}

// Handle chunk allocation type
if (chunk->allocated) {
new_chunk = Mix_QuickLoad_RAW(chunk->abuf, chunk->alen);
if (!new_chunk)
RAISE(pgExc_BufferError, "there is a problem I can't describe :)");

// Create a deep copy of the audio buffer for allocated chunks
Uint8 *buffer_copy = (Uint8 *)malloc(chunk->alen);
if (!buffer_copy) {
Py_DECREF(new_sound);
PyErr_SetString(PyExc_MemoryError,
"Failed to allocate memory for sound buffer");
return NULL;
}
memcpy(buffer_copy, chunk->abuf, chunk->alen);

// Create a new Mix_Chunk
new_chunk = Mix_QuickLoad_RAW(buffer_copy, chunk->alen);
if (!new_chunk) {
free(buffer_copy);
Py_DECREF(new_sound);
PyErr_SetString(PyExc_RuntimeError,
"Failed to create new sound chunk");
return NULL;
}
new_chunk->volume = chunk->volume;
new_sound->chunk = new_chunk;
}
else {
// For non-allocated chunks (e.g., formats like .xm), create a full
// copy
new_chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
if (!new_chunk) {
Py_DECREF(new_sound);
PyErr_SetString(PyExc_MemoryError,
"Failed to allocate memory for sound chunk");
return NULL;
}
*new_chunk = *chunk; // Copy the entire structure

// For safety, ensure the copied chunk doesn't share pointers
new_chunk->abuf =
NULL; // Prevent double-free if original gets deallocated
new_chunk->allocated = 0;

new_sound->chunk = new_chunk;
}

return (PyObject *)new_sound;
}
Expand Down
20 changes: 15 additions & 5 deletions test/mixer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,18 +710,28 @@ def test_get_sdl_mixer_version__linked_equals_compiled(self):
compiled_version = pygame.mixer.get_sdl_mixer_version(linked=False)

self.assertTupleEqual(linked_version, compiled_version)

def test_snd_copy(self):
mixer.init()
filename = example_path(os.path.join("data", "house_lo.wav"))

def test_snd_copy(self):
mixer.init()

filenames = [
"house_lo.mp3",
"house_lo.ogg",
"house_lo.wav",
"house_lo.flac",
# "house_lo.opus", unsupported
# "surfonasinewave.xm" unsupported
]

for f in filenames:
filename = example_path(os.path.join("data", f))
sound = mixer.Sound(file=filename)
sound_copy = sound.copy()
self.assertEqual(sound.get_length(), sound_copy.get_length())
self.assertEqual(sound.get_num_channels(), sound_copy.get_num_channels())
self.assertEqual(sound.get_volume(), sound_copy.get_volume())
self.assertEqual(sound.get_raw(), sound_copy.get_raw())

# Destroy the original sound
del sound

# Test on the copy
Expand Down

0 comments on commit aec7da7

Please sign in to comment.