-
-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pygame.Sound.copy
implementation
#3238
base: main
Are you sure you want to change the base?
Conversation
pygame.Sound.copy
implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for contributing to pygame-ce!
This change would need documentation and type stubs for complete approval
Parameter type changing from pgSoundObject to PyObject. Co-authored-by: Thomasgrgi <[email protected]> Co-authored-by: Bilhox Co-authored-by: AntoineM <[email protected]>"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Things I noticed beside what ankith said. Also some error messages could be improved grammar wise.
Thanks for your help, I will update my PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, I left some requested changes.
Co-authored-by: Bilhox <[email protected]>"
It seems like xm or opus is "Unrecognized audio format" (using mixer.Sound() ) for the distribution that does the automatic test I failed. |
You are writing unittest for Sound.copy, not for other functionalities. |
// Handle chunk allocation type | ||
if (chunk->allocated) { | ||
// Create a deep copy of the audio buffer for allocated chunks | ||
Uint8 *buffer_copy = (Uint8 *)malloc(chunk->alen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is a memory leak. This is allocated but never freed, and it can't be freed here because it needs to live as long as the chunk does.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copying an entire struct like this may work in this scenario but in my opinion is not something that is safe in general. From SDL's perspective these are all internal fields and they can do whatever they want with it. They're barely documented.
Thank you for working on this @Borishkof! I can tell this is a high effort contribution. However, I feel that there is no safe way to do this within the SDL_mixer API, and I don't really see why this is a useful feature. I feel bad I didn't see the earlier discussion and say so then. Copying a surface? Important, because they are editable. Edit one copy, leave the other copy the same. Talking myself through it I guess you could attach sounds to objects in a game. So like different sprites have different volume explosion noises. So you would want to give them each a copy of the sound with a different preset volume. But that would be very wasteful on the memory front. The ideal solution I think would be a bunch of Mix_Chunks all pointed at the same audio buffer, with different volumes set. So we already have Quickload_RAW from SDL_mixer, and we already can get the raw bytes using the routine So maybe this can be done without this allocated branching? Whether or not the mix_chunk controls the allocation, the allocation can be copied out. We'd need some way of managing the life cycle of this new buffer that only some Sound objects have. If we wanted to share it between Sound copies for efficiency's sake it could be another Python object so we can ref-count it for garbage collection purposes. OK new idea on this train of thought, can't this be implemented safely and simply in Python? I haven't tested this at all but couldn't you take the output of |
Thank you for the review :) As I am a beginner in Pygame, I can't argue much about the solutions you propose and will leave it to the community to decide which is the most efficient way to tackle the issue. If the community reaches a consensus on a reasonably simple solution, I would be glad to try and implement it. Otherwise, I am happy to let anyone with good ideas take a shot at addressing this issue. 👍 |
I find the arguments gave by starbucks understandable, so I'm for an implementation in python side now. |
On second thought maybe sharing the memory is a bit too far. Sound data is mutable through https://pyga.me/docs/ref/sndarray.html#pygame.sndarray.samples, so that would need to protected against. Also I'm not sure the public Sound API supports zero copying the data. But anyways here is a 1 line Python implementation of sound.copy, in a demonstration program. import pygame
pygame.init()
window = pygame.Window(resizable=True)
screen = window.get_surface()
class MySound(pygame.Sound):
def copy(self):
return self.__class__(buffer=self.get_raw())
a = MySound(r"C:\Users\charl\Desktop\pygame-ce\examples\data\secosmic_lo.wav")
b = a.copy()
b.set_volume(0.1)
clock = pygame.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit
if event.type == pygame.KEYDOWN and event.key == pygame.K_1:
a.play()
if event.type == pygame.KEYDOWN and event.key == pygame.K_2:
b.play()
window.flip()
clock.tick(144) |
I've set this to a draft because it is not ready to merge in its current state. I was going to close it fully and send it back to the issue for a new PR, but the docs/tests/stubs bit of this PR is probably good. I just think the actual implementation needs to be overhauled. I showed a Python example of how this could be achieved in one line. This same logic could be applied in C (it would take more than one line), or it could be monkey patched into the type in |
Create a function for deep copying sound.
Create some tests (failing tests on .xm and .opus for un unknown reason).
issue : #1328 (comment)