acheney
7 months ago
commit
5ec3cb9454
10 changed files with 2523 additions and 0 deletions
@ -0,0 +1,875 @@
@@ -0,0 +1,875 @@
|
||||
// pixilang-based music visualizer |
||||
// by acheney (with help from nightradio, silent broadcast, and others) |
||||
// under mit license |
||||
|
||||
include "demo.pixi" |
||||
|
||||
// - CONFIG BEGIN - |
||||
|
||||
// -- DEMO LIB CONFIG -- |
||||
|
||||
// demo width in pixels |
||||
demo_xsize = 1920 |
||||
|
||||
// demo height in pixels |
||||
demo_ysize = 1080 |
||||
|
||||
// demo use opengl |
||||
demo_opengl = 1 |
||||
|
||||
// demo video export filename, comment it out if you don't want to export |
||||
//demo_video_export = "video.avi" |
||||
|
||||
// demo video export fps (frames per second) |
||||
demo_video_export_fps = 60 |
||||
|
||||
// demo video export quality (0 - 100) |
||||
demo_video_export_q = 100 |
||||
|
||||
// -- FILE CONFIG -- |
||||
|
||||
// note: all of these files should be located in the "media" directory of this program |
||||
|
||||
// the filename of the audio file |
||||
audio_filename = "song.mp3" |
||||
|
||||
// the filename of the artist image |
||||
artist_filename = "artist.png" |
||||
|
||||
// the filename of the logo image |
||||
logo_filename = "logo.png" |
||||
|
||||
// the filename of the cover image |
||||
cover_filename = "cover.png" |
||||
|
||||
// the filename of the background image (set this to be the same as the cover image if you don't want a separate background |
||||
background_filename = "background.png" |
||||
|
||||
// -- TEXT CONFIG -- |
||||
|
||||
// text (song title, song artist, song release title) |
||||
text_title = "dead girl" |
||||
text_artist = "DREADNOUGHT" |
||||
text_release = "DREADNOUGHT" |
||||
|
||||
// text distance scaling (0 - 1) |
||||
text_scale = 0.25 |
||||
|
||||
// text color |
||||
text_color = #FFFFFF |
||||
|
||||
// -- SPECTRUM/VISUALIZER CONFIG -- |
||||
|
||||
// goertzel size |
||||
vis_size = 2048 |
||||
|
||||
// visualizer color |
||||
vis_color = #FFFFFF |
||||
|
||||
// linear visualizer (only enabled when 1, logarithmic when 0) |
||||
vis_linear = 1 |
||||
|
||||
// visualizer linear interpolation (only enabled when 1, bars when 0) |
||||
vis_int = 0 |
||||
|
||||
// visualizer number of bars |
||||
vis_bars = 100 |
||||
|
||||
// visualizer bar width factor ( 0 - 1 ) |
||||
vis_bar_width = 0.5 |
||||
|
||||
// linear visualizer minimum frequency (hz) |
||||
vis_min_freq = 20 |
||||
|
||||
// linear visualizer maximum frequency (hz) |
||||
vis_max_freq = 3000 |
||||
|
||||
// logarithmic visualizer minimum midi pitch |
||||
vis_min_pitch = 15 |
||||
|
||||
// logarithmic visualizer maximum midi pitch |
||||
vis_max_pitch = 102 |
||||
|
||||
// visualizer smoothing factor ( >= 1 ) |
||||
vis_smooth = 1.5 |
||||
|
||||
// visualizer vertical scale |
||||
vis_scale = 50 |
||||
|
||||
// -- TIME CONFIG -- |
||||
|
||||
// time for fade to black |
||||
all_exit = 6000 |
||||
|
||||
// time for logo + artist + blur transitions |
||||
all_enter = 6000 |
||||
|
||||
// -- LOGO CONFIG -- |
||||
|
||||
// logo size scale ( % of image size ) |
||||
logo_scale = 0.25 |
||||
|
||||
// logo size scale ( persistent bottom-right corner ) ( % of demo_xsize ) |
||||
logo_scale_persistent = 0.075 |
||||
|
||||
// -- ARTIST CONFIG -- |
||||
|
||||
// artist size scale ( % of image size ) |
||||
artist_scale = 0.25 |
||||
|
||||
// -- COVER CONFIG -- |
||||
|
||||
//cover scale ( persistent top-right corner ) ( % of demo_xsize ) |
||||
cover_scale = 0.075 |
||||
|
||||
// -- BACKGROUND CONFIG -- |
||||
|
||||
// background gaussian blur radius |
||||
background_blur_rad = 20 |
||||
|
||||
// background brightness scale ( 0 - 1 ) |
||||
background_brightness = 0.8 |
||||
|
||||
// background flash speed ( 0 - 1 ) |
||||
background_flash_speed = 0.75 |
||||
|
||||
// background shake amplitude ( affects both amp and the zoom of the background ) |
||||
background_shake_amp = 2 |
||||
|
||||
// background shake speed ( the lower the value, the faster it is ) |
||||
background_shake_speed = 0.9 |
||||
|
||||
// -- BEGINNING FLASH CONFIG -- |
||||
|
||||
// speed of the flash at the beginning in seconds |
||||
beginning_flash_speed = 0.05 |
||||
|
||||
// fade out of the flash at the beginning in seconds |
||||
beginning_flash_fade = 2 |
||||
|
||||
// exponential curve of the flash at the beginning ( >=0 ) |
||||
beginning_flash_curve = 5 |
||||
|
||||
// - END CONFIG - |
||||
|
||||
media = "media/" |
||||
|
||||
audio_filename_internal = "" |
||||
artist_filename_internal = "" |
||||
logo_filename_internal = "" |
||||
cover_filename_internal = "" |
||||
background_filename_internal = "" |
||||
|
||||
strcat( audio_filename_internal, media ) |
||||
strcat( audio_filename_internal, audio_filename ) |
||||
|
||||
strcat( artist_filename_internal, media ) |
||||
strcat( artist_filename_internal, artist_filename ) |
||||
|
||||
strcat( logo_filename_internal, media ) |
||||
strcat( logo_filename_internal, logo_filename ) |
||||
|
||||
strcat( cover_filename_internal, media ) |
||||
strcat( cover_filename_internal, cover_filename ) |
||||
|
||||
strcat( background_filename_internal, media ) |
||||
strcat( background_filename_internal, background_filename ) |
||||
|
||||
demo_load_wav( audio_filename_internal ) |
||||
cover = load( cover_filename_internal ) |
||||
logo = load( logo_filename_internal ) |
||||
artist = load( artist_filename_internal ) |
||||
background = load( background_filename_internal ) |
||||
|
||||
set_flags( background, CFLAG_INTERP ) |
||||
set_flags( cover, CFLAG_INTERP ) |
||||
|
||||
demo_length = 0 |
||||
|
||||
goertzel_values = new( vis_bars, 1, FLOAT ) |
||||
|
||||
cover_xsize = get_xsize(cover) |
||||
cover_ysize = get_ysize(cover) |
||||
cover_size = cover_xsize * cover_ysize |
||||
cover_src = clone( cover ) |
||||
|
||||
background_xsize = get_xsize( background ) |
||||
background_ysize = get_ysize( background ) |
||||
background_src = clone( background ) |
||||
|
||||
logo_xsize = get_xsize(logo) |
||||
logo_ysize = get_ysize(logo) |
||||
|
||||
corner_x = -demo_xsize div 2 |
||||
corner_y = -demo_ysize div 2 |
||||
|
||||
logo_xsize = get_xsize(logo) |
||||
logo_ysize = get_ysize(logo) |
||||
|
||||
artist_xsize = get_xsize(artist) |
||||
artist_ysize = get_ysize(artist) |
||||
|
||||
demo_init() |
||||
custom_init() |
||||
|
||||
demo_add_scene( 0, 0, 0, view ) |
||||
demo_add_scene( 0, 0, demo_length, DEMO_STOP ) |
||||
|
||||
demo_play() |
||||
custom_deinit() |
||||
demo_deinit() |
||||
|
||||
fn view( $t1, $t2, $len ) |
||||
{ |
||||
clear( #000000 ) |
||||
|
||||
bg_render( $t1 ) |
||||
vis_render( $t1 ) |
||||
cover_render( $t1 ) |
||||
logo_render( $t1 ) |
||||
text_render( $t1 ) |
||||
|
||||
screen_blur( $t1 ) |
||||
|
||||
logos_render( $t1 ) |
||||
beginning_flash_render( $t1 ) |
||||
black( $t1 ) |
||||
|
||||
transp( 255 ) |
||||
} |
||||
|
||||
fn vis_render( $t1 ) |
||||
{ |
||||
|
||||
transp( 255 ) |
||||
|
||||
if ( vis_linear ) { |
||||
|
||||
if ( vis_int ) { |
||||
|
||||
freq_range = vis_max_freq - vis_min_freq |
||||
|
||||
freq_unit = freq_range / vis_bars |
||||
|
||||
bar_space = demo_xsize / vis_bars |
||||
|
||||
i = 0 while i < vis_bars { |
||||
|
||||
i_freq = ( freq_unit * i ) + vis_min_freq |
||||
|
||||
k = ( 0.5 + ( ( vis_size * i_freq ) / demo_sound_rate ) ) |
||||
|
||||
real_w = 2 * cos( 2 * M_PI * k / vis_size ) |
||||
imag_w = sin( 2 * M_PI * k / vis_size ) |
||||
|
||||
d1 = 0 |
||||
d2 = 0 |
||||
|
||||
j = 0 while j < vis_size { |
||||
|
||||
j = j + 1 |
||||
|
||||
while 1 { |
||||
|
||||
if demo_sound_type == FLOAT32 { |
||||
|
||||
// audio is 32-bit float |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 8 ) |
||||
break |
||||
|
||||
} |
||||
if demo_sound_type == INT16 { |
||||
|
||||
// audio is 16-bit int |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 23 ) |
||||
break |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
win = sin( M_PI * j / vis_size ) |
||||
x = v * win |
||||
|
||||
y = ( x * vis_size ) + real_w * d1 - d2 |
||||
d2 = d1 |
||||
d1 = y |
||||
|
||||
} |
||||
|
||||
result_r = 0.5 * real_w * d1 - d2 |
||||
result_i = imag_w * d1 |
||||
|
||||
amp = result_r * result_r + result_i * result_i |
||||
amp = sqrt( amp ) |
||||
|
||||
old_amp = goertzel_values[ i ] |
||||
|
||||
goertzel_values[ i ] = old_amp + ( amp - old_amp ) * ( 1 / vis_smooth ) |
||||
|
||||
amp_scaled = ( goertzel_values[ i ] / 500 ) * vis_scale |
||||
|
||||
goertzel_values[ i ] = amp_scaled |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
i = 0 while i < demo_xsize { |
||||
|
||||
bin = ( i / demo_xsize ) * vis_bars |
||||
idx = floor( bin ) |
||||
frac = bin - idx |
||||
amp = ( 1 - frac ) * goertzel_values[ idx ] + frac * goertzel_values[ idx + 1 ] |
||||
|
||||
i_adjusted = i - ( demo_xsize / 2 ) |
||||
line( i_adjusted, 0, i_adjusted, amp, vis_color ) |
||||
line( i_adjusted, 0, i_adjusted, -amp, vis_color ) |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
} else { |
||||
|
||||
freq_range = vis_max_freq - vis_min_freq |
||||
|
||||
freq_unit = freq_range / vis_bars |
||||
|
||||
bar_space = demo_xsize / vis_bars |
||||
|
||||
i = 0 while i < vis_bars { |
||||
|
||||
i_freq = ( freq_unit * i ) + vis_min_freq |
||||
|
||||
k = ( 0.5 + ( ( vis_size * i_freq ) / demo_sound_rate ) ) |
||||
|
||||
real_w = 2 * cos( 2 * M_PI * k / vis_size ) |
||||
imag_w = sin( 2 * M_PI * k / vis_size ) |
||||
|
||||
d1 = 0 |
||||
d2 = 0 |
||||
|
||||
j = 0 while j < vis_size { |
||||
|
||||
j = j + 1 |
||||
|
||||
while 1 { |
||||
|
||||
if demo_sound_type == FLOAT32 { |
||||
|
||||
// audio is 32-bit float |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 8 ) |
||||
break |
||||
|
||||
} |
||||
if demo_sound_type == INT16 { |
||||
|
||||
// audio is 16-bit int |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 23 ) |
||||
break |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
win = sin( M_PI * j / vis_size ) |
||||
x = v * win |
||||
|
||||
y = ( x * vis_size ) + real_w * d1 - d2 |
||||
d2 = d1 |
||||
d1 = y |
||||
|
||||
} |
||||
|
||||
result_r = 0.5 * real_w * d1 - d2 |
||||
result_i = imag_w * d1 |
||||
|
||||
amp = result_r * result_r + result_i * result_i |
||||
amp = sqrt( amp ) |
||||
|
||||
old_amp = goertzel_values[ i ] |
||||
|
||||
goertzel_values[ i ] = old_amp + ( amp - old_amp ) * ( 1 / vis_smooth ) |
||||
|
||||
amp_scaled = ( goertzel_values[ i ] / 500 ) * vis_scale |
||||
|
||||
fbox( ( -demo_xsize / 2 ) + ( bar_space * i ), -amp_scaled, bar_space * vis_bar_width, amp_scaled, vis_color ) |
||||
fbox( ( -demo_xsize / 2 ) + ( bar_space * i ), 0, bar_space * vis_bar_width, amp_scaled, vis_color ) |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} else { |
||||
|
||||
if (vis_int) { |
||||
|
||||
pitch_range = vis_max_pitch - vis_min_pitch |
||||
|
||||
pitch_unit = pitch_range / vis_bars |
||||
|
||||
bar_space = demo_xsize / vis_bars |
||||
|
||||
i = 0 while i < vis_bars { |
||||
|
||||
i_pitch = ( pitch_unit * i ) + vis_min_pitch |
||||
|
||||
i_freq = pow( 2, i_pitch / 12) * 8.175799 |
||||
|
||||
k = ( 0.5 + ( ( vis_size * i_freq ) / demo_sound_rate ) ) |
||||
|
||||
real_w = 2 * cos( 2 * M_PI * k / vis_size ) |
||||
imag_w = sin( 2 * M_PI * k / vis_size ) |
||||
|
||||
d1 = 0 |
||||
d2 = 0 |
||||
|
||||
j = 0 while j < vis_size { |
||||
|
||||
j = j + 1 |
||||
|
||||
while 1 { |
||||
|
||||
if demo_sound_type == FLOAT32 { |
||||
|
||||
// audio is 32-bit float |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 8 ) |
||||
break |
||||
|
||||
} |
||||
if demo_sound_type == INT16 { |
||||
|
||||
// audio is 16-bit int |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 23 ) |
||||
break |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
win = sin( M_PI * j / vis_size ) |
||||
x = v * win |
||||
|
||||
y = ( x * vis_size ) + real_w * d1 - d2 |
||||
d2 = d1 |
||||
d1 = y |
||||
|
||||
} |
||||
|
||||
result_r = 0.5 * real_w * d1 - d2 |
||||
result_i = imag_w * d1 |
||||
|
||||
amp = result_r * result_r + result_i * result_i |
||||
amp = sqrt( amp ) |
||||
|
||||
old_amp = goertzel_values[ i ] |
||||
|
||||
goertzel_values[ i ] = old_amp + ( amp - old_amp ) * ( 1 / vis_smooth ) |
||||
|
||||
amp_scaled = ( goertzel_values[ i ] / 500 ) * vis_scale |
||||
|
||||
goertzel_values[ i ] = amp_scaled |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
i = 0 while i < demo_xsize { |
||||
|
||||
bin = ( i / demo_xsize ) * vis_bars |
||||
idx = floor( bin ) |
||||
frac = bin - idx |
||||
amp = ( 1 - frac ) * goertzel_values[ idx ] + frac * goertzel_values[ idx + 1 ] |
||||
|
||||
i_adjusted = i - ( demo_xsize / 2 ) |
||||
line( i_adjusted, 0, i_adjusted, amp, vis_color ) |
||||
line( i_adjusted, 0, i_adjusted, -amp, vis_color ) |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
} else { |
||||
|
||||
pitch_range = vis_max_pitch - vis_min_pitch |
||||
|
||||
pitch_unit = pitch_range / vis_bars |
||||
|
||||
bar_space = demo_xsize / vis_bars |
||||
|
||||
i = 0 while i < vis_bars { |
||||
|
||||
i_pitch = ( pitch_unit * i ) + vis_min_pitch |
||||
|
||||
i_freq = pow( 2, i_pitch / 12) * 8.175799 |
||||
|
||||
k = ( 0.5 + ( ( vis_size * i_freq ) / demo_sound_rate ) ) |
||||
|
||||
real_w = 2 * cos( 2 * M_PI * k / vis_size ) |
||||
imag_w = sin( 2 * M_PI * k / vis_size ) |
||||
|
||||
d1 = 0 |
||||
d2 = 0 |
||||
|
||||
j = 0 while j < vis_size { |
||||
|
||||
j = j + 1 |
||||
|
||||
while 1 { |
||||
|
||||
if demo_sound_type == FLOAT32 { |
||||
|
||||
// audio is 32-bit float |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 8 ) |
||||
break |
||||
|
||||
} |
||||
if demo_sound_type == INT16 { |
||||
|
||||
// audio is 16-bit int |
||||
v = demo_sound_pcm_stream[ ( demo_sound_pcm_stream_ptr + j ) * demo_sound_channels ] / pow( 2, 23 ) |
||||
break |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
win = sin( M_PI * j / vis_size ) |
||||
x = v * win |
||||
|
||||
y = ( x * vis_size ) + real_w * d1 - d2 |
||||
d2 = d1 |
||||
d1 = y |
||||
|
||||
} |
||||
|
||||
result_r = 0.5 * real_w * d1 - d2 |
||||
result_i = imag_w * d1 |
||||
|
||||
amp = result_r * result_r + result_i * result_i |
||||
amp = sqrt( amp ) |
||||
|
||||
old_amp = goertzel_values[ i ] |
||||
|
||||
goertzel_values[ i ] = old_amp + ( amp - old_amp ) * ( 1 / vis_smooth ) |
||||
|
||||
amp_scaled = ( goertzel_values[ i ] / 500 ) * vis_scale |
||||
|
||||
fbox( ( -demo_xsize / 2 ) + ( bar_space * i ), -amp_scaled, bar_space * vis_bar_width, amp_scaled, vis_color ) |
||||
fbox( ( -demo_xsize / 2 ) + ( bar_space * i ), 0, bar_space * vis_bar_width, amp_scaled, vis_color ) |
||||
|
||||
i = i + 1 |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
transp( 255 ) |
||||
|
||||
} |
||||
|
||||
fn bg_render($t1) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
base = 255 * background_brightness |
||||
|
||||
sample = ( abs( demo_sound_pcm_stream[ demo_sound_pcm_stream_ptr * demo_sound_channels ] ) + 0.5 ) |
||||
|
||||
old_flash = flash |
||||
|
||||
flash = base * sample |
||||
|
||||
flash = old_flash * ( 1 - background_flash_speed ) + flash * background_flash_speed |
||||
|
||||
shake_x_func = sin( 0.6 * ( $t1 / ( 1000 * background_shake_speed ) ) ) + sin( 2.65 * ( $t1 / ( 1000 * background_shake_speed ) ) ) + sin( 3.7 * ( $t1 / ( 1000 * background_shake_speed ) ) ) * background_shake_amp |
||||
shake_y_func = sin( 0.4 * ( $t1 / ( 1000 * background_shake_speed ) ) ) + sin( 1.45 * ( $t1 / ( 1000 * background_shake_speed ) ) ) + sin( 4.5 * ( $t1 / ( 1000 * background_shake_speed ) ) ) * background_shake_amp |
||||
|
||||
pixi( background, shake_x_func , shake_y_func , get_color( flash, flash, flash ), ( ( demo_xsize / background_xsize ) ) * ( 1 + ( background_shake_amp / 30 ) ) , ( ( demo_xsize / background_xsize ) ) * ( 1 + ( background_shake_amp / 30 ) ) ) |
||||
|
||||
transp( 255 ) |
||||
} |
||||
|
||||
fn logos_render($t1) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
y_pos = smooth_staircase( ( ( $t1 / ( all_enter / 3 ) ) - 1 ), 1, 15, 1, -0.5 ) * ( all_enter / 3 ) |
||||
|
||||
pixi(artist, 0, -y_pos, WHITE, artist_scale, artist_scale) |
||||
pixi(logo, 0, -y_pos + ( all_enter / 3 ), WHITE, logo_scale, logo_scale) |
||||
|
||||
transp( 255 ) |
||||
|
||||
} |
||||
|
||||
fn logo_render($t1) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
rel_time = 1 - clip( max( $t1 - ( all_enter + 2000 ) , 0 ) / 1000 ) |
||||
|
||||
enter_func = ( pow( 50, rel_time ) - 1 ) / ( 50 - 1 ) |
||||
|
||||
enter_func_adjusted = ( 1 - enter_func ) * ( demo_ysize / 2 ) |
||||
|
||||
if (logo_xsize > logo_ysize) { |
||||
|
||||
logo_adjust_factor = demo_xsize / logo_ysize |
||||
|
||||
x_pos = corner_x - ( ( logo_ysize * logo_adjust_factor * logo_scale_persistent ) / 2 ) - demo_xsize / 50 |
||||
y_pos = corner_y - ( ( logo_ysize * logo_adjust_factor *logo_scale_persistent ) / 2 ) + demo_xsize / 50 + ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = logo_adjust_factor * logo_scale_persistent |
||||
y_scale = logo_adjust_factor * logo_scale_persistent |
||||
|
||||
pixi( logo, x_pos , y_pos, WHITE, x_scale, y_scale, ( ( logo_xsize - logo_ysize ) / 2 ), 0, logo_ysize, logo_ysize ) |
||||
|
||||
} else { |
||||
|
||||
logo_adjust_factor = demo_xsize / logo_xsize |
||||
|
||||
x_pos = -corner_x - ( ( logo_xsize * logo_adjust_factor * logo_scale_persistent ) / 2 ) - demo_xsize / 50 |
||||
y_pos = -corner_y - ( ( logo_xsize * logo_adjust_factor * logo_scale_persistent ) / 2 ) - demo_xsize / 50 + ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = logo_adjust_factor * logo_scale_persistent |
||||
y_scale = logo_adjust_factor * logo_scale_persistent |
||||
|
||||
pixi( logo, x_pos , y_pos, WHITE, x_scale, y_scale, ( ( logo_ysize - logo_xsize ) / 2 ), 0, logo_xsize, logo_xsize ) |
||||
|
||||
} |
||||
|
||||
transp( 255 ) |
||||
|
||||
} |
||||
|
||||
fn cover_render( $t1 ) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
rel_time = 1 - clip( max( $t1 - ( all_enter + 1000 ) , 0 ) / 1000 ) |
||||
|
||||
enter_func = ( pow( 50, rel_time ) - 1 ) / ( 50 - 1 ) |
||||
|
||||
enter_func_adjusted = ( 1 - enter_func ) * ( demo_ysize / 2 ) |
||||
|
||||
if (cover_xsize > cover_ysize) { |
||||
|
||||
cover_adjust_factor = demo_xsize / cover_ysize |
||||
|
||||
x_pos = -corner_x - ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) - demo_xsize / 50 |
||||
y_pos = corner_y + ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) + demo_xsize / 50 - ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = cover_adjust_factor * cover_scale |
||||
y_scale = cover_adjust_factor * cover_scale |
||||
|
||||
pixi( cover_src, x_pos , y_pos, WHITE, x_scale, y_scale, ( ( cover_xsize - cover_ysize ) / 2 ), 0, cover_ysize, cover_ysize ) |
||||
|
||||
} else { |
||||
|
||||
cover_adjust_factor = demo_xsize / cover_xsize |
||||
|
||||
x_pos = -corner_x - ( ( cover_xsize * cover_adjust_factor * cover_scale ) / 2 ) - demo_xsize / 50 |
||||
y_pos = corner_y + ( ( cover_xsize * cover_adjust_factor * cover_scale ) / 2 ) + demo_xsize / 50 - ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = cover_adjust_factor * cover_scale |
||||
y_scale = cover_adjust_factor * cover_scale |
||||
|
||||
pixi( cover_src, x_pos , y_pos, WHITE, x_scale, y_scale, ( ( cover_ysize - cover_xsize ) / 2 ), 0, cover_xsize, cover_xsize ) |
||||
|
||||
} |
||||
|
||||
transp( 255 ) |
||||
|
||||
} |
||||
|
||||
fn black( $t1 ) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
exit_point = demo_length - all_exit |
||||
rel_time = max($t1, exit_point) - exit_point |
||||
speed = 255 / (all_exit) |
||||
trans = min(255 - (rel_time * speed), 255) |
||||
transp(255 - trans) |
||||
|
||||
fbox(corner_x, corner_y, demo_xsize, demo_ysize, BLACK) |
||||
|
||||
transp( 255 ) |
||||
|
||||
} |
||||
|
||||
fn text_render($t1) { |
||||
|
||||
transp( 255 ) |
||||
|
||||
rel_time = 1 - clip( max( $t1 - ( all_enter + 1000 ) , 0 ) / 1000 ) |
||||
|
||||
enter_func = ( pow( 50, rel_time ) - 1 ) / ( 50 - 1 ) |
||||
|
||||
enter_func_adjusted = ( 1 - enter_func ) * ( demo_ysize / 2 ) |
||||
|
||||
if (cover_xsize > cover_ysize) { |
||||
|
||||
cover_adjust_factor = demo_xsize / cover_ysize |
||||
|
||||
x_pos = -corner_x - ( ( cover_ysize * cover_adjust_factor * cover_scale ) ) - demo_xsize / 25 |
||||
y_pos = corner_y + ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) + demo_xsize / 50 - ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = cover_adjust_factor * cover_scale |
||||
y_scale = cover_adjust_factor * cover_scale |
||||
|
||||
print( text_title, x_pos , y_pos - ( ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) * text_scale ) , text_color , TOP | RIGHT ) |
||||
print( text_artist, x_pos , y_pos , text_color , TOP | RIGHT ) |
||||
print( text_release, x_pos , y_pos + ( ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) * text_scale ) , text_color , TOP | RIGHT ) |
||||
|
||||
} else { |
||||
|
||||
cover_adjust_factor = demo_xsize / cover_xsize |
||||
|
||||
x_pos = -corner_x - ( ( cover_xsize * cover_adjust_factor * cover_scale ) ) - demo_xsize / 25 |
||||
y_pos = corner_y + ( ( cover_xsize * cover_adjust_factor * cover_scale ) / 2 ) + demo_xsize / 50 - ( ( demo_ysize / 2 ) - enter_func_adjusted ) |
||||
x_scale = cover_adjust_factor * cover_scale |
||||
y_scale = cover_adjust_factor * cover_scale |
||||
|
||||
print( text_title, x_pos , y_pos - ( ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) * text_scale ) , text_color , TOP | RIGHT ) |
||||
print( text_artist, x_pos , y_pos , text_color , TOP | RIGHT ) |
||||
print( text_release, x_pos , y_pos + ( ( ( cover_ysize * cover_adjust_factor * cover_scale ) / 2 ) * text_scale ) , text_color , TOP | RIGHT ) |
||||
|
||||
} |
||||
|
||||
transp( 255 ) |
||||
|
||||
|
||||
} |
||||
|
||||
fn screen_blur( $t1 ) { |
||||
|
||||
if (demo_opengl) { |
||||
|
||||
$prev_screen = get_screen() |
||||
if temp_img <= 0 { temp_img = new( demo_xsize, demo_ysize, PIXEL ) } else { resize( temp_img, demo_xsize, demo_ysize ) } |
||||
copy( temp_img, $prev_screen ) |
||||
set_screen( temp_img ) |
||||
|
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
|
||||
set_screen( $prev_screen ) |
||||
update_gl_data( temp_img ) |
||||
pixi( temp_img ) |
||||
|
||||
} else { |
||||
|
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_VBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
effector( EFF_HBLUR, ( 1 - ( clip( ( $t1 - all_enter ) / 1000 ) ) ) * 20 , WHITE, corner_x, corner_y, demo_xsize, demo_ysize ) |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
fn beginning_flash_render( $t1 ) { |
||||
|
||||
transp_time = max( 0 , $t1 - ( 1000 * beginning_flash_speed ) ) |
||||
transp_value = 255 - ( 255 * ( transp_time / ( 1000 * beginning_flash_fade ) ) ) |
||||
transp_value_curved = pow( transp_value / 255 , beginning_flash_curve ) * 255 |
||||
transp( transp_value_curved ) |
||||
|
||||
c = 255 * ( $t1 / ( 1000 * beginning_flash_speed ) ) |
||||
fbox(corner_x, corner_y, demo_xsize, demo_ysize, get_color( c , c , c )) |
||||
|
||||
transp( 255 ) |
||||
} |
||||
|
||||
|
||||
fn custom_init() |
||||
{ |
||||
gauss( background_src, background, background_blur_rad ) |
||||
|
||||
demo_length = (demo_sound_len / demo_sound_rate) * 1000 |
||||
} |
||||
|
||||
fn custom_deinit() |
||||
{ |
||||
|
||||
remove( goertzel_values ) |
||||
|
||||
} |
||||
|
||||
fn max($a, $b) { |
||||
if ($a >= $b) { |
||||
ret($a) |
||||
} else { |
||||
ret($b) |
||||
} |
||||
} |
||||
|
||||
fn min($a, $b) { |
||||
if ($a < $b) { |
||||
ret($a) |
||||
} else { |
||||
ret($b) |
||||
} |
||||
} |
||||
|
||||
fn clip( $a ) { |
||||
if ($a < 0) { ret( 0 ) } |
||||
if ($a >= 0) { ret( $a ) } |
||||
if ($a >= 1) { ret( 1 ) } |
||||
} |
||||
|
||||
fn gauss( $src, $dest, $rad ) { |
||||
|
||||
sigma = max(($rad / 2), 1) |
||||
|
||||
kernel_width = (2 * $rad) + 1 |
||||
|
||||
kernel = new(kernel_width, kernel_width, FLOAT) |
||||
|
||||
sum = 0 |
||||
|
||||
for (x = -$rad ; x <= $rad ; x + 1) { |
||||
for (y = -$rad ; y <= $rad ; y + 1) { |
||||
exp_num = -(x * x + y * y) |
||||
exp_dem = 2 * sigma * sigma |
||||
expression = pow(M_E, exp_num / exp_dem) |
||||
ker_val = (expression / (2 * M_PI * sigma * sigma)) |
||||
|
||||
kernel[(x + $rad), (y + $rad)] = ker_val |
||||
sum = sum + ker_val |
||||
} |
||||
} |
||||
|
||||
FIXED_POINT_MUL = 32768 |
||||
for (x = 0 ; x < kernel_width ; x + 1) { |
||||
for (y = 0 ; y < kernel_width ; y + 1) { |
||||
kernel[x, y] = kernel[x, y] / sum * FIXED_POINT_MUL |
||||
} |
||||
} |
||||
|
||||
convert_type( kernel, INT ) |
||||
conv_filter( $dest, $src, kernel, FIXED_POINT_MUL, 0, CONV_FILTER_COLOR ) |
||||
} |
||||
|
||||
fn smooth_staircase( $x, $h, $a, $w, $o ) { |
||||
|
||||
part_1 = ( $a * ( $x - $o ) ) / ( $w ) |
||||
part_2 = ( $a * floor( ( $x - $o ) / $w ) ) |
||||
part_3 = ( $a / 2 ) |
||||
part_4 = tanh( part_1 - part_2 - part_3 ) |
||||
part_5 = ( 2 * tanh( $a / 2 ) ) |
||||
part_6 = ( part_4 / part_5 ) |
||||
whole = ( $h * ( part_6 + ( 1 / 2 ) + floor( ( $x - $o ) / $w ) ) ) |
||||
|
||||
ret( whole ) |
||||
} |
||||
|
||||
show_memory_debug_messages( 1 ) |
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
// |
||||
// ffmpeg/avconv-based video export functions |
||||
// (experimental) |
||||
// |
||||
|
||||
fn ffmpeg_video_export_thread( $thread_id, $ff ) |
||||
{ |
||||
if $ff < 0 { ret( 0 ) } |
||||
$ts = "" |
||||
$audio = "" |
||||
$audio2 = "" |
||||
if $ff.audio_file_name > 0 |
||||
{ |
||||
sprintf( $audio, "-i \"%s\"", $ff.audio_file_name ) |
||||
$audio2 = "-acodec pcm_s16le" |
||||
} |
||||
$vcodec = "" |
||||
if $ff.kbits == 0 |
||||
{ |
||||
sprintf( $vcodec, "-vcodec libx264 -b:v 2000k -preset fast" ) |
||||
} |
||||
else |
||||
{ |
||||
sprintf( $vcodec, "-vcodec libx264 -b:v %uk -preset slow", $ff.kbits ) |
||||
} |
||||
sprintf( |
||||
$ts, |
||||
"%s %s -y -pix_fmt bgr32 -s %dx%d -f rawvideo -r %d -i \"%s\" %s %s \"%s\"", |
||||
g_avconv, |
||||
$audio, |
||||
$ff.xsize, |
||||
$ff.ysize, |
||||
$ff.fps, |
||||
$ff.pipe_name, |
||||
$vcodec, |
||||
$audio2, |
||||
$ff.name ) |
||||
printf( "FFmpeg (output) command: %s\n", $ts ) |
||||
system( $ts ) |
||||
} |
||||
|
||||
fn ffmpeg_video_export_open( $filename, $xsize, $ysize, $fps, $kbits, $max_frames, $audio_file_name ) |
||||
{ |
||||
g_avconv = -1 |
||||
while 1 |
||||
{ |
||||
if system( "ffmpeg -version" ) == 0 { g_avconv = "ffmpeg" break } |
||||
if system( "avconv -version" ) == 0 { g_avconv = "avconv" break } |
||||
break |
||||
} |
||||
if g_avconv == -1 |
||||
{ |
||||
logf( "No AV converters detected. Please install ffmpeg or avconv!\n" ) |
||||
logf( "Please also note that this library is designed for *nix systems (Linux, macOS, BSD, etc.) only.\n" ) |
||||
ret( -1 ) |
||||
} |
||||
|
||||
$ff = new( 1, 1, INT ) |
||||
$ff.xsize = $xsize |
||||
$ff.ysize = $ysize |
||||
$ff.fps = $fps |
||||
$ff.kbits = $kbits |
||||
$ff.name = $filename |
||||
$ff.pipe_name = new( 1, 1, INT8 ) |
||||
sprintf( $ff.pipe_name, "/tmp/avconv_vpipe_%d", $ff ) |
||||
$ff.frame = 0 |
||||
$ff.max_frames = $max_frames |
||||
if $0 >= 7 |
||||
{ |
||||
$ff.audio_file_name = $audio_file_name |
||||
} |
||||
|
||||
$ts = "" |
||||
sprintf( $ts, "mkfifo %s", $ff.pipe_name ) |
||||
system( $ts ) |
||||
$ff.th = thread_create( ffmpeg_video_export_thread, $ff ) |
||||
|
||||
ret( $ff ) |
||||
} |
||||
|
||||
fn ffmpeg_video_export_close( $ff ) |
||||
{ |
||||
if $ff < 0 { ret( 0 ) } |
||||
if $ff.pipe_f |
||||
{ |
||||
fclose( $ff.pipe_f ) |
||||
} |
||||
thread_destroy( $ff.th, INT_MAX ) |
||||
remove_file( $ff.pipe_name ) |
||||
remove( $ff.pipe_name ) |
||||
remove( $ff ) |
||||
} |
||||
|
||||
fn ffmpeg_video_export_write( $ff, $buf ) |
||||
{ |
||||
if $ff < 0 { ret( 0 ) } |
||||
if $ff.pipe_f == 0 { $ff.pipe_f = fopen( $ff.pipe_name, "wb" ) } |
||||
if $ff.pipe_f |
||||
{ |
||||
fwrite( $buf, get_size( $buf ) * get_esize( $buf ), $ff.pipe_f ) |
||||
$ff.frame + 1 |
||||
if $ff.max_frames && $ff.frame >= $ff.max_frames |
||||
{ |
||||
fputs( "FFmpeg export stop\n" ) |
||||
ret( 1 ) |
||||
} |
||||
} |
||||
ret( 0 ) |
||||
} |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
@ -0,0 +1,391 @@
@@ -0,0 +1,391 @@
|
||||
// |
||||
// AVI MJPEG encoder |
||||
// |
||||
|
||||
include "riff.pixi" |
||||
|
||||
AVIH_FLAG_HASINDEX = 0x00000010 //Index at end of file; NOT RECOGNIZED BY MPLAYER & VLC :( |
||||
AVIH_FLAG_MUSTUSEINDEX = 0x00000020 |
||||
AVIH_FLAG_ISINTERLEAVED = 0x00000100 |
||||
AVIH_FLAG_TRUSTCKTYPE = 0x00000800 //Use CKType to find key frames |
||||
AVIH_FLAG_WASCAPTUREFILE = 0x00010000 |
||||
AVIH_FLAG_COPYRIGHTED = 0x00020000 |
||||
|
||||
MJPEG_ENCODER_FLAG_HASSOUND = ( 1 << 0 ) |
||||
MJPEG_ENCODER_FLAG_USEINDEX = ( 1 << 1 ) |
||||
|
||||
fn mjpeg_fn_error( $fn_name, $pars ) |
||||
{ |
||||
logf( "%s() MJPEG error: wrong number of parameters (%d)\n", $fn_name, $pars ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_open( |
||||
$fps, |
||||
$width, |
||||
$height, |
||||
$quality, |
||||
$audio_channels, |
||||
$audio_frames_per_second, |
||||
$audio_sample_type, |
||||
$flags, |
||||
$output_stream ) |
||||
{ |
||||
if $0 != 9 { mjpeg_fn_error( "mjpeg_encoder_open", $0 ) ret( -1 ) } |
||||
|
||||
$mj = new( 1, 1, INT ) |
||||
$mj.fps = $fps |
||||
$mj.frames = 0 |
||||
$mj.width = $width |
||||
$mj.height = $height |
||||
$mj.quality = $quality |
||||
$mj.audio_ch = $audio_channels |
||||
$mj.audio_freq = $audio_frames_per_second |
||||
$mj.audio_type = $audio_sample_type |
||||
$mj.flags = $flags |
||||
$mj.out = $output_stream |
||||
$mj.idx = new( 4, 1, INT32 ) |
||||
$mj.idx_ptr = 0 |
||||
$mj.jpeg = -1 |
||||
$mj.silent_chunk = -1 |
||||
|
||||
$mj.audio_bits = 0 |
||||
if $audio_sample_type == INT8 { $mj.audio_bits = 8 } |
||||
if $audio_sample_type == INT16 { $mj.audio_bits = 16 } |
||||
if $audio_sample_type == FLOAT32 { $mj.audio_bits = 32 } |
||||
if $mj.audio_bits == 0 |
||||
{ |
||||
logf( "MJPEG encoder error: wrong audio sample type. Possible values: INT8, INT16, FLOAT32\n" ) |
||||
ret( -1 ) |
||||
} |
||||
|
||||
//AVI: |
||||
|
||||
$mj.c_avi = riff_chunk_open( -1, "RIFF", $mj.out ) |
||||
riff_chunk_write_data( $mj.c_avi, "AVI ", 0, 0 ) |
||||
|
||||
//Header: |
||||
|
||||
$c_hdrl = riff_chunk_open( $mj.c_avi, "LIST", $mj.out ) |
||||
riff_chunk_write_data( $c_hdrl, "hdrl", 0, 0 ) |
||||
|
||||
$c = riff_chunk_open( $c_hdrl, "avih", $mj.out ) |
||||
$avih = new( 14, 1, INT32 ) |
||||
clean( $avih ) |
||||
$avih[ 0 ] = 1000000 div $mj.fps //microSecPerFrame |
||||
$avih[ 1 ] = 10000000 //maxBytesPerSec |
||||
$avih[ 3 ] = AVIH_FLAG_ISINTERLEAVED | AVIH_FLAG_TRUSTCKTYPE | AVIH_FLAG_WASCAPTUREFILE //flags |
||||
if $flags & MJPEG_ENCODER_FLAG_USEINDEX |
||||
{ |
||||
$avih[ 3 ] | AVIH_FLAG_HASINDEX |
||||
} |
||||
$avih[ 4 ] = 0 //totalFrames |
||||
$mj.fix1_offset = ftell( $mj.out ) + 4 * 4 |
||||
if $flags & MJPEG_ENCODER_FLAG_HASSOUND { $avih[ 6 ] = 2 } else { $avih[ 6 ] = 1 } |
||||
$avih[ 7 ] = 1024 * 1024 //suggestedBufferSize |
||||
$avih[ 8 ] = $mj.width |
||||
$avih[ 9 ] = $mj.height |
||||
riff_chunk_write_data( $c, $avih, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
remove( $avih ) |
||||
|
||||
//Video stream info: |
||||
|
||||
$c_strl = riff_chunk_open( $c_hdrl, "LIST", $mj.out ) |
||||
riff_chunk_write_data( $c_strl, "strl", 0, 0 ) |
||||
|
||||
$c = riff_chunk_open( $c_strl, "strh", $mj.out ) |
||||
$strh = new( 14, 1, INT32 ) |
||||
clean( $strh ) |
||||
$strh[ 0 ] = 'vids' //type |
||||
$strh[ 1 ] = 'MJPG' //handler |
||||
$strh[ 5 ] = 1 //scale |
||||
$strh[ 6 ] = $fps //rate |
||||
$strh[ 8 ] = 0 //length |
||||
$mj.fix2_offset = ftell( $mj.out ) + 8 * 4 |
||||
$strh[ 9 ] = 1024 * 1024 //suggestedBufferSize |
||||
$strh[ 10 ] = -1 //quality |
||||
$strh[ 13 ] = $width | ( $height << 16 ) |
||||
riff_chunk_write_data( $c, $strh, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
remove( $strh ) |
||||
|
||||
$c = riff_chunk_open( $c_strl, "strf", $mj.out ) |
||||
$bmph = new( 10, 1, INT32 ) |
||||
clean( $bmph ) |
||||
$bmph[ 0 ] = get_size( $bmph ) * get_esize( $bmph ) //size |
||||
$bmph[ 1 ] = $width |
||||
$bmph[ 2 ] = $height |
||||
$bmph[ 3 ] = 1 | ( 24 << 16 ) //planes and bitCount |
||||
$bmph[ 4 ] = 'MJPG' //compression |
||||
$bmph[ 5 ] = $width * $height * 3 //imgSize |
||||
riff_chunk_write_data( $c, $bmph, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
remove( $bmph ) |
||||
|
||||
riff_chunk_close( $c_strl ) |
||||
|
||||
if $flags & MJPEG_ENCODER_FLAG_HASSOUND |
||||
{ |
||||
//Audio stream info (uncompressed interleaved): |
||||
|
||||
$c_strl = riff_chunk_open( $c_hdrl, "LIST", $mj.out ) |
||||
riff_chunk_write_data( $c_strl, "strl", 0, 0 ) |
||||
|
||||
$c = riff_chunk_open( $c_strl, "strh", $mj.out ) |
||||
$strh = new( 14, 1, INT32 ) |
||||
clean( $strh ) |
||||
$strh[ 0 ] = 'auds' //type |
||||
$strh[ 1 ] = 0 //handler |
||||
$strh[ 5 ] = 1 //scale |
||||
$strh[ 6 ] = $audio_frames_per_second //rate |
||||
$strh[ 8 ] = 0 //length |
||||
$mj.fix3_offset = ftell( $mj.out ) + 8 * 4 |
||||
$strh[ 9 ] = 0 //suggestedBufferSize |
||||
$strh[ 10 ] = -1 //quality |
||||
$strh[ 11 ] = $audio_channels * ( $mj.audio_bits / 8 ) //sampleSize |
||||
riff_chunk_write_data( $c, $strh, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
remove( $strh ) |
||||
|
||||
$c = riff_chunk_open( $c_strl, "strf", $mj.out ) |
||||
$fmt = new( 4, 1, INT32 ) |
||||
clean( $fmt ) |
||||
$audio_format = 1; if $mj.audio_bits == 32 { $audio_format = 3 } |
||||
$fmt[ 0 ] = $audio_format | ( $audio_channels << 16 ) |
||||
$fmt[ 1 ] = $audio_frames_per_second |
||||
$fmt[ 2 ] = $audio_frames_per_second * $audio_channels * ( $mj.audio_bits / 8 ) //bytes per second |
||||
$fmt[ 3 ] = $audio_channels * ( $mj.audio_bits / 8 ) | ( $mj.audio_bits << 16 ) //block align + bits |
||||
riff_chunk_write_data( $c, $fmt, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
remove( $fmt ) |
||||
|
||||
riff_chunk_close( $c_strl ) |
||||
} |
||||
|
||||
riff_chunk_close( $c_hdrl ) |
||||
|
||||
//Video and Audio data: |
||||
|
||||
$mj.c_movi = riff_chunk_open( $mj.c_avi, "LIST", $mj.out ) |
||||
riff_chunk_write_data( $mj.c_movi, "movi", 0, 0 ) |
||||
|
||||
ret( $mj ) |
||||
} |
||||
|
||||
/*fn mjpeg_encoder_jfif_to_avi1( $jpeg ) |
||||
{ |
||||
if $0 != 1 { mjpeg_fn_error( "mjpeg_encoder_jfif_to_avi1", $0 ) ret( 0 ) } |
||||
|
||||
$p = -1 |
||||
$i = 0 while $i < 256 |
||||
{ |
||||
if $jpeg[ $i ] == 'J' |
||||
{ |
||||
if $jpeg[ $i + 1 ] == 'F' |
||||
{ |
||||
if $jpeg[ $i + 2 ] == 'I' |
||||
{ |
||||
if $jpeg[ $i + 3 ] == 'F' |
||||
{ |
||||
$p = $i |
||||
break |
||||
} |
||||
} |
||||
} |
||||
} |
||||
$i + 1 |
||||
} |
||||
if $p >= 0 |
||||
{ |
||||
$size = get_size( $jpeg ) |
||||
$jpeg[ $p ] = 'A' $p + 1 |
||||
$jpeg[ $p ] = 'V' $p + 1 |
||||
$jpeg[ $p ] = 'I' $p + 1 |
||||
$jpeg[ $p ] = '1' $p + 1 |
||||
$jpeg[ $p ] = 0 $p + 1 |
||||
$jpeg[ $p ] = 0 $p + 1 |
||||
$jpeg[ $p ] = $size & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 8 ) & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 16 ) & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 24 ) & 255 $p + 1 |
||||
$jpeg[ $p ] = $size & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 8 ) & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 16 ) & 255 $p + 1 |
||||
$jpeg[ $p ] = ( $size >> 24 ) & 255 $p + 1 |
||||
} |
||||
|
||||
ret( 0 ) |
||||
}*/ |
||||
|
||||
fn mjpeg_encoder_write_jpeg( $mj, $jpeg, $offset_bytes, $size_bytes ) |
||||
{ |
||||
if $0 != 4 { mjpeg_fn_error( "mjpeg_encoder_write_jpeg", $0 ) ret( 0 ) } |
||||
if $mj <= 0 { ret( 0 ) } |
||||
|
||||
if $mj.flags & MJPEG_ENCODER_FLAG_USEINDEX |
||||
{ |
||||
mjpeg_encoder_add_index( $mj, '00dc', 0x10, ftell( $mj.out ) - ( $mj.c_movi.size_ptr + 4 ), $size_bytes ) |
||||
} |
||||
|
||||
$c = riff_chunk_open( $mj.c_movi, "00dc", $mj.out ) |
||||
riff_chunk_write_data( $c, $jpeg, $offset_bytes, $size_bytes ) |
||||
riff_chunk_close( $c ) |
||||
|
||||
ret( $size_bytes ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_write_image( $mj, $img ) |
||||
{ |
||||
if $0 != 2 { mjpeg_fn_error( "mjpeg_encoder_write_image", $0 ) ret( 0 ) } |
||||
if $mj <= 0 { ret( 0 ) } |
||||
|
||||
if $mj.jpeg <= 0 |
||||
{ |
||||
$mj.jpeg = new( 1, 1, INT8 ) |
||||
} |
||||
$jpeg = $mj.jpeg |
||||
if $img != -999 |
||||
{ |
||||
$f = fopen_mem( $jpeg ) |
||||
fsave( $img, $f, FORMAT_JPEG, $mj.quality ) |
||||
fclose( $f ) |
||||
} |
||||
|
||||
if $mj.flags & MJPEG_ENCODER_FLAG_USEINDEX |
||||
{ |
||||
mjpeg_encoder_add_index( $mj, '00dc', 0x10, ftell( $mj.out ) - ( $mj.c_movi.size_ptr + 4 ), get_size( $jpeg ) ) |
||||
} |
||||
|
||||
$c = riff_chunk_open( $mj.c_movi, "00dc", $mj.out ) |
||||
riff_chunk_write_data( $c, $jpeg, 0, 0 ) |
||||
riff_chunk_close( $c ) |
||||
|
||||
ret( get_size( $jpeg ) ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_get_audio_size( $mj ) //Number of audio frames per chunk |
||||
{ |
||||
if $0 != 1 { mjpeg_fn_error( "mjpeg_encoder_get_audio_size", $0 ) ret( 0 ) } |
||||
if $mj <= 0 { ret( 0 ) } |
||||
|
||||
$len1 = ( ( $mj.frames - 1 ) * $mj.audio_freq ) div $mj.fps |
||||
$len2 = ( $mj.frames * $mj.audio_freq ) div $mj.fps |
||||
$len = $len2 - $len1 |
||||
|
||||
ret( $len ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_write_audio( $mj, $audio, $offset_bytes, $size_bytes ) |
||||
{ |
||||
if $0 != 4 { mjpeg_fn_error( "mjpeg_encoder_write_audio", $0 ) ret( 0 ) } |
||||
if $mj <= 0 { ret( 0 ) } |
||||
|
||||
$bytes = mjpeg_encoder_get_audio_size( $mj ) * $mj.audio_ch * ( $mj.audio_bits div 8 ) |
||||
|
||||
if $mj.c_01wb <= 0 |
||||
{ |
||||
if $mj.flags & MJPEG_ENCODER_FLAG_USEINDEX |
||||
{ |
||||
mjpeg_encoder_add_index( $mj, '01wb', 0, ftell( $mj.out ) - ( $mj.c_movi.size_ptr + 4 ), $bytes ) |
||||
} |
||||
$mj.c_01wb = riff_chunk_open( $mj.c_movi, "01wb", $mj.out ) |
||||
} |
||||
|
||||
if $audio <= 0 |
||||
{ |
||||
//Silent chunk: |
||||
if $mj.silent_chunk <= 0 |
||||
{ |
||||
$mj.silent_chunk = new( $bytes, 1, INT8 ) |
||||
clean( $mj.silent_chunk ) |
||||
} |
||||
$audio = $mj.silent_chunk |
||||
} |
||||
|
||||
riff_chunk_write_data( $mj.c_01wb, $audio, $offset_bytes, $size_bytes ) |
||||
|
||||
ret( $size_bytes ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_next_frame( $mj ) |
||||
{ |
||||
if $0 != 1 { mjpeg_fn_error( "mjpeg_encoder_next_frame", $0 ) ret( -1 ) } |
||||
if $mj <= 0 { ret( -1 ) } |
||||
|
||||
if $mj.c_01wb > 0 |
||||
{ |
||||
//Close audio chunk: |
||||
riff_chunk_close( $mj.c_01wb ) |
||||
$mj.c_01wb = -1 |
||||
} |
||||
|
||||
$mj.frames + 1 |
||||
|
||||
ret( 0 ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_add_index( $mj, $id, $flags, $offset, $size ) |
||||
{ |
||||
if $0 != 5 { mjpeg_fn_error( "mjpeg_encoder_add_index", $0 ) ret( -1 ) } |
||||
if $mj <= 0 { ret( -1 ) } |
||||
|
||||
$idx = $mj.idx |
||||
$idx_ptr = $mj.idx_ptr |
||||
$idx[ $idx_ptr * 4 + 0 ] = $id |
||||
$idx[ $idx_ptr * 4 + 1 ] = $flags |
||||
$idx[ $idx_ptr * 4 + 2 ] = $offset |
||||
$idx[ $idx_ptr * 4 + 3 ] = $size |
||||
$idx_ptr + 1 |
||||
if $idx_ptr >= get_size( $idx ) / 4 |
||||
{ |
||||
resize( $idx, ( $idx_ptr + 256 ) * 4, 1, INT32 ) |
||||
} |
||||
$mj.idx_ptr = $idx_ptr |
||||
|
||||
ret( 0 ) |
||||
} |
||||
|
||||
fn mjpeg_encoder_close( $mj ) |
||||
{ |
||||
if $0 != 1 { mjpeg_fn_error( "mjpeg_encoder_close", $0 ) ret( -1 ) } |
||||
if $mj <= 0 { ret( -1 ) } |
||||
|
||||
if $mj.frames <= 0 |
||||
{ |
||||
logf( "MJPEG encoder error: no frames\n" ) |
||||
} |
||||
|
||||
riff_chunk_close( $mj.c_movi ) |
||||
|
||||
//Index: |
||||
|
||||
if $mj.flags & MJPEG_ENCODER_FLAG_USEINDEX |
||||
{ |
||||
$idx = $mj.idx |
||||
$idx_ptr = $mj.idx_ptr |
||||
$c = riff_chunk_open( $mj.c_avi, "idx1", $mj.out ) |
||||
riff_chunk_write_data( $c, $idx, 0, $idx_ptr * 4 * 4 ) |
||||
riff_chunk_close( $c ) |
||||
} |
||||
|
||||
//Fixup: |
||||
|
||||
fseek( $mj.out, $mj.fix1_offset, SEEK_SET ) |
||||
riff_write_int32( $mj.frames, $mj.out ) //totalFrames |
||||
fseek( $mj.out, $mj.fix2_offset, SEEK_SET ) |
||||
riff_write_int32( $mj.frames, $mj.out ) //video stream length |
||||
if $mj.flags & MJPEG_ENCODER_FLAG_HASSOUND |
||||
{ |
||||
fseek( $mj.out, $mj.fix3_offset, SEEK_SET ) |
||||
riff_write_int32( ( $mj.frames * $mj.audio_freq ) div $mj.fps, $mj.out ) //audio stream length (number of frames) |
||||
} |
||||
|
||||
riff_chunk_close( $mj.c_avi ) |
||||
|
||||
remove( $mj.silent_chunk ) |
||||
remove( $mj.jpeg ) |
||||
remove( $mj.idx ) |
||||
remove( $mj ) |
||||
|
||||
ret( 0 ) |
||||
} |
@ -0,0 +1,111 @@
@@ -0,0 +1,111 @@
|
||||
/* |
||||
|
||||
Functions for working with Resource Interchange File Format (RIFF) |
||||
|
||||
How to write: |
||||
c = riff_chunk_open( -1, "NAME", stream ) |
||||
riff_chunk_write_data( c, data_container, 0, 0 ) |
||||
riff_chunk_close( c ) |
||||
|
||||
How to read: not implemented yet. |
||||
|
||||
*/ |
||||
|
||||
fn riff_write_int32( $val, $f ) |
||||
{ |
||||
$w = 0 |
||||
while 1 |
||||
{ |
||||
if fputc( $val & 255, $f ) == -1 { $w = 0 break } |
||||
if fputc( ( $val >> 8 ) & 255, $f ) == -1 { $w = 0 break } |
||||
if fputc( ( $val >> 16 ) & 255, $f ) == -1 { $w = 0 break } |
||||
if fputc( ( $val >> 24 ) & 255, $f ) == -1 { $w = 0 break } |
||||
$w = 4 |
||||
break |
||||
} |
||||
ret( $w ) |
||||
} |
||||
|
||||
fn riff_chunk_open( $parent, $id, $f ) |
||||
{ |
||||
$err = 0 |
||||
$c = new( 1, 1, INT ) |
||||
$c.parent = $parent |
||||
if $parent > 0 |
||||
{ |
||||
$parent.size + 8 |
||||
$parent2 = $parent.parent |
||||
while 1 |
||||
{ |
||||
if $parent2 == -1 { break } |
||||
$parent2.size + 8 |
||||
$parent2 = $parent2.parent |
||||
} |
||||
} |
||||
$c.id = $id |
||||
$c.size = 0 |
||||
$c.size_ptr = 0 |
||||
$c.f = $f |
||||
while 1 |
||||
{ |
||||
if fwrite( $id, 4, $f ) != 4 { $err = 1 break } //Save chunk ID |
||||
$c.size_ptr = ftell( $f ) |
||||
if riff_write_int32( 0, $f ) != 4 { $err = 1 break } //Save chunk size (zero by default) |
||||
break |
||||
} |
||||
if $err |
||||
{ |
||||
remove( $c ) |
||||
$c = -1 |
||||
} |
||||
ret( $c ) |
||||
} |
||||
|
||||
fn riff_chunk_close( $c ) |
||||
{ |
||||
if $c <= 0 { logf( "Close: no chunk\n" ) ret } |
||||
if $c.size |
||||
{ |
||||
$f = $c.f |
||||
$prev_pos = ftell( $f ) |
||||
fseek( $f, $c.size_ptr, SEEK_SET ) |
||||
riff_write_int32( $c.size, $f ) |
||||
fseek( $f, $prev_pos, SEEK_SET ) |
||||
if $c.size & 1 |
||||
{ |
||||
fputc( 0, $f ); |
||||
$parent = $c.parent |
||||
while 1 |
||||
{ |
||||
if $parent == -1 { break } |
||||
$parent.size + 1 |
||||
$parent = $parent.parent |
||||
} |
||||
} |
||||
} |
||||
remove( $c ) |
||||
} |
||||
|
||||
fn riff_chunk_write_data( $c, $data, $offset_bytes, $size_bytes ) |
||||
{ |
||||
$w = 0 |
||||
if $c <= 0 { logf( "Write: no chunk\n" ) ret } |
||||
if $size_bytes <= 0 |
||||
{ |
||||
$size_bytes = get_size( $data ) * get_esize( $data ) |
||||
} |
||||
$f = $c.f |
||||
$w = fwrite( $data, $size_bytes, $f, $offset_bytes ) |
||||
if $w == $size_bytes |
||||
{ |
||||
$c.size + $size_bytes |
||||
$parent = $c.parent |
||||
while 1 |
||||
{ |
||||
if $parent == -1 { break } |
||||
$parent.size + $size_bytes |
||||
$parent = $parent.parent |
||||
} |
||||
} |
||||
ret( $w ) |
||||
} |
Loading…
Reference in new issue