Skip to content

Commit

Permalink
sfinfo
Browse files Browse the repository at this point in the history
  • Loading branch information
porres committed Feb 4, 2025
1 parent b0d038d commit c8cd53f
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 2 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ endif()

target_link_libraries(play.file_tilde PRIVATE ffmpeg)
target_link_libraries(sfload PRIVATE ffmpeg)
target_link_libraries(sfinfo PRIVATE ffmpeg)

target_link_libraries(pdlink PUBLIC link)
target_link_libraries(pdlink_tilde PUBLIC link opus)
Expand Down
41 changes: 41 additions & 0 deletions Documentation/Help-files/sfinfo-help.pd
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#N canvas 552 38 569 462 10;
#X obj 306 5 cnv 15 250 40 empty empty empty 12 13 0 18 #7c7c7c #e0e4dc 0;
#X obj 345 12 cnv 10 10 10 empty empty ELSE 0 15 2 30 #7c7c7c #e0e4dc 0;
#X obj 23 41 cnv 4 4 4 empty empty Query\ sound\ file\ information 0 28 2 18 #e0e0e0 #000000 0;
#X obj 458 12 cnv 10 10 10 empty empty EL 0 6 2 13 #7c7c7c #e0e4dc 0;
#X obj 478 12 cnv 10 10 10 empty empty Locus 0 6 2 13 #7c7c7c #e0e4dc 0;
#X obj 515 12 cnv 10 10 10 empty empty Solus' 0 6 2 13 #7c7c7c #e0e4dc 0;
#X obj 464 27 cnv 10 10 10 empty empty ELSE 0 6 2 13 #7c7c7c #e0e4dc 0;
#X obj 502 27 cnv 10 10 10 empty empty library 0 6 2 13 #7c7c7c #e0e4dc 0;
#N canvas 0 22 450 278 (subpatch) 0;
#X coords 0 1 100 -1 252 42 1 0 0;
#X restore 305 4 graph;
#X obj 3 4 cnv 15 301 42 empty empty sfinfo 20 20 2 37 #e0e0e0 #000000 0;
#N canvas 0 22 450 278 (subpatch) 0;
#X coords 0 1 100 -1 302 42 1;
#X restore 2 4 graph;
#X obj 7 413 cnv 15 552 21 empty empty empty 20 12 0 14 #e0e0e0 #202020 0;
#X obj 7 291 cnv 3 550 3 empty empty inlets 8 12 0 13 #dcdcdc #000000 0;
#X obj 7 342 cnv 3 550 3 empty empty outlets 8 12 0 13 #dcdcdc #000000 0;
#X obj 7 378 cnv 3 550 3 empty empty arguments 8 12 0 13 #dcdcdc #000000 0;
#X obj 130 300 cnv 17 3 32 empty empty 0 5 9 0 16 #dcdcdc #9c9c9c 0;
#X obj 290 154 loadbang;
#X obj 130 355 cnv 17 3 17 empty empty 0 5 9 0 16 #dcdcdc #9c9c9c 0;
#X text 121 150 see also:;
#X obj 121 194 else/play.file~;
#X obj 121 214 else/player~;
#X obj 121 234 else/sample~;
#X text 74 87 [sfinfo] supports all files that [sfload] and [play.file~] support and can be used to query file sample information but only channels so far as this object is still very experimental)., f 71;
#X obj 121 174 else/sfload;
#X msg 290 179 read bubul.mp3 \, channels;
#X obj 290 207 else/sfinfo;
#X obj 290 228 route channels;
#X floatatom 290 251 5 0 0 0 - - - 0;
#X text 164 301 read <symbol> - read sound file;
#X text 246 391 none;
#X text 194 354 anything - sound file's information;
#X text 195 316 channels - query for number of channels;
#X connect 16 0 24 0;
#X connect 24 0 25 0;
#X connect 25 0 26 0;
#X connect 26 0 27 0;
100 changes: 100 additions & 0 deletions Source/Control/sfinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@

#include <m_pd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>

static t_class *sfinfo_class;

typedef struct _sfinfo {
t_object x_obj;
t_outlet *x_info_outlet;
AVFormatContext *x_ic;
t_canvas *x_canvas;
char x_path[MAXPDSTRING];
t_atom x_info[1];
int x_opened;
}t_sfinfo;

void* sfinfo_nchs(t_sfinfo *x){
if(!x->x_opened){
pd_error(x, "[sfinfo]: No file loaded");
return(NULL);
}
x->x_ic = avformat_alloc_context();
if(avformat_open_input(&x->x_ic, x->x_path, NULL, NULL) != 0){
pd_error(x, "[sfinfo]: Could not open file '%s'", x->x_path);
return(NULL);
}
if (avformat_find_stream_info(x->x_ic, NULL) < 0) {
pd_error(x, "[sfinfo]: Could not find stream information");
avformat_close_input(&x->x_ic);
return(NULL);
}
int audio_stream_index = -1;
for(unsigned int i = 0; i < x->x_ic->nb_streams; i++){
if(x->x_ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
audio_stream_index = i;
break;
}
}
if(audio_stream_index == -1){
pd_error(x, "[sfinfo]: Could not find any audio stream in the file");
avformat_close_input(&x->x_ic);
return(NULL);
}
AVStream *audio_stream = x->x_ic->streams[audio_stream_index];
// Use AVChannelLayout to determine the number of channels
AVChannelLayout layout = {0}; // Initialize the layout
if(audio_stream->codecpar->ch_layout.u.mask)
av_channel_layout_from_mask(&layout, audio_stream->codecpar->ch_layout.u.mask);
else
av_channel_layout_default(&layout, audio_stream->codecpar->ch_layout.nb_channels);
unsigned int num_channels = layout.nb_channels;
// Clean up
av_channel_layout_uninit(&layout);
avformat_close_input(&x->x_ic);
// Output the number of channels
SETFLOAT(x->x_info + 0, (t_float)num_channels);
outlet_anything(x->x_info_outlet, gensym("channels"), 1, x->x_info);
return(NULL);
}

static int sfinfo_find_file(t_sfinfo *x, t_symbol *file, char *dir_out) {
static char fname[MAXPDSTRING];
char *bufptr;
int fd = canvas_open(x->x_canvas, file->s_name, "", fname, &bufptr, MAXPDSTRING, 1);
if(fd < 0){
pd_error(x, "[sfinfo] file '%s' not found", file->s_name);
return(0);
}
else if(bufptr > fname){
bufptr[-1] = '/';
strcpy(dir_out, fname);
}
return(1);
}

void sfinfo_read(t_sfinfo* x, t_symbol* file){
x->x_opened = sfinfo_find_file(x, file, x->x_path);
}

static void sfinfo_free(t_sfinfo *x) {
if(x->x_ic)
avformat_close_input(&x->x_ic);
}

static void *sfinfo_new(t_symbol *s, int ac, t_atom *av) {
t_sfinfo *x = (t_sfinfo *)pd_new(sfinfo_class);
x->x_ic = NULL;
x->x_canvas = canvas_getcurrent();
x->x_info_outlet = outlet_new(&x->x_obj, &s_list);
return(x);
}

void sfinfo_setup(void) {
sfinfo_class = class_new(gensym("sfinfo"), (t_newmethod)sfinfo_new,
(t_method)sfinfo_free, sizeof(t_sfinfo), 0, A_GIMME, 0);
class_addmethod(sfinfo_class, (t_method)sfinfo_read, gensym("read"), A_SYMBOL, 0);
class_addmethod(sfinfo_class, (t_method)sfinfo_nchs, gensym("channels"), 0);
}
2 changes: 0 additions & 2 deletions Source/Control/sfload.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ void* sfload_read_audio(void *arg){ // read audio into array
SETFLOAT(x->x_sfinfo + 1, x->x_stream_ctx->sample_rate);
SETFLOAT(x->x_sfinfo + 2, nch);
SETFLOAT(x->x_sfinfo + 3, av_get_bytes_per_sample(x->x_stream_ctx->sample_fmt) * 8);
// SETFLOAT(x->x_sfinfo + 4, loop_start_entry ? atoi(loop_start_entry->value) : 0);
// SETFLOAT(x->x_sfinfo + 5, loop_end_entry ? atoi(loop_end_entry->value) : output_index);
x->x_num_channels = nch;
x->x_result_ready = output_index;
for(unsigned int ch = 0; ch < nch; ch++)
Expand Down

0 comments on commit c8cd53f

Please sign in to comment.